fix: traversal!
This commit is contained in:
parent
7714c87058
commit
89dc685d62
|
@ -16,7 +16,7 @@ const App = () => {
|
||||||
const [typeRenderers] = useState(typeRenderMap());
|
const [typeRenderers] = useState(typeRenderMap());
|
||||||
return (
|
return (
|
||||||
<TypeRenderersContext.Provider value={typeRenderers}>
|
<TypeRenderersContext.Provider value={typeRenderers}>
|
||||||
<Resource uri="/resources/cha0s/initial/kitty.entity.json" />
|
<Resource uri="/resources/cha0s/initial/mama-kitty.entity.json" />
|
||||||
</TypeRenderersContext.Provider>
|
</TypeRenderersContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,8 +5,7 @@ import React from 'react';
|
||||||
import useTypeRenderers from '~/client/hooks/useTypeRenderers';
|
import useTypeRenderers from '~/client/hooks/useTypeRenderers';
|
||||||
|
|
||||||
import propTypes from './prop-types';
|
import propTypes from './prop-types';
|
||||||
import {contextStepsList} from './steps-lists';
|
import {stepOptions, typeFromLiteral} from './typing';
|
||||||
import {typeFromLiteral} from './typing';
|
|
||||||
|
|
||||||
const decorate = compose(
|
const decorate = compose(
|
||||||
contempo(require('./literal.raw.scss')),
|
contempo(require('./literal.raw.scss')),
|
||||||
|
@ -20,21 +19,15 @@ const Literal = ({
|
||||||
const typeRenderers = useTypeRenderers();
|
const typeRenderers = useTypeRenderers();
|
||||||
const type = typeFromLiteral(value.value);
|
const type = typeFromLiteral(value.value);
|
||||||
const Component = typeRenderers[type];
|
const Component = typeRenderers[type];
|
||||||
const stepsList = contextStepsList(context, type);
|
const options = stepOptions(context, [], 0, type);
|
||||||
const tierOptions = Object.keys(stepsList.reduce((r, optionSteps) => {
|
options.push('<literal>');
|
||||||
if (!optionSteps[0] || !optionSteps[0].key) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
return {...r, [optionSteps[0].key]: true};
|
|
||||||
}, {}));
|
|
||||||
tierOptions.push('<literal>');
|
|
||||||
return (
|
return (
|
||||||
<div className="literal">
|
<div className="literal">
|
||||||
<select readOnly value="<literal>">
|
<select readOnly value="<literal>">
|
||||||
{
|
{
|
||||||
tierOptions
|
options
|
||||||
.sort((l, r) => (l.toLowerCase() < r.toLowerCase() ? -1 : 1))
|
.sort((l, r) => (l.toLowerCase() < r.toLowerCase() ? -1 : 1))
|
||||||
.map((tierOption) => <option key={tierOption}>{tierOption}</option>)
|
.map((option) => <option key={option}>{option}</option>)
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
{Component ? <Component dispatchers={dispatchers} value={value.value} /> : null}
|
{Component ? <Component dispatchers={dispatchers} value={value.value} /> : null}
|
||||||
|
|
|
@ -5,8 +5,7 @@ import React from 'react';
|
||||||
import Value from '~/client/value';
|
import Value from '~/client/value';
|
||||||
|
|
||||||
import propTypes from './prop-types';
|
import propTypes from './prop-types';
|
||||||
import {contextStepsList} from './steps-lists';
|
import {stepOptions, typeFromSteps} from './typing';
|
||||||
import {typeFromSteps} from './typing';
|
|
||||||
|
|
||||||
const decorate = compose(
|
const decorate = compose(
|
||||||
contempo(require('./traversal.raw.scss')),
|
contempo(require('./traversal.raw.scss')),
|
||||||
|
@ -15,9 +14,10 @@ const decorate = compose(
|
||||||
const Traversal = (props) => {
|
const Traversal = (props) => {
|
||||||
const {
|
const {
|
||||||
context,
|
context,
|
||||||
|
dispatchers,
|
||||||
value: {steps, value},
|
value: {steps, value},
|
||||||
} = props;
|
} = props;
|
||||||
const stepsList = contextStepsList(context, typeFromSteps(context, steps));
|
const stepsType = typeFromSteps(context, steps);
|
||||||
return (
|
return (
|
||||||
<div className="traversal">
|
<div className="traversal">
|
||||||
{steps.map((step, i) => (
|
{steps.map((step, i) => (
|
||||||
|
@ -27,27 +27,14 @@ const Traversal = (props) => {
|
||||||
(() => {
|
(() => {
|
||||||
switch (step.type) {
|
switch (step.type) {
|
||||||
case 'key': {
|
case 'key': {
|
||||||
const tierOptions = Object.keys(stepsList.reduce((r, optionSteps) => {
|
const options = stepOptions(context, steps, i, stepsType);
|
||||||
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>');
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<span className="key">
|
<span className="key" data-step-key={step.key}>
|
||||||
<select readOnly value={steps[i].key}>
|
<select readOnly value={step.key}>
|
||||||
{
|
{
|
||||||
tierOptions
|
options
|
||||||
.sort((l, r) => (l.toLowerCase() < r.toLowerCase() ? -1 : 1))
|
.sort((l, r) => (l.toLowerCase() < r.toLowerCase() ? -1 : 1))
|
||||||
.map((tierOption) => <option key={tierOption}>{tierOption}</option>)
|
.map((option) => <option key={option}>{option}</option>)
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</span>
|
</span>
|
||||||
|
@ -61,7 +48,11 @@ const Traversal = (props) => {
|
||||||
<div className="arg" key={JSON.stringify(arg)}>
|
<div className="arg" key={JSON.stringify(arg)}>
|
||||||
<label>
|
<label>
|
||||||
{arg.label}
|
{arg.label}
|
||||||
<Value.Component context={context} value={arg} />
|
<Value.Component
|
||||||
|
context={context}
|
||||||
|
dispatchers={dispatchers}
|
||||||
|
value={arg}
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
@ -79,7 +70,11 @@ const Traversal = (props) => {
|
||||||
value && (
|
value && (
|
||||||
<span className="assign">
|
<span className="assign">
|
||||||
<span className="op">=</span>
|
<span className="op">=</span>
|
||||||
<Value.Component context={context} value={value} />
|
<Value.Component
|
||||||
|
context={context}
|
||||||
|
dispatchers={dispatchers}
|
||||||
|
value={value}
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -92,6 +87,6 @@ Traversal.propTypes = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
type: '-traversal',
|
type: 'traversal',
|
||||||
Component: decorate(Traversal),
|
Component: decorate(Traversal),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
import {Context} from '@avocado/behavior';
|
import {Context} from '@avocado/behavior';
|
||||||
|
|
||||||
|
let digraph;
|
||||||
|
// eslint-disable-next-line no-return-assign
|
||||||
|
const cachedDigraph = () => (digraph || (digraph = Context.allTypesInvertedDigraph()));
|
||||||
|
|
||||||
export function isBehaviorItem(valueOrItem) {
|
export function isBehaviorItem(valueOrItem) {
|
||||||
if ('object' !== typeof valueOrItem) {
|
if ('object' !== typeof valueOrItem) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -42,27 +46,60 @@ export function typeFromValue(v) {
|
||||||
return isBehaviorItem(v) ? v.type : undefined;
|
return isBehaviorItem(v) ? v.type : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function typeFromSteps(context, steps) {
|
const stepTo = ([variable, type], step) => {
|
||||||
if (!steps || 0 === steps.length) {
|
const {key} = step;
|
||||||
return 'undefined';
|
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(
|
return [variable, type];
|
||||||
([v, type], step) => {
|
};
|
||||||
const {key} = step;
|
|
||||||
if (key) {
|
export function descriptionFromSteps(context, steps) {
|
||||||
const description = Context.typeDescription(type, v);
|
if (!steps || 0 === steps.length) {
|
||||||
return [
|
return {};
|
||||||
'object' === typeof v ? v[key] : undefined,
|
}
|
||||||
description[key] ? description[key].type : type,
|
const [variable, type] = steps.slice(1).reduce(stepTo, context.get(steps[0].key));
|
||||||
];
|
return Context.typeDescription(type, variable);
|
||||||
}
|
|
||||||
return [v, type];
|
|
||||||
},
|
|
||||||
context.get(steps[0].key),
|
|
||||||
);
|
|
||||||
return finalType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function typeFits(reference, candidate) {
|
export function typeFits(reference, candidate) {
|
||||||
return 'any' === reference || -1 !== (reference.split('|') || []).indexOf(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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user