fix: traversal!

This commit is contained in:
cha0s 2020-06-22 04:53:32 -05:00
parent 7714c87058
commit 89dc685d62
4 changed files with 80 additions and 55 deletions

View File

@ -16,7 +16,7 @@ const App = () => {
const [typeRenderers] = useState(typeRenderMap());
return (
<TypeRenderersContext.Provider value={typeRenderers}>
<Resource uri="/resources/cha0s/initial/kitty.entity.json" />
<Resource uri="/resources/cha0s/initial/mama-kitty.entity.json" />
</TypeRenderersContext.Provider>
);
};

View File

@ -5,8 +5,7 @@ import React from 'react';
import useTypeRenderers from '~/client/hooks/useTypeRenderers';
import propTypes from './prop-types';
import {contextStepsList} from './steps-lists';
import {typeFromLiteral} from './typing';
import {stepOptions, typeFromLiteral} from './typing';
const decorate = compose(
contempo(require('./literal.raw.scss')),
@ -20,21 +19,15 @@ const Literal = ({
const typeRenderers = useTypeRenderers();
const type = typeFromLiteral(value.value);
const Component = typeRenderers[type];
const stepsList = contextStepsList(context, type);
const tierOptions = Object.keys(stepsList.reduce((r, optionSteps) => {
if (!optionSteps[0] || !optionSteps[0].key) {
return r;
}
return {...r, [optionSteps[0].key]: true};
}, {}));
tierOptions.push('<literal>');
const options = stepOptions(context, [], 0, type);
options.push('<literal>');
return (
<div className="literal">
<select readOnly value="<literal>">
{
tierOptions
options
.sort((l, r) => (l.toLowerCase() < r.toLowerCase() ? -1 : 1))
.map((tierOption) => <option key={tierOption}>{tierOption}</option>)
.map((option) => <option key={option}>{option}</option>)
}
</select>
{Component ? <Component dispatchers={dispatchers} value={value.value} /> : null}

View File

@ -5,8 +5,7 @@ import React from 'react';
import Value from '~/client/value';
import propTypes from './prop-types';
import {contextStepsList} from './steps-lists';
import {typeFromSteps} from './typing';
import {stepOptions, typeFromSteps} from './typing';
const decorate = compose(
contempo(require('./traversal.raw.scss')),
@ -15,9 +14,10 @@ const decorate = compose(
const Traversal = (props) => {
const {
context,
dispatchers,
value: {steps, value},
} = props;
const stepsList = contextStepsList(context, typeFromSteps(context, steps));
const stepsType = typeFromSteps(context, steps);
return (
<div className="traversal">
{steps.map((step, i) => (
@ -27,27 +27,14 @@ const Traversal = (props) => {
(() => {
switch (step.type) {
case 'key': {
const tierOptions = Object.keys(stepsList.reduce((r, optionSteps) => {
if (!optionSteps[i] || !optionSteps[i].key) {
return r;
}
for (let j = 0; j < i; ++j) {
if (steps[j].key !== optionSteps[j].key) {
return r;
}
}
return {...r, [optionSteps[i].key]: true};
}, {}));
if (0 === i) {
tierOptions.push('<literal>');
}
const options = stepOptions(context, steps, i, stepsType);
return (
<span className="key">
<select readOnly value={steps[i].key}>
<span className="key" data-step-key={step.key}>
<select readOnly value={step.key}>
{
tierOptions
options
.sort((l, r) => (l.toLowerCase() < r.toLowerCase() ? -1 : 1))
.map((tierOption) => <option key={tierOption}>{tierOption}</option>)
.map((option) => <option key={option}>{option}</option>)
}
</select>
</span>
@ -61,7 +48,11 @@ const Traversal = (props) => {
<div className="arg" key={JSON.stringify(arg)}>
<label>
{arg.label}
<Value.Component context={context} value={arg} />
<Value.Component
context={context}
dispatchers={dispatchers}
value={arg}
/>
</label>
</div>
))}
@ -79,7 +70,11 @@ const Traversal = (props) => {
value && (
<span className="assign">
<span className="op">=</span>
<Value.Component context={context} value={value} />
<Value.Component
context={context}
dispatchers={dispatchers}
value={value}
/>
</span>
)
}
@ -92,6 +87,6 @@ Traversal.propTypes = {
};
export default {
type: '-traversal',
type: 'traversal',
Component: decorate(Traversal),
};

View File

@ -1,5 +1,9 @@
import {Context} from '@avocado/behavior';
let digraph;
// eslint-disable-next-line no-return-assign
const cachedDigraph = () => (digraph || (digraph = Context.allTypesInvertedDigraph()));
export function isBehaviorItem(valueOrItem) {
if ('object' !== typeof valueOrItem) {
return false;
@ -42,27 +46,60 @@ export function typeFromValue(v) {
return isBehaviorItem(v) ? v.type : undefined;
}
export function typeFromSteps(context, steps) {
if (!steps || 0 === steps.length) {
return 'undefined';
const stepTo = ([variable, type], step) => {
const {key} = step;
if (key) {
const description = Context.typeDescription(type, variable);
return [
'object' === typeof variable ? variable[key] : undefined,
description[key] ? description[key].type : type,
];
}
const [, finalType] = steps.slice(1).reduce(
([v, type], step) => {
const {key} = step;
if (key) {
const description = Context.typeDescription(type, v);
return [
'object' === typeof v ? v[key] : undefined,
description[key] ? description[key].type : type,
];
}
return [v, type];
},
context.get(steps[0].key),
);
return finalType;
return [variable, type];
};
export function descriptionFromSteps(context, steps) {
if (!steps || 0 === steps.length) {
return {};
}
const [variable, type] = steps.slice(1).reduce(stepTo, context.get(steps[0].key));
return Context.typeDescription(type, variable);
}
export function typeFits(reference, candidate) {
return 'any' === reference || -1 !== (reference.split('|') || []).indexOf(candidate);
}
export function stepOptions(context, steps, i, type) {
let description;
if (0 === i) {
description = Object.entries(context.all())
.reduce((r, [key, tuple]) => ({...r, [key]: {type: tuple[1]}}), {});
}
else {
description = descriptionFromSteps(context, steps.slice(0, i));
}
let options;
if ('any' !== type) {
const inverted = cachedDigraph();
const candidates = (inverted[type] || []).concat(type);
options = Object.entries(description)
.reduce((r, [key, spec]) => (
candidates.find((candidate) => typeFits(candidate, spec.type))
? r.concat(key)
: r
), []);
}
else {
options = Object.keys(description);
}
return options;
}
export function typeFromSteps(context, steps) {
if (!steps || 0 === steps.length) {
return 'undefined';
}
const [, type] = steps.slice(1).reduce(stepTo, context.get(steps[0].key));
return type;
}