Convert src/compiler/compile/nodes/shared/get_const_tags.ts to JavaScript

pull/8569/head
Simon Holthausen 3 years ago
parent 160cdc948b
commit 3d81ad780e

@ -12,7 +12,9 @@ import replace_object from '../../utils/replace_object.js';
import is_contextual from './is_contextual.js'; import is_contextual from './is_contextual.js';
import { clone } from '../../../utils/clone.js'; import { clone } from '../../../utils/clone.js';
import compiler_errors from '../../compiler_errors.js'; import compiler_errors from '../../compiler_errors.js';
const regex_contains_term_function_expression = /FunctionExpression/; const regex_contains_term_function_expression = /FunctionExpression/;
export default class Expression { export default class Expression {
/** @type {'Expression'} */ /** @type {'Expression'} */
type = 'Expression'; type = 'Expression';
@ -20,7 +22,7 @@ export default class Expression {
/** @type {import('../../Component.js').default} */ /** @type {import('../../Component.js').default} */
component; component;
/** @type {Owner} */ /** @type {import('../interfaces.js').INode} */
owner; owner;
/** @type {import('estree').Node} */ /** @type {import('estree').Node} */
@ -54,7 +56,7 @@ export default class Expression {
/** /**
* @param {import('../../Component.js').default} component * * @param {import('../../Component.js').default} component *
* @param {Owner} owner * * @param {import('../interfaces.js').INode} owner *
* @param {import('./TemplateScope.js').default} template_scope * * @param {import('./TemplateScope.js').default} template_scope *
* @param {import('estree').Node} info * * @param {import('estree').Node} info *
* @param {boolean} [lazy] undefined * @param {boolean} [lazy] undefined
@ -362,6 +364,7 @@ export default class Expression {
// we need a combo block/init recipe // we need a combo block/init recipe
const { deps, func_declaration } = extract_functions(); const { deps, func_declaration } = extract_functions();
if (owner.type === 'Attribute' && owner.parent.name === 'slot') { if (owner.type === 'Attribute' && owner.parent.name === 'slot') {
/** @type {Set<import('../interfaces.js').INode>} */
const dep_scopes = new Set( const dep_scopes = new Set(
deps.map(/** @param {any} name */ (name) => template_scope.get_owner(name)) deps.map(/** @param {any} name */ (name) => template_scope.get_owner(name))
); );
@ -480,5 +483,3 @@ function get_function_name(_node, parent) {
} }
return 'func'; return 'func';
} }
/** @typedef {INode} Owner */

@ -1,98 +1,100 @@
import { TemplateNode, ConstTag as ConstTagType } from '../../../interfaces'; import ConstTag from '../ConstTag.js';
import Component from '../../Component'; import map_children from './map_children.js';
import ConstTag from '../ConstTag'; import check_graph_for_cycles from '../../utils/check_graph_for_cycles.js';
import map_children from './map_children'; import compiler_errors from '../../compiler_errors.js';
import { INodeAllowConstTag, INode } from '../interfaces';
import check_graph_for_cycles from '../../utils/check_graph_for_cycles'; /**
import compiler_errors from '../../compiler_errors'; * @param {import('../../../interfaces.js').TemplateNode[]} children
* @param {import('../../Component.js').default} component
export default function get_const_tags( * @param {import('../interfaces.js').INodeAllowConstTag} node
children: TemplateNode[], * @param {import('../interfaces.js').INode} parent
component: Component, * @returns {[import('../../../interfaces.js').ConstTag[], never[]]}
node: INodeAllowConstTag, */
parent: INode export default function get_const_tags(children, component, node, parent) {
): [ConstTag[], Array<Exclude<INode, ConstTag>>] {
const const_tags: ConstTagType[] = []; /** @type {ConstTagType[]} */
const others: Array<Exclude<TemplateNode, ConstTagType>> = []; const const_tags = [];
for (const child of children) { /** @type {Array<Exclude<import('../../../interfaces.js').TemplateNode, ConstTagType>>} */
if (child.type === 'ConstTag') { const others = [];
const_tags.push(child as ConstTagType); for (const child of children) {
} else { if (child.type === 'ConstTag') {
others.push(child); const_tags.push(/** @type {ConstTagType} */ (child));
} }
} else {
others.push(child);
const consts_nodes = const_tags.map((tag) => new ConstTag(component, node, node.scope, tag)); }
const sorted_consts_nodes = sort_consts_nodes(consts_nodes, component); }
sorted_consts_nodes.forEach((node) => node.parse_expression()); const consts_nodes = const_tags.map(/** @param {any} tag */ (tag) => new ConstTag(component, node, node.scope, tag));
const sorted_consts_nodes = sort_consts_nodes(consts_nodes, component);
const children_nodes = map_children(component, parent, node.scope, others); sorted_consts_nodes.forEach(/** @param {any} node */ (node) => node.parse_expression());
const children_nodes = map_children(component, parent, node.scope, others);
return [sorted_consts_nodes, children_nodes as Array<Exclude<INode, ConstTag>>]; return [sorted_consts_nodes, /** @type {Array<Exclude<import('../interfaces.js').INode, import('../../../interfaces.js').ConstTag>>} */ (children_nodes)];
} }
function sort_consts_nodes(consts_nodes: ConstTag[], component: Component) { /**
type ConstNode = { * @param {import('../../../interfaces.js').ConstTag[]} consts_nodes
assignees: Set<string>; * @param {import('../../Component.js').default} component
dependencies: Set<string>; */
node: ConstTag; function sort_consts_nodes(consts_nodes, component) {
};
const sorted_consts_nodes: ConstNode[] = []; /** @type {ConstNode[]} */
const sorted_consts_nodes = [];
const unsorted_consts_nodes: ConstNode[] = consts_nodes.map((node) => {
return { /** @type {ConstNode[]} */
assignees: node.assignees, const unsorted_consts_nodes = consts_nodes.map(/** @param {any} node */ (node) => {
dependencies: node.dependencies, return {
node assignees: node.assignees,
}; dependencies: node.dependencies,
}); node
};
const lookup = new Map(); });
const lookup = new Map();
unsorted_consts_nodes.forEach((node) => { unsorted_consts_nodes.forEach(/** @param {any} node */ (node) => {
node.assignees.forEach((name) => { node.assignees.forEach(/** @param {any} name */ (name) => {
if (!lookup.has(name)) { if (!lookup.has(name)) {
lookup.set(name, []); lookup.set(name, []);
} }
lookup.get(name).push(node); lookup.get(name).push(node);
}); });
}); });
const cycle = check_graph_for_cycles(unsorted_consts_nodes.reduce(/**
const cycle = check_graph_for_cycles( * @param {any} acc
unsorted_consts_nodes.reduce((acc, node) => { * @param {any} node
node.assignees.forEach((v) => { */ (acc, node) => {
node.dependencies.forEach((w) => { node.assignees.forEach(/** @param {any} v */ (v) => {
if (!node.assignees.has(w)) { node.dependencies.forEach(/** @param {any} w */ (w) => {
acc.push([v, w]); if (!node.assignees.has(w)) {
} acc.push([v, w]);
}); }
}); });
return acc; });
}, []) return acc;
); }, []));
if (cycle && cycle.length) {
if (cycle && cycle.length) { const nodeList = lookup.get(cycle[0]);
const nodeList = lookup.get(cycle[0]); const node = nodeList[0];
const node = nodeList[0]; component.error(node.node, compiler_errors.cyclical_const_tags(cycle));
component.error(node.node, compiler_errors.cyclical_const_tags(cycle)); }
}
/** @param {ConstNode} node */
const add_node = (node: ConstNode) => { const add_node = (node) => {
if (sorted_consts_nodes.includes(node)) return; if (sorted_consts_nodes.includes(node))
return;
node.dependencies.forEach(/** @param {any} name */ (name) => {
if (node.assignees.has(name))
return;
const earlier_nodes = lookup.get(name);
if (earlier_nodes) {
earlier_nodes.forEach(add_node);
}
});
sorted_consts_nodes.push(node);
};
unsorted_consts_nodes.forEach(add_node);
return sorted_consts_nodes.map(/** @param {any} node */ (node) => node.node);
}
node.dependencies.forEach((name) => {
if (node.assignees.has(name)) return;
const earlier_nodes = lookup.get(name);
if (earlier_nodes) {
earlier_nodes.forEach(add_node);
}
});
sorted_consts_nodes.push(node);
};
unsorted_consts_nodes.forEach(add_node);
return sorted_consts_nodes.map((node) => node.node);
}

Loading…
Cancel
Save