Fix CJS local binding emit for ES decorators (#53725)

This commit is contained in:
Ron Buckton 2023-04-10 17:05:38 -04:00 committed by GitHub
parent 926c6f1ddb
commit 3e76fb5ca2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 268 additions and 5 deletions

View File

@ -46,6 +46,7 @@ import {
getAllDecoratorsOfClassElement,
getCommentRange,
getEffectiveBaseTypeNode,
getEmitScriptTarget,
getFirstConstructorWithBody,
getHeritageClause,
getNonAssignmentOperatorForCompoundAssignment,
@ -279,6 +280,9 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
hoistVariableDeclaration,
} = context;
const compilerOptions = context.getCompilerOptions();
const languageVersion = getEmitScriptTarget(compilerOptions);
let top: LexicalEnvironmentStackEntry | undefined;
let classInfo: ClassInfo | undefined;
let classThis: Identifier | undefined;
@ -1003,7 +1007,12 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
Debug.assertIsDefined(node.name, "A class declaration that is not a default export must have a name.");
const iife = transformClassLike(node, factory.createStringLiteralFromNode(node.name));
const modifiers = visitNodes(node.modifiers, modifierVisitor, isModifier);
const varDecl = factory.createVariableDeclaration(node.name, /*exclamationToken*/ undefined, /*type*/ undefined, iife);
// When we transform to ES5/3 this will be moved inside an IIFE and should reference the name
// without any block-scoped variable collision handling
const declName = languageVersion <= ScriptTarget.ES2015 ?
factory.getInternalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true) :
factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true);
const varDecl = factory.createVariableDeclaration(declName, /*exclamationToken*/ undefined, /*type*/ undefined, iife);
const varDecls = factory.createVariableDeclarationList([varDecl], NodeFlags.Let);
const statement = factory.createVariableStatement(modifiers, varDecls);
setOriginalNode(statement, node);

View File

