|
|
|
@ -1,5 +1,5 @@
|
|
|
|
|
import { x } from 'code-red';
|
|
|
|
|
import { Node, Identifier, Expression } from 'estree';
|
|
|
|
|
import { Node, Identifier, Expression, PrivateIdentifier } from 'estree';
|
|
|
|
|
import { walk } from 'estree-walker';
|
|
|
|
|
import is_reference, { NodeWithPropertyDefinition } from 'is-reference';
|
|
|
|
|
import { clone } from '../../../utils/clone';
|
|
|
|
@ -7,7 +7,16 @@ import Component from '../../Component';
|
|
|
|
|
import flatten_reference from '../../utils/flatten_reference';
|
|
|
|
|
import TemplateScope from './TemplateScope';
|
|
|
|
|
|
|
|
|
|
export interface Context {
|
|
|
|
|
export type Context = DestructuredVariable | ComputedProperty;
|
|
|
|
|
|
|
|
|
|
interface ComputedProperty {
|
|
|
|
|
type: 'ComputedProperty';
|
|
|
|
|
property_name: string;
|
|
|
|
|
key: Expression | PrivateIdentifier;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface DestructuredVariable {
|
|
|
|
|
type: 'DestructuredVariable'
|
|
|
|
|
key: Identifier;
|
|
|
|
|
name?: string;
|
|
|
|
|
modifier: (node: Node) => Node;
|
|
|
|
@ -21,26 +30,33 @@ export function unpack_destructuring({
|
|
|
|
|
default_modifier = (node) => node,
|
|
|
|
|
scope,
|
|
|
|
|
component,
|
|
|
|
|
context_rest_properties
|
|
|
|
|
context_rest_properties,
|
|
|
|
|
number_of_computed_props = { n: 0 }
|
|
|
|
|
}: {
|
|
|
|
|
contexts: Context[];
|
|
|
|
|
node: Node;
|
|
|
|
|
modifier?: Context['modifier'];
|
|
|
|
|
default_modifier?: Context['default_modifier'];
|
|
|
|
|
modifier?: DestructuredVariable['modifier'];
|
|
|
|
|
default_modifier?: DestructuredVariable['default_modifier'];
|
|
|
|
|
scope: TemplateScope;
|
|
|
|
|
component: Component;
|
|
|
|
|
context_rest_properties: Map<string, Node>;
|
|
|
|
|
// we want to pass this by reference, as a sort of global variable, because
|
|
|
|
|
// if we pass this by value, we could get computed_property_# variable collisions
|
|
|
|
|
// when we deal with nested object destructuring
|
|
|
|
|
number_of_computed_props?: { n: number };
|
|
|
|
|
}) {
|
|
|
|
|
if (!node) return;
|
|
|
|
|
|
|
|
|
|
if (node.type === 'Identifier') {
|
|
|
|
|
contexts.push({
|
|
|
|
|
type: 'DestructuredVariable',
|
|
|
|
|
key: node as Identifier,
|
|
|
|
|
modifier,
|
|
|
|
|
default_modifier
|
|
|
|
|
});
|
|
|
|
|
} else if (node.type === 'RestElement') {
|
|
|
|
|
contexts.push({
|
|
|
|
|
type: 'DestructuredVariable',
|
|
|
|
|
key: node.argument as Identifier,
|
|
|
|
|
modifier,
|
|
|
|
|
default_modifier
|
|
|
|
@ -56,7 +72,8 @@ export function unpack_destructuring({
|
|
|
|
|
default_modifier,
|
|
|
|
|
scope,
|
|
|
|
|
component,
|
|
|
|
|
context_rest_properties
|
|
|
|
|
context_rest_properties,
|
|
|
|
|
number_of_computed_props
|
|
|
|
|
});
|
|
|
|
|
context_rest_properties.set((element.argument as Identifier).name, element);
|
|
|
|
|
} else if (element && element.type === 'AssignmentPattern') {
|
|
|
|
@ -76,7 +93,8 @@ export function unpack_destructuring({
|
|
|
|
|
)}` as Node,
|
|
|
|
|
scope,
|
|
|
|
|
component,
|
|
|
|
|
context_rest_properties
|
|
|
|
|
context_rest_properties,
|
|
|
|
|
number_of_computed_props
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
unpack_destructuring({
|
|
|
|
@ -86,7 +104,8 @@ export function unpack_destructuring({
|
|
|
|
|
default_modifier,
|
|
|
|
|
scope,
|
|
|
|
|
component,
|
|
|
|
|
context_rest_properties
|
|
|
|
|
context_rest_properties,
|
|
|
|
|
number_of_computed_props
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
@ -105,29 +124,41 @@ export function unpack_destructuring({
|
|
|
|
|
default_modifier,
|
|
|
|
|
scope,
|
|
|
|
|
component,
|
|
|
|
|
context_rest_properties
|
|
|
|
|
context_rest_properties,
|
|
|
|
|
number_of_computed_props
|
|
|
|
|
});
|
|
|
|
|
context_rest_properties.set((property.argument as Identifier).name, property);
|
|
|
|
|
} else if (property.type === 'Property') {
|
|
|
|
|
const key = property.key;
|
|
|
|
|
const value = property.value;
|
|
|
|
|
|
|
|
|
|
let property_name: any;
|
|
|
|
|
let new_modifier: (node: Node) => Node;
|
|
|
|
|
|
|
|
|
|
if (property.computed) {
|
|
|
|
|
// TODO: If the property is computed, ie, { [computed_key]: prop }, the computed_key can be any type of expression.
|
|
|
|
|
// e.g { [computedProperty]: ... }
|
|
|
|
|
const property_name = `computed_property_${number_of_computed_props.n}`;
|
|
|
|
|
number_of_computed_props.n += 1;
|
|
|
|
|
|
|
|
|
|
contexts.push({
|
|
|
|
|
type: 'ComputedProperty',
|
|
|
|
|
property_name,
|
|
|
|
|
key
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
new_modifier = (node) => x`${modifier(node)}[${property_name}]`;
|
|
|
|
|
used_properties.push(x`${property_name}`);
|
|
|
|
|
} else if (key.type === 'Identifier') {
|
|
|
|
|
// e.g. { someProperty: ... }
|
|
|
|
|
property_name = key.name;
|
|
|
|
|
const property_name = key.name;
|
|
|
|
|
new_modifier = (node) => x`${modifier(node)}.${property_name}`;
|
|
|
|
|
used_properties.push(x`"${property_name}"`);
|
|
|
|
|
} else if (key.type === 'Literal') {
|
|
|
|
|
// e.g. { "property-in-quotes": ... } or { 14: ... }
|
|
|
|
|
property_name = key.value;
|
|
|
|
|
const property_name = key.value;
|
|
|
|
|
new_modifier = (node) => x`${modifier(node)}["${property_name}"]`;
|
|
|
|
|
used_properties.push(x`"${property_name}"`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
used_properties.push(x`"${property_name}"`);
|
|
|
|
|
if (value.type === 'AssignmentPattern') {
|
|
|
|
|
// e.g. { property = default } or { property: newName = default }
|
|
|
|
|
const n = contexts.length;
|
|
|
|
@ -147,7 +178,8 @@ export function unpack_destructuring({
|
|
|
|
|
)}` as Node,
|
|
|
|
|
scope,
|
|
|
|
|
component,
|
|
|
|
|
context_rest_properties
|
|
|
|
|
context_rest_properties,
|
|
|
|
|
number_of_computed_props
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
// e.g. { property } or { property: newName }
|
|
|
|
@ -158,7 +190,8 @@ export function unpack_destructuring({
|
|
|
|
|
default_modifier,
|
|
|
|
|
scope,
|
|
|
|
|
component,
|
|
|
|
|
context_rest_properties
|
|
|
|
|
context_rest_properties,
|
|
|
|
|
number_of_computed_props
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -174,7 +207,9 @@ function update_reference(
|
|
|
|
|
): Node {
|
|
|
|
|
const find_from_context = (node: Identifier) => {
|
|
|
|
|
for (let i = n; i < contexts.length; i++) {
|
|
|
|
|
const { key } = contexts[i];
|
|
|
|
|
const cur_context = contexts[i];
|
|
|
|
|
if (cur_context.type !== 'DestructuredVariable') continue;
|
|
|
|
|
const { key } = cur_context;
|
|
|
|
|
if (node.name === key.name) {
|
|
|
|
|
throw new Error(`Cannot access '${node.name}' before initialization`);
|
|
|
|
|
}
|
|
|
|
|