Skip to content

Commit

Permalink
feat(HObject): add rest of parse rules to HObjects AOT mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Mararok committed Sep 29, 2024
1 parent dd32e11 commit 72a46fc
Show file tree
Hide file tree
Showing 45 changed files with 2,334 additions and 542 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
"prepublish": "yarn run build"
},
"peerDependencies": {
"@hexancore/common": "^0.16.0",
"@hexancore/common": "^0.16.1",
"@nestjs/common": "^10.3.9",
"@nestjs/config": "^3.0.0",
"@nestjs/core": "^10.3.9",
Expand Down Expand Up @@ -103,7 +103,7 @@
"tslib": "^2.6.3"
},
"devDependencies": {
"@hexancore/common": "^0.16.0",
"@hexancore/common": "0.16.1",
"@hexancore/mocker": "^1.1.2",
"@nestjs/cli": "^10.3.2",
"@nestjs/common": "^10.3.9",
Expand Down Expand Up @@ -131,7 +131,7 @@
"ts-jest": "^29.1.1",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "5.4.5"
"typescript": "5.6.2"
},
"bugs": {
"url": "https://github.com/hexancore/core/issues"
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/Test/TsTransformerTestHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,10 @@ export class TsTransformerTestHelper {
);
}

public createTransformerFactory(transformer: (sourceFile: ts.SourceFile, context: ts.TransformationContext,) => ts.SourceFile): ts.TransformerFactory<ts.SourceFile> {
public createTransformerFactory(transformer: ContextAwareCustomTransformer): ts.TransformerFactory<ts.SourceFile> {
return (context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => transformer(sourceFile, context);
}


public transformExistingAndReturnAsString(sourceFilePath: string, transformers: ts.TransformerFactory<ts.SourceFile>[]): string {
const sourceFile = this.createSourceFileFromExisting(sourceFilePath);
return this.transformAndReturnAsString(sourceFile, transformers);
Expand All @@ -57,6 +56,7 @@ export class TsTransformerTestHelper {
const transformResult = ts.transform(sourceFile, transformers, this.compilerOptions);

const transformedSourceFile = transformResult.transformed[0];

const printer = ts.createPrinter();

const result = printer.printNode(
Expand Down
1 change: 1 addition & 0 deletions src/Compiler/Transformer/Feature/FeatureTsTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export class FeatureTsTransformer {
for (const t of this.transformers) {
if (t.supports(featureSourceTransformContext.featureSourcePath, featureSourceTransformContext.feature)) {
const transformed = t.transform(source, featureSourceTransformContext);
TsTransfromerHelper.reportDiagnostics(featureSourceTransformContext.diagnostics);
return transformed;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import type { HObjectPropertyTsMeta } from "./HObjectPropertyTsMeta";

export class HObjectToConstructorTsFactory {
public create(properties: HObjectPropertyTsMeta[]): ts.ConstructorDeclaration {

const callSuper = ts.factory.createExpressionStatement(ts.factory.createCallExpression(ts.factory.createSuper(), undefined, undefined));

const propertiesSorted = [...properties.filter(p => !p.optional), ...properties.filter(p => p.optional)];
const constructorParameters = propertiesSorted.map(p => this.createParameter(p));
const constructorAssignments = propertiesSorted.map(p => this.createAssignment(p));

return ts.factory.createConstructorDeclaration(
[ts.factory.createModifier(ts.SyntaxKind.PublicKeyword)],
constructorParameters,
ts.factory.createBlock(constructorAssignments, true)
ts.factory.createBlock([callSuper, ...constructorAssignments], true)
);
}

Expand Down
141 changes: 127 additions & 14 deletions src/Compiler/Transformer/Feature/HObject/HObjectParseTsFactory.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,105 @@

import ts from "typescript";
import ts, { type Identifier } from "typescript";
import type { HObjectPropertyTsMeta } from "./HObjectPropertyTsMeta";

import type { ImportDeclarationWrapper } from "../../Helper/ImportDeclarationWrapper";
import { TsTransfromerHelper } from "../../TsTransformerHelper";
import { HObjectPropertyParseTsFactory } from "./HObjectPropertyParseTsFactory";
import { HObjectKind, type FeatureHObjectMeta } from "@/Util/Feature/Meta";

const HOBJECT_ANY_TYPE_MAP = {
[HObjectKind.Command]: {
anyTypeName: "AnyHCommand",
typeName: "HCommandType"
},
[HObjectKind.Query]: {
anyTypeName: "AnyHQuery",
typeName: "HQueryType"
},
[HObjectKind.Event]: {
anyTypeName: "AnyHEvent",
typeName: "HEventType"
},
[HObjectKind.Dto]: {
anyTypeName: "AnyDto",
typeName: "HDtoType"
},
[HObjectKind.ValueObject]: {
anyTypeName: "AnyValueObject",
typeName: "HValueObjectType"
},
[HObjectKind.Entity]: {
anyTypeName: "AnyEntity",
typeName: "HEntityType"
},
[HObjectKind.AggregateRoot]: {
anyTypeName: "AnyAggregateRoot",
typeName: "HAggregateRootType"
}
};

export class HObjectParseTsFactory {

private propertyTsFactory: HObjectPropertyParseTsFactory;

public constructor() {
this.propertyTsFactory = new HObjectPropertyParseTsFactory();
}

public create(hObjectClassName: string, properties: HObjectPropertyTsMeta[], hCommonImportDecl: ImportDeclarationWrapper): ts.MethodDeclaration {
//`public static parse<T extends AnyDto>(this: DtoType<T>, plain: unknown): R<T, PlainParseError>`
public create(meta: FeatureHObjectMeta, hObjectClassName: string, properties: HObjectPropertyTsMeta[], hCommonImportDecl: ImportDeclarationWrapper): ts.MethodDeclaration {
const returnType = ts.factory.createTypeReferenceNode(
hCommonImportDecl.getEntityName('R'), [ts.factory.createTypeReferenceNode(hObjectClassName, [])]
);

const typeInfo = HOBJECT_ANY_TYPE_MAP[meta.kind];

const parameters = [
ts.factory.createParameterDeclaration(
undefined,
undefined,
ts.factory.createIdentifier('this'),
undefined,
ts.factory.createTypeReferenceNode(typeInfo.typeName, [ts.factory.createTypeReferenceNode("T")])
),
ts.factory.createParameterDeclaration(undefined, undefined, 'plain', undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword))
];

const genericT = ts.factory.createTypeParameterDeclaration(
undefined,
ts.factory.createIdentifier("T"),
ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(typeInfo.anyTypeName), undefined)
);

return ts.factory.createMethodDeclaration(
[ts.factory.createModifier(ts.SyntaxKind.PublicKeyword), ts.factory.createModifier(ts.SyntaxKind.StaticKeyword)],
undefined, // *
'parse',
undefined, // '?'
undefined, // generic
[genericT],
parameters,
returnType,
ts.factory.createBlock(this.createBody(hObjectClassName, properties), true)
ts.factory.createBlock(this.createBody(hObjectClassName, properties, hCommonImportDecl), true)
);
}

private createBody(hObjectClassName: string, properties: HObjectPropertyTsMeta[]): ts.Statement[] {
private createBody(hObjectClassName: string, properties: HObjectPropertyTsMeta[], hCommonImportDecl: ImportDeclarationWrapper): ts.Statement[] {
properties = [...properties.filter(p => !p.optional), ...properties.filter(p => p.optional)];

const statements: ts.Statement[] = [
this.createCheckIsObject(hObjectClassName),
this.createCheckIsObject(hObjectClassName, hCommonImportDecl),
this.createPlainObjVarDeclaration(hObjectClassName),
this.createIssuesVarDeclaration(),
];

const propNames: string[] = [];
for (const p of properties) {
statements.push(...this.propertyTsFactory.create(p));
statements.push(...this.propertyTsFactory.create(p, hCommonImportDecl));
propNames.push(p.name);
}

statements.push(this.createCheckAnyIssues(hObjectClassName, hCommonImportDecl));
statements.push(this.createReturnNew(hObjectClassName, hCommonImportDecl, propNames));

return statements;
}

Expand All @@ -57,7 +110,7 @@ export class HObjectParseTsFactory {
}
`
*/
private createCheckIsObject(hObjectClassName: string): ts.Statement {
private createCheckIsObject(hObjectClassName: string, hCommonImportDecl: ImportDeclarationWrapper): ts.Statement {
// `typeof plain !== 'object'`
const condtionExpression = ts.factory.createBinaryExpression(
ts.factory.createTypeOfExpression(ts.factory.createIdentifier('plain')),
Expand All @@ -69,15 +122,12 @@ export class HObjectParseTsFactory {
ts.factory.createReturnStatement(
ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(
ts.factory.createIdentifier('PlainParseHelper'),
hCommonImportDecl.get('PlainParseHelper'),
'HObjectIsNotObjectParseErr'
),
undefined,
[
ts.factory.createAsExpression(
ts.factory.createIdentifier(hObjectClassName),
ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
),
this.createAsAny(hObjectClassName),
ts.factory.createIdentifier('plain')
]
)
Expand Down Expand Up @@ -109,4 +159,67 @@ export class HObjectParseTsFactory {
return TsTransfromerHelper.createConstStatement("issues", type, initializer);

}

private createCheckAnyIssues(hObjectClassName: string, hCommonImportDecl: ImportDeclarationWrapper): ts.Statement {
return ts.factory.createIfStatement(
ts.factory.createBinaryExpression(
ts.factory.createPropertyAccessExpression(
this.issuesVarIdentifier(),
ts.factory.createIdentifier('length')
),
ts.factory.createToken(ts.SyntaxKind.GreaterThanToken),
ts.factory.createNumericLiteral('0')
),
ts.factory.createBlock(
[
ts.factory.createReturnStatement(
ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(
hCommonImportDecl.get('PlainParseHelper'),
ts.factory.createIdentifier('HObjectParseErr')
),
undefined,
[
this.createAsAny(hObjectClassName),
this.issuesVarIdentifier(),
]
)
)
],
true
),
undefined
);
}

private createReturnNew(hObjectClassName: string, hCommonImportDecl: ImportDeclarationWrapper, propNames: string[]) {
return ts.factory.createReturnStatement(
ts.factory.createAsExpression(
ts.factory.createCallExpression(
hCommonImportDecl.get("OK"),
undefined,
[
ts.factory.createNewExpression(
hCommonImportDecl.get(hObjectClassName),
undefined,
propNames.map((name) => this.createAsAny(name))
)
]
),
ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
)
);
}

private issuesVarIdentifier(): ts.Identifier {
return ts.factory.createIdentifier("issues");
}

private createAsAny(name: string): ts.Expression {
return ts.factory.createAsExpression(
ts.factory.createIdentifier(name),
ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
);
}

}
Loading

0 comments on commit 72a46fc

Please sign in to comment.