@ -208,7 +208,7 @@ let C = (() => {
Object.defineProperty(exports, "__esModule", { value: true });
exports.D = void 0;
/*34*/
exports.D = (() => {
let D = exports.D = (() => {
let _classDecorators = [dec, dec];
let _classDescriptor;
let _classExtraInitializers = [];
@ -243,7 +243,7 @@ exports.default = (() => {
Object.defineProperty(exports, "__esModule", { value: true });
exports.F = void 0;
/*40*/
exports.F = (() => {
let F = exports.F = (() => {
let _classDecorators = [dec, dec];
let _classDescriptor;
let _classExtraInitializers = [];

View File

@ -205,7 +205,7 @@ let C = (() => {
Object.defineProperty(exports, "__esModule", { value: true });
exports.D = void 0;
/*34*/
exports.D = (() => {
let D = exports.D = (() => {
let _classDecorators = [dec, dec];
let _classDescriptor;
let _classExtraInitializers = [];
@ -238,7 +238,7 @@ exports.default = (() => {
Object.defineProperty(exports, "__esModule", { value: true });
exports.F = void 0;
/*40*/
exports.F = (() => {
let F = exports.F = (() => {
let _classDecorators = [dec, dec];
let _classDescriptor;
let _classExtraInitializers = [];

View File

@ -0,0 +1,71 @@
//// [esDecorators-classDeclaration-commonjs-classNamespaceMerge.ts]
declare var deco: any;
@deco
export class Example {
static foo() {}
}
export namespace Example {
export const x = 1;
}
Example.foo();
//// [esDecorators-classDeclaration-commonjs-classNamespaceMerge.js]
"use strict";
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.push(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.push(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Example = void 0;
let Example = exports.Example = (() => {
let _classDecorators = [deco];
let _classDescriptor;
let _classExtraInitializers = [];
let _classThis;
var Example = class {
static {
__esDecorate(null, _classDescriptor = { value: this }, _classDecorators, { kind: "class", name: this.name }, null, _classExtraInitializers);
Example = _classThis = _classDescriptor.value;
__runInitializers(_classThis, _classExtraInitializers);
}
static foo() { }
};
return Example = _classThis;
})();
(function (Example) {
Example.x = 1;
})(Example = exports.Example || (exports.Example = {}));
Example.foo();

View File

@ -0,0 +1,26 @@
=== tests/cases/conformance/esDecorators/classDeclaration/esDecorators-classDeclaration-commonjs-classNamespaceMerge.ts ===
declare var deco: any;
>deco : Symbol(deco, Decl(esDecorators-classDeclaration-commonjs-classNamespaceMerge.ts, 0, 11))
@deco
>deco : Symbol(deco, Decl(esDecorators-classDeclaration-commonjs-classNamespaceMerge.ts, 0, 11))
export class Example {
>Example : Symbol(Example, Decl(esDecorators-classDeclaration-commonjs-classNamespaceMerge.ts, 0, 22), Decl(esDecorators-classDeclaration-commonjs-classNamespaceMerge.ts, 5, 1))
static foo() {}
>foo : Symbol(Example.foo, Decl(esDecorators-classDeclaration-commonjs-classNamespaceMerge.ts, 3, 22))
}
export namespace Example {
>Example : Symbol(Example, Decl(esDecorators-classDeclaration-commonjs-classNamespaceMerge.ts, 0, 22), Decl(esDecorators-classDeclaration-commonjs-classNamespaceMerge.ts, 5, 1))
export const x = 1;
>x : Symbol(x, Decl(esDecorators-classDeclaration-commonjs-classNamespaceMerge.ts, 8, 16))
}
Example.foo();
>Example.foo : Symbol(Example.foo, Decl(esDecorators-classDeclaration-commonjs-classNamespaceMerge.ts, 3, 22))
>Example : Symbol(Example, Decl(esDecorators-classDeclaration-commonjs-classNamespaceMerge.ts, 0, 22), Decl(esDecorators-classDeclaration-commonjs-classNamespaceMerge.ts, 5, 1))
>foo : Symbol(Example.foo, Decl(esDecorators-classDeclaration-commonjs-classNamespaceMerge.ts, 3, 22))

View File

@ -0,0 +1,28 @@
=== tests/cases/conformance/esDecorators/classDeclaration/esDecorators-classDeclaration-commonjs-classNamespaceMerge.ts ===
declare var deco: any;
>deco : any
@deco
>deco : any
export class Example {
>Example : Example
static foo() {}
>foo : () => void
}
export namespace Example {
>Example : typeof Example
export const x = 1;
>x : 1
>1 : 1
}
Example.foo();
>Example.foo() : void
>Example.foo : () => void
>Example : typeof Example
>foo : () => void

View File

@ -0,0 +1,64 @@
//// [esDecorators-classDeclaration-commonjs.ts]
declare var deco: any;
@deco
export class Example {
static foo() {}
}
Example.foo();
//// [esDecorators-classDeclaration-commonjs.js]
"use strict";
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.push(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.push(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Example = void 0;
let Example = exports.Example = (() => {
let _classDecorators = [deco];
let _classDescriptor;
let _classExtraInitializers = [];
let _classThis;
var Example = class {
static {
__esDecorate(null, _classDescriptor = { value: this }, _classDecorators, { kind: "class", name: this.name }, null, _classExtraInitializers);
Example = _classThis = _classDescriptor.value;
__runInitializers(_classThis, _classExtraInitializers);
}
static foo() { }
};
return Example = _classThis;
})();
Example.foo();

View File

@ -0,0 +1,19 @@
=== tests/cases/conformance/esDecorators/classDeclaration/esDecorators-classDeclaration-commonjs.ts ===
declare var deco: any;
>deco : Symbol(deco, Decl(esDecorators-classDeclaration-commonjs.ts, 0, 11))
@deco
>deco : Symbol(deco, Decl(esDecorators-classDeclaration-commonjs.ts, 0, 11))
export class Example {
>Example : Symbol(Example, Decl(esDecorators-classDeclaration-commonjs.ts, 0, 22))
static foo() {}
>foo : Symbol(Example.foo, Decl(esDecorators-classDeclaration-commonjs.ts, 3, 22))
}
Example.foo();
>Example.foo : Symbol(Example.foo, Decl(esDecorators-classDeclaration-commonjs.ts, 3, 22))
>Example : Symbol(Example, Decl(esDecorators-classDeclaration-commonjs.ts, 0, 22))
>foo : Symbol(Example.foo, Decl(esDecorators-classDeclaration-commonjs.ts, 3, 22))

View File

@ -0,0 +1,20 @@
=== tests/cases/conformance/esDecorators/classDeclaration/esDecorators-classDeclaration-commonjs.ts ===
declare var deco: any;
>deco : any
@deco
>deco : any
export class Example {
>Example : Example
static foo() {}
>foo : () => void
}
Example.foo();
>Example.foo() : void
>Example.foo : () => void
>Example : typeof Example
>foo : () => void

View File

@ -0,0 +1,15 @@
// @target: es2022
// @module: commonjs
declare var deco: any;
@deco
export class Example {
static foo() {}
}
export namespace Example {
export const x = 1;
}
Example.foo();

View File

@ -0,0 +1,11 @@
// @target: es2022
// @module: commonjs
declare var deco: any;
@deco
export class Example {
static foo() {}
}
Example.foo();