|
|
|
@ -1,13 +1,24 @@
|
|
|
|
import { x } from 'code-red';
|
|
|
|
import { b, x } from 'code-red';
|
|
|
|
import { Node, Identifier, Expression } from 'estree';
|
|
|
|
import { Node, Identifier, Expression as ESTreeExpression } from 'estree';
|
|
|
|
import { walk } from 'estree-walker';
|
|
|
|
import { walk } from 'estree-walker';
|
|
|
|
import is_reference, { NodeWithPropertyDefinition } from 'is-reference';
|
|
|
|
import is_reference, { NodeWithPropertyDefinition } from 'is-reference';
|
|
|
|
import { clone } from '../../../utils/clone';
|
|
|
|
import { clone } from '../../../utils/clone';
|
|
|
|
import Component from '../../Component';
|
|
|
|
import Component from '../../Component';
|
|
|
|
|
|
|
|
import Block from '../../render_dom/Block';
|
|
|
|
import flatten_reference from '../../utils/flatten_reference';
|
|
|
|
import flatten_reference from '../../utils/flatten_reference';
|
|
|
|
|
|
|
|
import { INode } from '../interfaces';
|
|
|
|
|
|
|
|
import Expression from './Expression';
|
|
|
|
import TemplateScope from './TemplateScope';
|
|
|
|
import TemplateScope from './TemplateScope';
|
|
|
|
|
|
|
|
|
|
|
|
export interface Context {
|
|
|
|
export type Context = DestructuredVariable | ComputedProperty;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
interface ComputedProperty {
|
|
|
|
|
|
|
|
type: 'ComputedProperty';
|
|
|
|
|
|
|
|
declaration: (block: Block, scope: TemplateScope, ctx: string) => Node[];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
interface DestructuredVariable {
|
|
|
|
|
|
|
|
type: 'DestructuredVariable'
|
|
|
|
key: Identifier;
|
|
|
|
key: Identifier;
|
|
|
|
name?: string;
|
|
|
|
name?: string;
|
|
|
|
modifier: (node: Node) => Node;
|
|
|
|
modifier: (node: Node) => Node;
|
|
|
|
@ -21,26 +32,32 @@ export function unpack_destructuring({
|
|
|
|
default_modifier = (node) => node,
|
|
|
|
default_modifier = (node) => node,
|
|
|
|
scope,
|
|
|
|
scope,
|
|
|
|
component,
|
|
|
|
component,
|
|
|
|
context_rest_properties
|
|
|
|
context_rest_properties,
|
|
|
|
|
|
|
|
owner,
|
|
|
|
|
|
|
|
number_of_computed_props = 0
|
|
|
|
}: {
|
|
|
|
}: {
|
|
|
|
contexts: Context[];
|
|
|
|
contexts: Context[];
|
|
|
|
node: Node;
|
|
|
|
node: Node;
|
|
|
|
modifier?: Context['modifier'];
|
|
|
|
modifier?: DestructuredVariable['modifier'];
|
|
|
|
default_modifier?: Context['default_modifier'];
|
|
|
|
default_modifier?: DestructuredVariable['default_modifier'];
|
|
|
|
scope: TemplateScope;
|
|
|
|
scope: TemplateScope;
|
|
|
|
component: Component;
|
|
|
|
component: Component;
|
|
|
|
context_rest_properties: Map<string, Node>;
|
|
|
|
context_rest_properties: Map<string, Node>;
|
|
|
|
|
|
|
|
owner: INode;
|
|
|
|
|
|
|
|
number_of_computed_props?: number;
|
|
|
|
}) {
|
|
|
|
}) {
|
|
|
|
if (!node) return;
|
|
|
|
if (!node) return;
|
|
|
|
|
|
|
|
|
|
|
|
if (node.type === 'Identifier') {
|
|
|
|
if (node.type === 'Identifier') {
|
|
|
|
contexts.push({
|
|
|
|
contexts.push({
|
|
|
|
|
|
|
|
type: 'DestructuredVariable',
|
|
|
|
key: node as Identifier,
|
|
|
|
key: node as Identifier,
|
|
|
|
modifier,
|
|
|
|
modifier,
|
|
|
|
default_modifier
|
|
|
|
default_modifier
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else if (node.type === 'RestElement') {
|
|
|
|
} else if (node.type === 'RestElement') {
|
|
|
|
contexts.push({
|
|
|
|
contexts.push({
|
|
|
|
|
|
|
|
type: 'DestructuredVariable',
|
|
|
|
key: node.argument as Identifier,
|
|
|
|
key: node.argument as Identifier,
|
|
|
|
modifier,
|
|
|
|
modifier,
|
|
|
|
default_modifier
|
|
|
|
default_modifier
|
|
|
|
@ -56,7 +73,9 @@ export function unpack_destructuring({
|
|
|
|
default_modifier,
|
|
|
|
default_modifier,
|
|
|
|
scope,
|
|
|
|
scope,
|
|
|
|
component,
|
|
|
|
component,
|
|
|
|
context_rest_properties
|
|
|
|
context_rest_properties,
|
|
|
|
|
|
|
|
owner,
|
|
|
|
|
|
|
|
number_of_computed_props
|
|
|
|
});
|
|
|
|
});
|
|
|
|
context_rest_properties.set((element.argument as Identifier).name, element);
|
|
|
|
context_rest_properties.set((element.argument as Identifier).name, element);
|
|
|
|
} else if (element && element.type === 'AssignmentPattern') {
|
|
|
|
} else if (element && element.type === 'AssignmentPattern') {
|
|
|
|
@ -76,7 +95,9 @@ export function unpack_destructuring({
|
|
|
|
)}` as Node,
|
|
|
|
)}` as Node,
|
|
|
|
scope,
|
|
|
|
scope,
|
|
|
|
component,
|
|
|
|
component,
|
|
|
|
context_rest_properties
|
|
|
|
context_rest_properties,
|
|
|
|
|
|
|
|
owner,
|
|
|
|
|
|
|
|
number_of_computed_props
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
unpack_destructuring({
|
|
|
|
unpack_destructuring({
|
|
|
|
@ -86,7 +107,9 @@ export function unpack_destructuring({
|
|
|
|
default_modifier,
|
|
|
|
default_modifier,
|
|
|
|
scope,
|
|
|
|
scope,
|
|
|
|
component,
|
|
|
|
component,
|
|
|
|
context_rest_properties
|
|
|
|
context_rest_properties,
|
|
|
|
|
|
|
|
owner,
|
|
|
|
|
|
|
|
number_of_computed_props
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
@ -105,29 +128,43 @@ export function unpack_destructuring({
|
|
|
|
default_modifier,
|
|
|
|
default_modifier,
|
|
|
|
scope,
|
|
|
|
scope,
|
|
|
|
component,
|
|
|
|
component,
|
|
|
|
context_rest_properties
|
|
|
|
context_rest_properties,
|
|
|
|
|
|
|
|
owner,
|
|
|
|
|
|
|
|
number_of_computed_props
|
|
|
|
});
|
|
|
|
});
|
|
|
|
context_rest_properties.set((property.argument as Identifier).name, property);
|
|
|
|
context_rest_properties.set((property.argument as Identifier).name, property);
|
|
|
|
} else if (property.type === 'Property') {
|
|
|
|
} else if (property.type === 'Property') {
|
|
|
|
const key = property.key;
|
|
|
|
const key = property.key;
|
|
|
|
const value = property.value;
|
|
|
|
const value = property.value;
|
|
|
|
|
|
|
|
|
|
|
|
let property_name: any;
|
|
|
|
|
|
|
|
let new_modifier: (node: Node) => Node;
|
|
|
|
let new_modifier: (node: Node) => Node;
|
|
|
|
|
|
|
|
|
|
|
|
if (property.computed) {
|
|
|
|
if (property.computed) {
|
|
|
|
// TODO: If the property is computed, ie, { [computed_key]: prop }, the computed_key can be any type of expression.
|
|
|
|
// TODO: If the property is computed, ie, { [computed_key]: prop }, the computed_key can be any type of expression.
|
|
|
|
|
|
|
|
const computed_property = `#computed_property_${number_of_computed_props}`;
|
|
|
|
|
|
|
|
new_modifier = (node) => x`${modifier(node)}[${computed_property}]`;
|
|
|
|
|
|
|
|
used_properties.push(x`${computed_property}`);
|
|
|
|
|
|
|
|
number_of_computed_props += 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
contexts.push({
|
|
|
|
|
|
|
|
type: 'ComputedProperty',
|
|
|
|
|
|
|
|
declaration: (block, scope, ctx) => {
|
|
|
|
|
|
|
|
const computed_expression = new Expression(component, owner, scope, key);
|
|
|
|
|
|
|
|
return b`const ${computed_property} = ${computed_expression.manipulate(block, ctx)}`;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
} else if (key.type === 'Identifier') {
|
|
|
|
} else if (key.type === 'Identifier') {
|
|
|
|
// e.g. { someProperty: ... }
|
|
|
|
// e.g. { someProperty: ... }
|
|
|
|
property_name = key.name;
|
|
|
|
const property_name = key.name;
|
|
|
|
new_modifier = (node) => x`${modifier(node)}.${property_name}`;
|
|
|
|
new_modifier = (node) => x`${modifier(node)}.${property_name}`;
|
|
|
|
|
|
|
|
used_properties.push(x`"${property_name}"`);
|
|
|
|
} else if (key.type === 'Literal') {
|
|
|
|
} else if (key.type === 'Literal') {
|
|
|
|
// e.g. { "property-in-quotes": ... } or { 14: ... }
|
|
|
|
// e.g. { "property-in-quotes": ... } or { 14: ... }
|
|
|
|
property_name = key.value;
|
|
|
|
const property_name = key.value;
|
|
|
|
new_modifier = (node) => x`${modifier(node)}["${property_name}"]`;
|
|
|
|
new_modifier = (node) => x`${modifier(node)}["${property_name}"]`;
|
|
|
|
|
|
|
|
used_properties.push(x`"${property_name}"`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
used_properties.push(x`"${property_name}"`);
|
|
|
|
|
|
|
|
if (value.type === 'AssignmentPattern') {
|
|
|
|
if (value.type === 'AssignmentPattern') {
|
|
|
|
// e.g. { property = default } or { property: newName = default }
|
|
|
|
// e.g. { property = default } or { property: newName = default }
|
|
|
|
const n = contexts.length;
|
|
|
|
const n = contexts.length;
|
|
|
|
@ -147,7 +184,9 @@ export function unpack_destructuring({
|
|
|
|
)}` as Node,
|
|
|
|
)}` as Node,
|
|
|
|
scope,
|
|
|
|
scope,
|
|
|
|
component,
|
|
|
|
component,
|
|
|
|
context_rest_properties
|
|
|
|
context_rest_properties,
|
|
|
|
|
|
|
|
owner,
|
|
|
|
|
|
|
|
number_of_computed_props
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// e.g. { property } or { property: newName }
|
|
|
|
// e.g. { property } or { property: newName }
|
|
|
|
@ -158,7 +197,9 @@ export function unpack_destructuring({
|
|
|
|
default_modifier,
|
|
|
|
default_modifier,
|
|
|
|
scope,
|
|
|
|
scope,
|
|
|
|
component,
|
|
|
|
component,
|
|
|
|
context_rest_properties
|
|
|
|
context_rest_properties,
|
|
|
|
|
|
|
|
owner,
|
|
|
|
|
|
|
|
number_of_computed_props
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -169,14 +210,17 @@ export function unpack_destructuring({
|
|
|
|
function update_reference(
|
|
|
|
function update_reference(
|
|
|
|
contexts: Context[],
|
|
|
|
contexts: Context[],
|
|
|
|
n: number,
|
|
|
|
n: number,
|
|
|
|
expression: Expression,
|
|
|
|
expression: ESTreeExpression,
|
|
|
|
to_ctx: (name: string) => Node
|
|
|
|
to_ctx: (name: string) => Node
|
|
|
|
): Node {
|
|
|
|
): Node {
|
|
|
|
const find_from_context = (node: Identifier) => {
|
|
|
|
const find_from_context = (node: Identifier) => {
|
|
|
|
for (let i = n; i < contexts.length; i++) {
|
|
|
|
for (let i = n; i < contexts.length; i++) {
|
|
|
|
const { key } = contexts[i];
|
|
|
|
const cur_context = contexts[i];
|
|
|
|
if (node.name === key.name) {
|
|
|
|
if (cur_context.type === 'DestructuredVariable') {
|
|
|
|
throw new Error(`Cannot access '${node.name}' before initialization`);
|
|
|
|
const { key } = cur_context;
|
|
|
|
|
|
|
|
if (node.name === key.name) {
|
|
|
|
|
|
|
|
throw new Error(`Cannot access '${node.name}' before initialization`);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return to_ctx(node.name);
|
|
|
|
return to_ctx(node.name);
|
|
|
|
@ -187,7 +231,7 @@ function update_reference(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NOTE: avoid unnecessary deep clone?
|
|
|
|
// NOTE: avoid unnecessary deep clone?
|
|
|
|
expression = clone(expression) as Expression;
|
|
|
|
expression = clone(expression) as ESTreeExpression;
|
|
|
|
walk(expression, {
|
|
|
|
walk(expression, {
|
|
|
|
enter(node, parent: Node) {
|
|
|
|
enter(node, parent: Node) {
|
|
|
|
if (
|
|
|
|
if (
|
|
|
|
|