fix: typing

This commit is contained in:
cha0s 2020-06-22 10:11:49 -05:00
parent e4ac23c75f
commit a8702b190c
3 changed files with 59 additions and 49 deletions

View File

@ -5,7 +5,7 @@ import React from 'react';
import useTypeRenderers from '~/client/hooks/useTypeRenderers';
import propTypes from './prop-types';
import {stepOptions, typeFromLiteral} from './typing';
import {stepsOptions, typeFromLiteral} from './typing';
const decorate = compose(
contempo(require('./literal.raw.scss')),
@ -19,7 +19,7 @@ const Literal = ({
const typeRenderers = useTypeRenderers();
const type = typeFromLiteral(value.value);
const Component = typeRenderers[type];
const options = stepOptions(context, [], 0, type);
const [options] = stepsOptions(context, [{type: 'key'}], type);
options.push('<literal>');
return (
<div className="literal">

View File

@ -5,7 +5,7 @@ import React from 'react';
import Value from '~/client/value';
import propTypes from './prop-types';
import {descriptionFromSteps, stepOptions, typeFromSteps} from './typing';
import {descriptionFromSteps, stepsOptions, typeFromSteps} from './typing';
const decorate = compose(
contempo(require('./traversal.raw.scss')),
@ -19,6 +19,7 @@ const Traversal = (props) => {
value: {steps, value},
} = props;
const stepsType = type || typeFromSteps(context, steps);
const optionsList = stepsOptions(context, steps, stepsType);
return (
<div className="traversal">
{steps.map((step, i) => (
@ -28,7 +29,7 @@ const Traversal = (props) => {
(() => {
switch (step.type) {
case 'key': {
const options = stepOptions(context, steps, i, stepsType);
const options = optionsList[i];
return (
<span className="key" data-step-key={step.key}>
<select readOnly value={step.key}>
@ -42,7 +43,7 @@ const Traversal = (props) => {
);
}
case 'invoke': {
const description = descriptionFromSteps(context, steps.slice(0, i + 1));
const description = descriptionFromSteps(context, steps);
return (
<div className="invoke">
<span className="paren open">(</span>

View File

@ -46,6 +46,59 @@ export function typeFromValue(v) {
return isBehaviorItem(v) ? v.type : undefined;
}
const fakeContextDescription = (context) => (
Object.entries(context.all())
.reduce((r, [key, tuple]) => ({...r, [key]: {type: tuple[1]}}), {})
);
export function descriptionFromSteps(context, steps) {
const isInvocation = 'invoke' === steps[steps.length - 1].type;
const keyStepsCount = steps.length - (isInvocation ? 1 : 0);
let description = fakeContextDescription(context);
let variable;
for (let i = 0; i < keyStepsCount; ++i) {
const {key} = steps[i];
variable = 0 === i ? context.get(key)[0] : variable[key];
const lookupDesc = Context.typeDescription(
description[key].type,
(isInvocation && keyStepsCount - 1 === i) ? undefined : variable,
);
description = 0 !== Object.keys(lookupDesc).length ? lookupDesc : description[key];
}
return description;
}
export function typeFits(reference, candidate) {
return 'any' === reference || -1 !== (reference.split('|') || []).indexOf(candidate);
}
export function stepsOptions(context, steps, type) {
const isInvocation = 'invoke' === steps[steps.length - 1].type;
const keyStepsCount = steps.length - (isInvocation ? 1 : 0);
const optionsList = [];
const inverted = cachedDigraph();
const candidates = (inverted[type] || []).concat(type);
for (let i = 0; i < keyStepsCount; ++i) {
let description = fakeContextDescription(context);
let variable;
for (let j = 0; j < i; ++j) {
const {key} = steps[j];
variable = 0 === j ? context.get(key)[0] : variable[key];
description = Context.typeDescription(description[key].type, variable);
}
const options = 'any' === type
? Object.keys(description)
: Object.entries(description)
.reduce((r, [key, spec]) => (
candidates.find((candidate) => typeFits(candidate, spec.type))
? r.concat(key)
: r
), []);
optionsList.push(options);
}
return optionsList;
}
const stepTo = ([variable, type], step) => {
const {key} = step;
if (key) {
@ -58,50 +111,6 @@ const stepTo = ([variable, type], step) => {
return [variable, type];
};
const fakeContextDescription = (context) => (
Object.entries(context.all())
.reduce((r, [key, tuple]) => ({...r, [key]: {type: tuple[1]}}), {})
);
export function descriptionFromSteps(context, steps) {
if (!steps || 0 === steps.length) {
return fakeContextDescription(context);
}
const max = Math.max(0, steps.length - 2);
const [variable, type] = steps.slice(0, max).reduce(stepTo, context.get(steps[0].key));
const description = Context.typeDescription(type, variable);
return 0 === max ? description : description[steps[max].key];
}
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 = descriptionFromSteps(context, []);
}
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';