Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion cli/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,10 @@ export abstract class Transform {
/** Called when parsing is complete, before a program is instantiated from the AST. */
afterParse?(parser: Parser): void | Promise<void>;

/** Called after the program is instantiated. */
/**
* Called after the program is instantiated and before compilation-time validation runs.
* This is the last hook where transforms can rewrite preserved AST-only syntax before it is rejected.
*/
afterInitialize?(program: Program): void | Promise<void>;

/** Called when compilation is complete, before the module is being validated. */
Expand Down
2 changes: 1 addition & 1 deletion cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ export async function main(argv, options) {
stats.initializeTime += stats.end(begin);
}

// Call afterInitialize transform hook
// Call afterInitialize transform hook, the last AST rewrite point before compilation-time validation.
{
let error = await applyTransform("afterInitialize", program);
if (error) return prepareResult(error);
Expand Down
4 changes: 4 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export default defineConfig([

// FIXME: Tagged template literal tests with invalid escapes
"tests/compiler/templateliteral.ts",

// Decorators on `this` are not allowed typically in TypeScript, but this
// fixture exercises that AS-only syntax and is validated by transform tests.
"tests/transform/parameter-decorators.ts",
]),

js.configs.recommended,
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@
"test:browser": "node --enable-source-maps tests/browser",
"test:asconfig": "cd tests/asconfig && npm run test",
"test:transform": "npm run test:transform:esm && npm run test:transform:cjs",
"test:transform:esm": "node bin/asc tests/compiler/empty --transform ./tests/transform/index.js --noEmit && node bin/asc tests/compiler/empty --transform ./tests/transform/simple.js --noEmit",
"test:transform:cjs": "node bin/asc tests/compiler/empty --transform ./tests/transform/cjs/index.js --noEmit && node bin/asc tests/compiler/empty --transform ./tests/transform/cjs/simple.js --noEmit",
"test:transform:esm": "node bin/asc tests/compiler/empty --transform ./tests/transform/index.js --noEmit && node bin/asc tests/compiler/empty --transform ./tests/transform/simple.js --noEmit && node bin/asc tests/transform/parameter-decorators.ts --transform ./tests/transform/remove-parameter-decorators.js --noEmit",
"test:transform:cjs": "node bin/asc tests/compiler/empty --transform ./tests/transform/cjs/index.js --noEmit && node bin/asc tests/compiler/empty --transform ./tests/transform/cjs/simple.js --noEmit && node bin/asc tests/transform/parameter-decorators.ts --transform ./tests/transform/cjs/remove-parameter-decorators.js --noEmit",
"test:cli": "node tests/cli/options.js",
"asbuild": "npm run asbuild:debug && npm run asbuild:release",
"asbuild:debug": "node bin/asc --config src/asconfig.json --target debug",
Expand Down
12 changes: 10 additions & 2 deletions src/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,12 @@ export abstract class Node {
name: IdentifierExpression,
type: TypeNode,
initializer: Expression | null,
range: Range
range: Range,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i prefer to put range at the end like the other ast.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree

decorators: DecoratorNode[] | null = null
): ParameterNode {
Comment on lines -184 to 186
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think range should be always at end.

  decorators: DecoratorNode[] | null,
  range: Range,
): ParameterNode {

And yes, this will lead to more refactorings

return new ParameterNode(parameterKind, name, type, initializer, range);
let parameter = new ParameterNode(parameterKind, name, type, initializer, range);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar here.

Suggested change
let parameter = new ParameterNode(parameterKind, name, type, initializer, range);
let parameter = new ParameterNode(parameterKind, name, type, initializer, decorators, range);

parameter.decorators = decorators;
return parameter;
}

// special
Expand Down Expand Up @@ -926,6 +929,9 @@ export class FunctionTypeNode extends TypeNode {
) {
super(NodeKind.FunctionType, isNullable, range);
}

/** Decorators on an explicit `this` parameter, if any, preserved for transforms. */
explicitThisDecorators: DecoratorNode[] | null = null;
}

/** Represents a type parameter. */
Expand Down Expand Up @@ -971,6 +977,8 @@ export class ParameterNode extends Node {
super(NodeKind.Parameter, range);
}

/** Decorators, if any, preserved so transforms can rewrite them before validation. */
decorators: DecoratorNode[] | null = null;
/** Implicit field declaration, if applicable. */
implicitFieldDeclaration: FieldDeclaration | null = null;
/** Common flags indicating specific traits. */
Expand Down
2 changes: 2 additions & 0 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,8 @@ export class Compiler extends DiagnosticEmitter {

// initialize lookup maps, built-ins, imports, exports, etc.
this.program.initialize();
// Reject any parameter decorators that transforms left on the AST.
this.program.validateParameterDecorators();


// Binaryen treats all function references as being leaked to the outside world when
Expand Down
31 changes: 31 additions & 0 deletions src/extra/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ export class ASTBuilder {
sb.push(isNullable ? "((" : "(");
let explicitThisType = node.explicitThisType;
if (explicitThisType) {
this.serializeParameterDecorators(node.explicitThisDecorators);
sb.push("this: ");
this.visitTypeNode(explicitThisType);
}
Expand Down Expand Up @@ -1153,6 +1154,7 @@ export class ASTBuilder {
let numParameters = parameters.length;
let explicitThisType = signature.explicitThisType;
if (explicitThisType) {
this.serializeParameterDecorators(signature.explicitThisDecorators);
sb.push("this: ");
this.visitTypeNode(explicitThisType);
}
Expand Down Expand Up @@ -1563,9 +1565,38 @@ export class ASTBuilder {
indent(sb, this.indentLevel);
}

serializeParameterDecorators(decorators: DecoratorNode[] | null): void {
if (decorators) {
for (let i = 0, k = decorators.length; i < k; ++i) {
this.visitParameterDecorator(decorators[i]);
}
}
}

private visitParameterDecorator(node: DecoratorNode): void {
let sb = this.sb;
sb.push("@");
this.visitNode(node.name);
let args = node.args;
if (args) {
sb.push("(");
let numArgs = args.length;
if (numArgs) {
this.visitNode(args[0]);
for (let i = 1; i < numArgs; ++i) {
sb.push(", ");
this.visitNode(args[i]);
}
}
sb.push(")");
}
sb.push(" ");
}

serializeParameter(node: ParameterNode): void {
let sb = this.sb;
let kind = node.parameterKind;
this.serializeParameterDecorators(node.decorators);
let implicitFieldDeclaration = node.implicitFieldDeclaration;
if (implicitFieldDeclaration) {
this.serializeAccessModifiers(implicitFieldDeclaration);
Expand Down
2 changes: 1 addition & 1 deletion src/index-wasm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ export function getDependee(program: Program, file: string): string | null {

// Compiler

/** Initializes the program pre-emptively for transform hooks. */
/** Initializes the program pre-emptively so `afterInitialize` transforms can rewrite the AST before compilation. */
export function initializeProgram(program: Program): void {
program.initialize();
}
Expand Down
Loading