inula/packages/transpiler/view-generator/src/MainViewGenerator.ts

83 lines
2.8 KiB
TypeScript

import { type types as t } from '@babel/core';
import { type ViewParticle } from '@openinula/reactivity-parser';
import ViewGenerator from './ViewGenerator';
export default class MainViewGenerator extends ViewGenerator {
/**
* @brief Generate the main view, i.e., View() { ... }
* @param viewParticles
* @returns [viewBody, classProperties, templateIdx]
*/
generate(viewParticles: ViewParticle[]): [t.BlockStatement, t.ClassProperty[], number] {
const allClassProperties: t.ClassProperty[] = [];
const allInitStatements: t.Statement[] = [];
const allUpdateStatements: Record<number, t.Statement[]> = {};
const topLevelNodes: string[] = [];
viewParticles.forEach(viewParticle => {
const [initStatements, updateStatements, classProperties, nodeName] = this.generateChild(viewParticle);
allInitStatements.push(...initStatements);
Object.entries(updateStatements).forEach(([depNum, statements]) => {
if (!allUpdateStatements[Number(depNum)]) {
allUpdateStatements[Number(depNum)] = [];
}
allUpdateStatements[Number(depNum)].push(...statements);
});
allClassProperties.push(...classProperties);
topLevelNodes.push(nodeName);
});
const viewBody = this.t.blockStatement([
...this.declareNodes(),
...this.geneUpdate(allUpdateStatements),
...allInitStatements,
this.geneReturn(topLevelNodes),
]);
return [viewBody, allClassProperties, this.templateIdx];
}
/**
* @View
* this._$update = ($changed) => {
* if ($changed & 1) {
* ...
* }
* ...
* }
*/
private geneUpdate(updateStatements: Record<number, t.Statement[]>): t.Statement[] {
if (Object.keys(updateStatements).length === 0) return [];
return [
this.t.expressionStatement(
this.t.assignmentExpression(
'=',
this.t.memberExpression(this.t.thisExpression(), this.t.identifier('_$update'), false),
this.t.arrowFunctionExpression(
this.updateParams,
this.t.blockStatement([
...Object.entries(updateStatements)
.filter(([depNum]) => depNum !== '0')
.map(([depNum, statements]) => {
return this.t.ifStatement(
this.t.binaryExpression('&', this.t.identifier('$changed'), this.t.numericLiteral(Number(depNum))),
this.t.blockStatement(statements)
);
}),
...(updateStatements[0] ?? []),
])
)
)
),
];
}
/**
* @View
* return [${nodeNames}]
*/
private geneReturn(topLevelNodes: string[]) {
return this.t.returnStatement(this.t.arrayExpression(topLevelNodes.map(nodeName => this.t.identifier(nodeName))));
}
}