Skip to content

Commit

Permalink
#76, copy fields support, part 4.
Browse files Browse the repository at this point in the history
  • Loading branch information
ajvincent committed Mar 2, 2024
1 parent 708176a commit b23b149
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 44 deletions.
83 changes: 83 additions & 0 deletions stage_3_generation/build/decorators/CloneStatement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//#region preamble
import {
CodeBlockWriter,
} from "ts-morph";

import {
ClassFieldStatementsMap,
LiteralTypeStructureImpl,
MemberedStatementsKey,
MethodSignatureImpl,
ParameterDeclarationImpl,
UnionTypeStructureImpl,
type stringWriterOrStatementImpl,
} from "#stage_two/snapshot/source/exports.js";

import GetterFilter from "../fieldStatements/GetterFilter.js";

import BlockStatementImpl from "../../pseudoStatements/BlockStatement.js";
import CallExpressionStatementImpl from "#stage_three/generation/pseudoStatements/CallExpression.js";
//#endregion preamble

export default class CloneStatement_Statements extends GetterFilter
{
getMethodSignature(): MethodSignatureImpl
{
this.module.addImports("ts-morph", [], ["StatementStructures"]);
this.module.addImports("public", [], ["stringOrWriterFunction", "StatementStructureImpls"]);
const method = new MethodSignatureImpl("#cloneStatement");

const param = new ParameterDeclarationImpl("source");
param.typeStructure = new UnionTypeStructureImpl([
LiteralTypeStructureImpl.get("stringOrWriterFunction"),
LiteralTypeStructureImpl.get("StatementStructures")
]);
method.parameters.push(param);

method.returnTypeStructure = new UnionTypeStructureImpl([
LiteralTypeStructureImpl.get("stringOrWriterFunction"),
LiteralTypeStructureImpl.get("StatementStructureImpls")
]);

return method;
}

accept(
key: MemberedStatementsKey
): boolean
{
return (
(key.statementGroupKey === "static #cloneStatement") &&
(key.fieldKey === ClassFieldStatementsMap.FIELD_TAIL_FINAL_RETURN)
);
}

getStatements(
key: MemberedStatementsKey
): readonly stringWriterOrStatementImpl[]
{
void(key);
this.module.addImports("internal", ["StructureClassesMap"], []);

return [
new BlockStatementImpl(
`if (typeof source !== "object")`,
[
`return source;`
]
).writerFunction,

(writer: CodeBlockWriter): void => {
writer.write("return ");
(new CallExpressionStatementImpl({
name: "StructureClassesMap.clone",
typeParameters: [
LiteralTypeStructureImpl.get("StatementStructures"),
LiteralTypeStructureImpl.get("StatementStructureImpls"),
],
parameters: ["source"]
})).writerFunction(writer);
}
]
}
}
8 changes: 8 additions & 0 deletions stage_3_generation/build/decorators/createDecorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
import modifyTypeMembersForTypeStructures from "../classTools/modifyTypeMembersForTypeStructures.js";

import StatementsRouter from "../fieldStatements/StatementsRouter.js";
import CloneStatement_Statements from "./CloneStatement.js";

