diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1e16d2cbf0d..c7513deba56 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23503,6 +23503,15 @@ namespace ts { } function getTypeReferenceSerializationKind(typeName: EntityName, location?: Node): TypeReferenceSerializationKind { + // ensure both `typeName` and `location` are parse tree nodes. + typeName = getParseTreeNode(typeName, isEntityName); + if (!typeName) return TypeReferenceSerializationKind.Unknown; + + if (location) { + location = getParseTreeNode(location); + if (!location) return TypeReferenceSerializationKind.Unknown; + } + // Resolve the symbol as a value to ensure the type can be reached at runtime during emit. const valueSymbol = resolveEntityName(typeName, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, location); diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 71a3c7dcb7a..692c758bc75 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -1947,7 +1947,7 @@ namespace ts { const name = getMutableClone(node); name.flags &= ~NodeFlags.Synthesized; name.original = undefined; - name.parent = currentScope; + name.parent = getParseTreeNode(currentScope); // ensure the parent is set to a parse tree node. if (useFallback) { return createLogicalAnd( createStrictInequality( diff --git a/src/harness/unittests/customTransforms.ts b/src/harness/unittests/customTransforms.ts index 4b05ebb9ea7..f47bdad5d58 100644 --- a/src/harness/unittests/customTransforms.ts +++ b/src/harness/unittests/customTransforms.ts @@ -3,12 +3,11 @@ namespace ts { describe("customTransforms", () => { - function emitsCorrectly(name: string, sources: { file: string, text: string }[], customTransformers: CustomTransformers) { + function emitsCorrectly(name: string, sources: { file: string, text: string }[], customTransformers: CustomTransformers, options: CompilerOptions = {}) { it(name, () => { const roots = sources.map(source => createSourceFile(source.file, source.text, ScriptTarget.ES2015)); const fileMap = arrayToMap(roots, file => file.fileName); const outputs = createMap(); - const options: CompilerOptions = {}; const host: CompilerHost = { getSourceFile: (fileName) => fileMap.get(fileName), getDefaultLibFileName: () => "lib.d.ts", @@ -82,5 +81,25 @@ namespace ts { emitsCorrectly("before", sources, { before: [before] }); emitsCorrectly("after", sources, { after: [after] }); emitsCorrectly("both", sources, { before: [before], after: [after] }); + + emitsCorrectly("before+decorators", [{ + file: "source.ts", + text: ` + declare const dec: any; + class B {} + @dec export class C { constructor(b: B) { } } + 'change' + ` + }], {before: [ + context => node => visitNode(node, function visitor(node: Node): Node { + if (isStringLiteral(node) && node.text === "change") return createLiteral("changed"); + return visitEachChild(node, visitor, context); + }) + ]}, { + target: ScriptTarget.ES5, + module: ModuleKind.ES2015, + emitDecoratorMetadata: true, + experimentalDecorators: true + }); }); } \ No newline at end of file diff --git a/tests/baselines/reference/customTransforms/before+decorators.js b/tests/baselines/reference/customTransforms/before+decorators.js new file mode 100644 index 00000000000..ef705f0c9d8 --- /dev/null +++ b/tests/baselines/reference/customTransforms/before+decorators.js @@ -0,0 +1,26 @@ +// [source.js] +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +var B = /** @class */ (function () { + function B() { + } + return B; +}()); +var C = /** @class */ (function () { + function C(b) { + } + C = __decorate([ + dec, + __metadata("design:paramtypes", [B]) + ], C); + return C; +}()); +export { C }; +"changed";