Create and make use of record constructors instead of literal objects.

This commit is contained in:
Robin Heggelund Hansen 2021-07-15 11:31:48 +02:00
parent 36e77be58a
commit fddb3c41a3
2 changed files with 75 additions and 7 deletions

View File

@ -1,10 +1,16 @@
import ts from 'typescript';
import { astNodes } from './utils/create';
export const recordUpdate = (): ts.TransformerFactory<ts.SourceFile> =>
(context) => (sourceFile) => {
const registry = new RecordRegistry();
ts.visitNode(sourceFile, replaceObjectLiterals(registry, context));
return sourceFile;
const replacedLiterals = ts.visitNode(sourceFile, replaceObjectLiterals(registry, context));
const recordStatements = createRecordStatements(registry);
replacedLiterals.statements = recordStatements.concat(replacedLiterals.statements);
return replacedLiterals;
}
@ -18,28 +24,91 @@ class RecordRegistry {
}
register(recordAst: ts.Node): String {
console.log(recordAst);
const shapeId = recordAst.properties.
map((it) => it.name.text).
join(",");
if (this.map.has(shapeId)) {
return this.map.get(shapeId);
}
const recordId = this.counter + 1;
this.counter = recordId;
const recordClassName = `Record${recordId}`;
this.map.set(shapeId, recordClassName);
return recordClassName;
}
}
function replaceObjectLiterals(_registry: RecordRegistry, ctx: ts.TransformationContext) {
function replaceObjectLiterals(registry: RecordRegistry, ctx: ts.TransformationContext) {
const visitorHelp = (node: ts.Node): ts.VisitResult<ts.Node> => {
if (isUpdateExpression(node)) {
return node;
}
const visitedNode = ts.visitEachChild(node, visitorHelp, ctx);
if (!isRecordLiteral(visitedNode)) {
return visitedNode;
}
const recordClassName = registry.register(visitedNode);
console.log(recordClassName);
const recordConstruction = ts.createParen(
ts.createNew(
ts.createIdentifier(recordClassName),
undefined,
visitedNode.properties.map((it) => it.initializer)
)
);
return visitedNode;
return recordConstruction;
}
return visitorHelp;
}
function isUpdateExpression(node: ts.Node): boolean {
return ts.isCallExpression(node) &&
ts.isIdentifier(node.expression) &&
node.expression.text === '_Utils_update';
}
function isRecordLiteral(node: ts.Node): boolean {
return ts.isObjectLiteralExpression(node) &&
node.properties.length > 0 &&
node.properties[0].name.text !== '$';
}
function createRecordStatements(registry: RecordRegistry): ts.Node[] {
const statementString = Array.from(registry.map.entries()).
map((it) => createRecordStatement(
it[1],
it[0].split(',')
)).join('\n');
return astNodes(statementString);
}
function createRecordStatement(className: String, props: String[]): String {
const propList = props.join(',');
const propSetters = props.
map((name) => `this.${name} = ${name};`).
join(' ');
const propGetters = props.
map((name) => `this.${name}`).
join(', ');
return `
function ${className}(${propList}) {
${propSetters}
}
${className}.prototype.$clone = function(cb) {
var clone = new ${className}(${propGetters});
cb(clone);
return clone;
}
`;
}

View File

@ -1,4 +1,3 @@
import ts from 'typescript';
export const ast = (sourceText: string): ts.Node => {