Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
15564e9
Parse and preserve parameter decorators
jtenner Mar 27, 2026
75d7c6a
Reject surviving parameter decorators after transforms
jtenner Mar 27, 2026
65527dd
Cover transform-time removal of parameter decorators
jtenner Mar 27, 2026
32f69b2
Clarify transform-only parameter decorator contract
jtenner Mar 27, 2026
21f724f
Document transform hook timing for parameter decorators
jtenner Mar 27, 2026
c474861
Fix lint for parameter decorator fixtures
jtenner Mar 27, 2026
ec618c9
chore: ignore AS parameter decorator fixture in eslint
jtenner Apr 5, 2026
4505b5c
Fix parameter decorator review feedback
jtenner Apr 8, 2026
c267d6e
chore: remove legacy eslint config
jtenner Apr 11, 2026
6f75b5e
refactor: consolidate parameter decorator validation
jtenner Apr 13, 2026
53dc57c
chore: remove unused AST imports
jtenner Apr 13, 2026
bcbce9a
style: move parameter range to the end
jtenner Apr 13, 2026
ba37601
style: include explicit this decorators in function types
jtenner Apr 13, 2026
b1fa8aa
refactor: reuse decorator serialization for parameters
jtenner Apr 13, 2026
2a7f4fb
refactor: rename tryParseParameterDecorators helper
jtenner Apr 14, 2026
e401a30
Refactor parameter decorator parsing
jtenner Apr 15, 2026
d1ce4c7
Update NOTICE
PaperPrototype Apr 15, 2026
2ca7c6a
Update NOTICE
PaperPrototype Apr 15, 2026
93f7b31
undo unecessary comment changes
PaperPrototype Apr 15, 2026
9757397
Undo changes to index-wasm.ts
PaperPrototype Apr 16, 2026
2177f77
removed currentSourceStatementDepth and currentSourceStatementHasPara…
PaperPrototype Apr 16, 2026
9b2dc22
Remove NodeWalker and ParameterDecoratorValidator and validateParamet…
PaperPrototype Apr 16, 2026
9f9f3bd
Remove NodeWalker from ast.ts
PaperPrototype Apr 16, 2026
6743001
remove validateParameterDecorators from compiler.ts
PaperPrototype Apr 16, 2026
efe656b
Update compiler.ts
PaperPrototype Apr 16, 2026
3e8b163
Update compiler.ts
PaperPrototype Apr 16, 2026
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
1 change: 1 addition & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ under the licensing terms detailed in LICENSE:
* Mopsgamer <79159094+Mopsgamer@users.noreply.github.com>
* EDM115 <github@edm115.dev>
* Weixie Cui <cuiweixie@gmail.com>
* Abdiel Lopez <a.paperprototype@gmail.com>

Portions of this software are derived from third-party works licensed under
the following terms:
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
13 changes: 10 additions & 3 deletions src/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,11 @@ export abstract class Node {
parameters: ParameterNode[],
returnType: TypeNode,
explicitThisType: NamedTypeNode | null,
explicitThisDecorators: DecoratorNode[] | null,
isNullable: bool,
range: Range
): FunctionTypeNode {
return new FunctionTypeNode(parameters, returnType, explicitThisType, isNullable, range);
return new FunctionTypeNode(parameters, returnType, explicitThisType, explicitThisDecorators, isNullable, range);
}

static createOmittedType(
Expand All @@ -181,9 +182,10 @@ export abstract class Node {
name: IdentifierExpression,
type: TypeNode,
initializer: Expression | null,
decorators: DecoratorNode[] | null,
range: Range
): ParameterNode {
return new ParameterNode(parameterKind, name, type, initializer, range);
return new ParameterNode(parameterKind, name, type, initializer, decorators, range);
}

// special
Expand Down Expand Up @@ -919,6 +921,8 @@ export class FunctionTypeNode extends TypeNode {
public returnType: TypeNode,
/** Explicitly provided this type, if any. */
public explicitThisType: NamedTypeNode | null, // can't be a function
/** Decorators on an explicit `this` parameter, if any. Preserved as transform-only syntax. */
public explicitThisDecorators: DecoratorNode[] | null,
/** Whether nullable or not. */
isNullable: bool,
/** Source range. */
Expand Down Expand Up @@ -965,12 +969,13 @@ export class ParameterNode extends Node {
public type: TypeNode,
/** Initializer expression, if any. */
public initializer: Expression | null,
/** Decorators, if any. Preserved as transform-only syntax so transforms can rewrite or remove them before validation. */
public decorators: DecoratorNode[] | null,
/** Source range. */
range: Range
) {
super(NodeKind.Parameter, range);
}

/** Implicit field declaration, if applicable. */
implicitFieldDeclaration: FieldDeclaration | null = null;
/** Common flags indicating specific traits. */
Expand Down Expand Up @@ -1664,6 +1669,8 @@ export class Source extends Node {
debugInfoIndex: i32 = -1;
/** Re-exported sources. */
exportPaths: string[] | null = null;
/** Source-level statements known to contain preserved parameter decorators, revisited after transforms for validation. */
parameterDecoratorStatements: Statement[] | null = null;

/** Checks if this source represents native code. */
get isNative(): bool {
Expand Down
20 changes: 17 additions & 3 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 @@ -1541,7 +1543,7 @@ export class ASTBuilder {

// other

serializeDecorator(node: DecoratorNode): void {
serializeDecorator(node: DecoratorNode, isInline: bool = false): void {
let sb = this.sb;
sb.push("@");
this.visitNode(node.name);
Expand All @@ -1556,16 +1558,28 @@ export class ASTBuilder {
this.visitNode(args[i]);
}
}
sb.push(")\n");
sb.push(")");
}
if (isInline) {
sb.push(" ");
} else {
sb.push("\n");
indent(sb, this.indentLevel);
}
}

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

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
Loading