import {
addImportsToModule,
Expand Down Expand Up @@ -60,6 +61,13 @@ async function buildDecorator(

typeToClass.addTypeMember(true, module.createCopyFieldsMethod())

if (name.startsWith("StatementedNode")) {
const cloneStatementFilter = new CloneStatement_Statements(module);
router.filters.unshift(cloneStatementFilter);
typeToClass.addTypeMember(true, cloneStatementFilter.getMethodSignature());
}


typeToClass.defineStatementsByPurpose("body", false);
module.classMembersMap = typeToClass.buildClassMembersMap();

Expand Down
113 changes: 74 additions & 39 deletions stage_3_generation/build/fieldStatements/CopyFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
LiteralTypeStructureImpl,
MemberedStatementsKey,
ParenthesesTypeStructureImpl,
QualifiedNameTypeStructureImpl,
type PropertySignatureImpl,
TypeStructureKind,
type TypeStructures,
Expand All @@ -30,6 +31,7 @@ import {
} from "#stage_two/snapshot/source/exports.js";

import {
getClassInterfaceName,
getStructureNameFromModified,
} from "#utilities/source/StructureNameTransforms.js";

Expand All @@ -41,6 +43,7 @@ import GetterFilter from "../fieldStatements/GetterFilter.js";

import BlockStatementImpl from "../../pseudoStatements/BlockStatement.js";
import CallExpressionStatementImpl from "#stage_three/generation/pseudoStatements/CallExpression.js";
import InterfaceModule from "#stage_three/generation/moduleClasses/InterfaceModule.js";
//#endregion preamble

const booleanType = LiteralTypeStructureImpl.get("boolean");
Expand Down Expand Up @@ -202,12 +205,21 @@ export default class CopyFieldsStatements extends GetterFilter
{
const { name } = fieldType;

if (name === "statements") {
if ((this.module.baseName === "StatementedNodeStructure") && (name === "statements")) {
return this.#getStatementsForCloneStatements();
}

const originalField = this.#getOriginalField(name);
void(originalField);
if ((this.module.baseName === "Structure") && (
(name === "leadingTrivia") || (name === "trailingTrivia")
))
{
return this.#getStatementsForTrivia(name);
}

// DecoratableNodeStructureMixin
// JSDocableNodeStructureMixin
// ParameteredNodeStructureMixin
// TypeParameteredNodeStructureMixin

if (objectType.kind === TypeStructureKind.Parentheses)
objectType = objectType.childTypes[0];
Expand All @@ -217,50 +229,73 @@ export default class CopyFieldsStatements extends GetterFilter

const childTypes = types as readonly ReadonlyDeep<LiteralTypeStructureImpl>[];

let useStructureClassesMap = false;
let includesString = false;
let generatedClassName = "";

for (const childType of childTypes) {
if (childType === stringType) {
includesString = true;
}
else if (childType === LiteralTypeStructureImpl.get("stringOrWriterFunction")) {
if (childType === LiteralTypeStructureImpl.get("stringOrWriterFunction")) {
this.module.addImports("public", [], ["stringOrWriterFunction"]);
}
else if (getStructureNameFromModified(childType.stringValue) !== childType.stringValue) {
this.module.addImports(
"public",
["StructureClassesMap"],
[childType.stringValue]
);
useStructureClassesMap = true;
}
}
assert(generatedClassName === "");

void(includesString);
// DecoratableNodeStructureMixin
// JSDocableNodeStructureMixin
// ParameteredNodeStructureMixin
// TypeParameteredNodeStructureMixin
this.module.addImports("public", [], [childType.stringValue]);
this.module.addImports("internal", ["StructureClassesMap"], []);

if (useStructureClassesMap) {
/*
if (source.decorators) {
target.decorators.push(
...StructureClassesMap.cloneArrayWithKind<
DecoratorStructure,
StructureKind.Decorator,
DecoratorImpl
>(
StructureKind.Decorator,
StructureClassesMap.forceArray(source.decorators),
),
);
generatedClassName = childType.stringValue;
}
*/
return [];
}
assert(generatedClassName, `we should be ready to clone structures now, ${this.module.decoratorName}:${name}`);

const generatedStructureName = getStructureNameFromModified(generatedClassName);
const generatedInterfaceName = getClassInterfaceName(generatedStructureName);
const generatedStructureKind = InterfaceModule.structuresMap.get(generatedInterfaceName)!.structureKindName!;

this.module.addImports(
"ts-morph", [], ["StructureKind", generatedStructureName]
);

const callClone = new CallExpressionStatementImpl({
name: "...StructureClassesMap.cloneArrayWithKind",
typeParameters: [
LiteralTypeStructureImpl.get(generatedStructureName),
new QualifiedNameTypeStructureImpl([
"StructureKind",
generatedStructureKind
]),
objectType as TypeStructures
],
parameters: [
`StructureKind.${generatedStructureKind}`,
new CallExpressionStatementImpl({
name: `StructureClassesMap.forceArray`,
parameters: [
`source.${name}`
]
})
]
});

assert(name === "leadingTrivia" || name === "trailingTrivia");
return [
new BlockStatementImpl(
`if (source.${name})`,
[
new CallExpressionStatementImpl({
name: `target.${name}.push`,
parameters: [
callClone
]
}).writerFunction
]
).writerFunction
];

return [];
}

#getStatementsForTrivia(
name: string
): readonly stringWriterOrStatementImpl[]
{
return [
new BlockStatementImpl(
`if (Array.isArray(source.${name}))`,
Expand Down Expand Up @@ -334,7 +369,7 @@ export default class CopyFieldsStatements extends GetterFilter
}

#getOriginalField(
propertyName: string
propertyName: string,
): PropertySignatureImpl
{
return getTypeAugmentedStructure(
Expand Down
11 changes: 6 additions & 5 deletions stage_3_generation/pseudoStatements/CallExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,24 @@ import type {
} from "ts-morph";

import type {
TypeStructures,
stringOrWriterFunction
} from "#stage_two/snapshot/source/exports.js";
import StatementBase from "./StatementBase.js";

export interface CallExpressionStatementContext {
name: string;
readonly typeParameters: string[];
readonly parameters: stringOrWriterFunction[];
readonly typeParameters: TypeStructures[];
readonly parameters: (stringOrWriterFunction | CallExpressionStatementImpl)[];
}

export default
class CallExpressionStatementImpl extends StatementBase
implements CallExpressionStatementContext
{
name: string;
readonly typeParameters: string[] = [];
readonly parameters: stringOrWriterFunction[] = [];
readonly typeParameters: TypeStructures[] = [];
readonly parameters: (stringOrWriterFunction | CallExpressionStatementImpl)[] = [];

constructor(
context: Pick<CallExpressionStatementContext, "name"> & Partial<CallExpressionStatementContext>
Expand All @@ -38,7 +39,7 @@ implements CallExpressionStatementContext
writer.write(this.name);
if (this.typeParameters.length) {
this.pairedWrite(writer, "<", ">", () => {
this.writeArray(writer, this.typeParameters);
this.writeArray(writer, this.typeParameters.map(typeParam => typeParam.writerFunction));
})
}

Expand Down

0 comments on commit b23b149

Please sign in to comment.