inula/packages/transpiler/view-generator/src/NodeGenerators/CompGenerator.ts

154 lines
5.2 KiB
TypeScript

import { type types as t } from '@babel/core';
import { type DependencyProp, type CompParticle, type ViewParticle } from '@openinula/reactivity-parser';
import ForwardPropGenerator from '../HelperGenerators/ForwardPropGenerator';
export default class CompGenerator extends ForwardPropGenerator {
run() {
let { props } = this.viewParticle as CompParticle;
props = this.alterPropViews(props);
const { tag, children } = this.viewParticle as CompParticle;
const dlNodeName = this.generateNodeName();
this.addInitStatement(...this.declareCompNode(dlNodeName, tag, props, children));
const allDependencyIndexArr: number[] = [];
// ---- Resolve props
Object.entries(props).forEach(([key, { value, dependencyIndexArr, dependenciesNode }]) => {
if (key === 'forwardProps') return;
if (key === 'didUpdate') return;
allDependencyIndexArr.push(...dependencyIndexArr);
if (CompGenerator.lifecycle.includes(key as (typeof CompGenerator.lifecycle)[number])) {
this.addInitStatement(this.addLifecycle(dlNodeName, key as (typeof CompGenerator.lifecycle)[number], value));
return;
}
if (key === 'ref') {
this.addInitStatement(this.initElement(dlNodeName, value));
return;
}
if (key === 'elements') {
this.addInitStatement(this.initElement(dlNodeName, value, true));
return;
}
if (key === '_$content') {
this.addUpdateStatements(dependencyIndexArr, this.setCompContent(dlNodeName, value, dependenciesNode));
return;
}
if (key === 'props') {
this.addUpdateStatements(dependencyIndexArr, this.setCompProps(dlNodeName, value, dependenciesNode));
return;
}
this.addUpdateStatements(dependencyIndexArr, this.setCompProp(dlNodeName, key, value, dependenciesNode));
});
// ---- Add addUpdate last
if (props.didUpdate) {
this.addUpdateStatements(allDependencyIndexArr, this.addOnUpdate(dlNodeName, props.didUpdate.value));
}
return dlNodeName;
}
/**
* @View
* null
* or
* [[prop1, value1, deps1], [prop2, value2, deps2], ...
*/
private generateCompProps(props: Record<string, DependencyProp>): t.Expression {
if (Object.keys(props).length === 0) return this.t.nullLiteral();
return this.t.arrayExpression(
Object.entries(props).map(([key, { value, dependenciesNode }]) => {
return this.t.arrayExpression([this.t.stringLiteral(key), value, dependenciesNode]);
})
);
}
/**
* @View
* ${dlNodeName} = new ${tag}()
* ${dlNodeName}._$init(${props}, ${content}, ${children}, ${this})
*/
private declareCompNode(
dlNodeName: string,
tag: t.Expression,
props: Record<string, DependencyProp>,
children: ViewParticle[]
): t.Statement[] {
const willForwardProps = 'forwardProps' in props;
const newProps = Object.fromEntries(
Object.entries(props).filter(
([key]) =>
!['ref', 'elements', 'forwardProps', '_$content', 'didUpdate', 'props', ...CompGenerator.lifecycle].includes(
key
)
)
);
const content = props._$content;
return [
this.t.expressionStatement(
this.t.assignmentExpression('=', this.t.identifier(dlNodeName), this.t.newExpression(tag, []))
),
this.t.expressionStatement(
this.t.callExpression(this.t.memberExpression(this.t.identifier(dlNodeName), this.t.identifier('_$init')), [
this.generateCompProps(newProps),
content ? this.t.arrayExpression([content.value, content.dependenciesNode]) : this.t.nullLiteral(),
children.length > 0 ? this.t.identifier(this.declarePropView(children)) : this.t.nullLiteral(),
willForwardProps ? this.t.identifier('this') : this.t.nullLiteral(),
])
),
];
}
/**
* @View
* ${dlNodeName}._$setContent(() => ${value}, ${dependenciesNode})
*/
private setCompContent(dlNodeName: string, value: t.Expression, dependenciesNode: t.ArrayExpression): t.Statement {
return this.optionalExpression(
dlNodeName,
this.t.callExpression(this.t.memberExpression(this.t.identifier(dlNodeName), this.t.identifier('_$setContent')), [
this.t.arrowFunctionExpression([], value),
dependenciesNode,
])
);
}
/**
* @View
* ${dlNodeName}._$setProp(${key}, () => ${value}, ${dependenciesNode})
*/
private setCompProp(
dlNodeName: string,
key: string,
value: t.Expression,
dependenciesNode: t.ArrayExpression
): t.Statement {
return this.optionalExpression(
dlNodeName,
this.t.callExpression(this.t.memberExpression(this.t.identifier(dlNodeName), this.t.identifier('_$setProp')), [
this.t.stringLiteral(key),
this.t.arrowFunctionExpression([], value),
dependenciesNode,
])
);
}
/**
* @View
* ${dlNodeName}._$setProps(() => ${value}, ${dependenciesNode})
*/
private setCompProps(dlNodeName: string, value: t.Expression, dependenciesNode: t.ArrayExpression): t.Statement {
return this.optionalExpression(
dlNodeName,
this.t.callExpression(this.t.memberExpression(this.t.identifier(dlNodeName), this.t.identifier('_$setProps')), [
this.t.arrowFunctionExpression([], value),
dependenciesNode,
])
);
}
}