Skip to content

Commit 3cfb531

Browse files
authored
Port checks for tslib helpers (#3777)
1 parent 6eb79f4 commit 3cfb531

92 files changed

Lines changed: 1788 additions & 1340 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

internal/ast/utilities.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4505,3 +4505,37 @@ func IsSuperProperty(node *Node) bool {
45054505
return (IsPropertyAccessExpression(node) || IsElementAccessExpression(node)) &&
45064506
node.Expression().Kind == KindSuperKeyword
45074507
}
4508+
4509+
// Indicates whether a node is a potential source of an assigned name for a class, function, or arrow function.
4510+
func IsNamedEvaluationSource(node *Node) bool {
4511+
switch node.Kind {
4512+
case KindPropertyAssignment:
4513+
return !IsProtoSetter(node.AsPropertyAssignment().Name())
4514+
case KindShorthandPropertyAssignment:
4515+
return node.AsShorthandPropertyAssignment().ObjectAssignmentInitializer != nil
4516+
case KindVariableDeclaration:
4517+
return IsIdentifier(node.AsVariableDeclaration().Name()) && node.Initializer() != nil
4518+
case KindParameter:
4519+
return IsIdentifier(node.AsParameterDeclaration().Name()) && node.Initializer() != nil && node.AsParameterDeclaration().DotDotDotToken == nil
4520+
case KindBindingElement:
4521+
return IsIdentifier(node.AsBindingElement().Name()) && node.Initializer() != nil && node.AsBindingElement().DotDotDotToken == nil
4522+
case KindPropertyDeclaration:
4523+
return node.Initializer() != nil
4524+
case KindBinaryExpression:
4525+
switch node.AsBinaryExpression().OperatorToken.Kind {
4526+
case KindEqualsToken, KindAmpersandAmpersandEqualsToken, KindBarBarEqualsToken, KindQuestionQuestionEqualsToken:
4527+
return IsIdentifier(node.AsBinaryExpression().Left)
4528+
}
4529+
case KindExportAssignment:
4530+
return true
4531+
}
4532+
return false
4533+
}
4534+
4535+
// Indicates whether a property name is the special `__proto__` property.
4536+
// Per the ECMA-262 spec, this only matters for property assignments whose name is
4537+
// the Identifier `__proto__`, or the string literal `"__proto__"`, but not for
4538+
// computed property names.
4539+
func IsProtoSetter(node *Node) bool {
4540+
return (IsIdentifier(node) || IsStringLiteral(node)) && node.Text() == "__proto__"
4541+
}

internal/checker/checker.go

Lines changed: 269 additions & 5 deletions
Large diffs are not rendered by default.

internal/checker/types.go

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,46 @@ const (
111111
SymbolFormatFlagsDoNotIncludeSymbolChain SymbolFormatFlags = 1 << 5
112112
)
113113

114+
type ExternalEmitHelpers uint32
115+
116+
const (
117+
ExternalEmitHelpersRest ExternalEmitHelpers = 1 << iota // __rest (used by ESNext object rest transformation)
118+
ExternalEmitHelpersDecorate // __decorate (used by TypeScript decorators transformation)
119+
ExternalEmitHelpersMetadata // __metadata (used by TypeScript decorators transformation)
120+
ExternalEmitHelpersParam // __param (used by TypeScript decorators transformation)
121+
ExternalEmitHelpersAwaiter // __awaiter (used by ES2017 async functions transformation)
122+
ExternalEmitHelpersAwait // __await (used by ES2017 async generator transformation)
123+
ExternalEmitHelpersAsyncGenerator // __asyncGenerator (used by ES2017 async generator transformation)
124+
ExternalEmitHelpersAsyncDelegator // __asyncDelegator (used by ES2017 async generator yield* transformation)
125+
ExternalEmitHelpersAsyncValues // __asyncValues (used by ES2017 for..await..of transformation)
126+
ExternalEmitHelpersExportStar // __exportStar (used by CommonJS/AMD/UMD module transformation)
127+
ExternalEmitHelpersImportStar // __importStar (used by CommonJS/AMD/UMD module transformation)
128+
ExternalEmitHelpersImportDefault // __importDefault (used by CommonJS/AMD/UMD module transformation)
129+
ExternalEmitHelpersMakeTemplateObject // __makeTemplateObject (used for constructing template string array objects)
130+
ExternalEmitHelpersClassPrivateFieldGet // __classPrivateFieldGet (used by the class private field transformation)
131+
ExternalEmitHelpersClassPrivateFieldSet // __classPrivateFieldSet (used by the class private field transformation)
132+
ExternalEmitHelpersClassPrivateFieldIn // __classPrivateFieldIn (used by the class private field transformation)
133+
ExternalEmitHelpersSetFunctionName // __setFunctionName (used by class fields and ECMAScript decorators)
134+
ExternalEmitHelpersPropKey // __propKey (used by class fields and ECMAScript decorators)
135+
ExternalEmitHelpersAddDisposableResourceAndDisposeResources // __addDisposableResource and __disposeResources (used by ESNext transformations)
136+
ExternalEmitHelpersRewriteRelativeImportExtension // __rewriteRelativeImportExtension (used by --rewriteRelativeImportExtensions)
137+
ExternalEmitHelpersESDecorateAndRunInitializers = ExternalEmitHelpersDecorate // __esDecorate and __runInitializers (used by ECMAScript decorators transformation)
138+
139+
ExternalEmitHelpersFirstEmitHelper = ExternalEmitHelpersRest
140+
ExternalEmitHelpersLastEmitHelper = ExternalEmitHelpersRewriteRelativeImportExtension
141+
142+
// Helpers included by ES2017 for..await..of
143+
ExternalEmitHelpersForAwaitOfIncludes = ExternalEmitHelpersAsyncValues
144+
145+
// Helpers included by ES2017 async generators
146+
ExternalEmitHelpersAsyncGeneratorIncludes = ExternalEmitHelpersAwait | ExternalEmitHelpersAsyncGenerator
147+
148+
// Helpers included by yield* in ES2017 async generators
149+
ExternalEmitHelpersAsyncDelegatorIncludes = ExternalEmitHelpersAwait | ExternalEmitHelpersAsyncDelegator | ExternalEmitHelpersAsyncValues
150+
)
151+
152+
const externalHelpersModuleNameText = "tslib"
153+
114154
// Ids
115155

116156
type TypeId uint32
@@ -346,15 +386,17 @@ type AssertionLinks struct {
346386
// SourceFile links
347387

348388
type SourceFileLinks struct {
349-
typeChecked bool
350-
unusedChecked bool
351-
deferredNodes collections.OrderedSet[*ast.Node]
352-
identifierCheckNodes []*ast.Node
353-
localJsxNamespace string
354-
localJsxFragmentNamespace string
355-
localJsxFactory *ast.EntityName
356-
localJsxFragmentFactory *ast.EntityName
357-
jsxFragmentType *Type
389+
typeChecked bool
390+
unusedChecked bool
391+
externalHelpersModule *ast.Symbol
392+
requestedExternalEmitHelpers ExternalEmitHelpers
393+
deferredNodes collections.OrderedSet[*ast.Node]
394+
identifierCheckNodes []*ast.Node
395+
localJsxNamespace string
396+
localJsxFragmentNamespace string
397+
localJsxFactory *ast.EntityName
398+
localJsxFragmentFactory *ast.EntityName
399+
jsxFragmentType *Type
358400
}
359401

360402
// Signature specific links

internal/checker/utilities.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,3 +1810,11 @@ func CreateModeMismatchDetails(program Program, file *ast.SourceFile) Diagnostic
18101810
Args: nil,
18111811
}
18121812
}
1813+
1814+
func walkUpOuterExpressions(node *ast.Node) *ast.Node {
1815+
parent := node.Parent
1816+
for parent != nil && ast.IsOuterExpression(parent, ast.OEKAll) {
1817+
parent = parent.Parent
1818+
}
1819+
return parent
1820+
}

internal/printer/helpers.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,8 +348,6 @@ var restHelper = &EmitHelper{
348348
};`,
349349
}
350350

351-
// !!! ES2017 Helpers
352-
353351
var awaiterHelper = &EmitHelper{
354352
Name: "typescript:awaiter",
355353
ImportName: "__awaiter",

internal/transformers/estransforms/namedevaluation.go

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,6 @@ func classHasDeclaredOrExplicitlyAssignedName(emitContext *printer.EmitContext,
5555
return node.Name() != nil || classHasExplicitlyAssignedName(emitContext, node)
5656
}
5757

58-
// Indicates whether a property name is the special `__proto__` property.
59-
// Per the ECMA-262 spec, this only matters for property assignments whose name is
60-
// the Identifier `__proto__`, or the string literal `"__proto__"`, but not for
61-
// computed property names.
62-
func isProtoSetter(node *ast.PropertyName) bool {
63-
return (ast.IsIdentifier(node) || ast.IsStringLiteral(node)) && node.Text() == "__proto__"
64-
}
65-
6658
type anonymousFunctionDefinition = ast.Node // ClassExpression | FunctionExpression | ArrowFunction
6759

6860
// Indicates whether an expression is an anonymous function definition.
@@ -92,39 +84,12 @@ func isAnonymousFunctionDefinition(emitContext *printer.EmitContext, node *ast.E
9284
return true
9385
}
9486

95-
// Indicates whether a node is a potential source of an assigned name for a class, function, or arrow function.
96-
func isNamedEvaluationSource(node *ast.Node) bool {
97-
switch node.Kind {
98-
case ast.KindPropertyAssignment:
99-
return !isProtoSetter(node.AsPropertyAssignment().Name())
100-
case ast.KindShorthandPropertyAssignment:
101-
return node.AsShorthandPropertyAssignment().ObjectAssignmentInitializer != nil
102-
case ast.KindVariableDeclaration:
103-
return ast.IsIdentifier(node.AsVariableDeclaration().Name()) && node.Initializer() != nil
104-
case ast.KindParameter:
105-
return ast.IsIdentifier(node.AsParameterDeclaration().Name()) && node.Initializer() != nil && node.AsParameterDeclaration().DotDotDotToken == nil
106-
case ast.KindBindingElement:
107-
return ast.IsIdentifier(node.AsBindingElement().Name()) && node.Initializer() != nil && node.AsBindingElement().DotDotDotToken == nil
108-
case ast.KindPropertyDeclaration:
109-
return node.Initializer() != nil
110-
case ast.KindBinaryExpression:
111-
switch node.AsBinaryExpression().OperatorToken.Kind {
112-
case ast.KindEqualsToken, ast.KindAmpersandAmpersandEqualsToken, ast.KindBarBarEqualsToken, ast.KindQuestionQuestionEqualsToken:
113-
return ast.IsIdentifier(node.AsBinaryExpression().Left)
114-
}
115-
break
116-
case ast.KindExportAssignment:
117-
return true
118-
}
119-
return false
120-
}
121-
12287
func isNamedEvaluation(emitContext *printer.EmitContext, node *ast.Node) bool {
12388
return isNamedEvaluationAnd(emitContext, node, nil)
12489
}
12590

12691
func isNamedEvaluationAnd(emitContext *printer.EmitContext, node *ast.Node, cb func(*anonymousFunctionDefinition) bool) bool {
127-
if !isNamedEvaluationSource(node) {
92+
if !ast.IsNamedEvaluationSource(node) {
12893
return false
12994
}
13095
switch node.Kind {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
error TS6504: File '/node_modules/tslib/tslib.js' is a JavaScript file. Did you mean to enable the 'allowJs' option?
2+
The file is in the program because:
3+
Root file specified for compilation
4+
/privateIdentifierPropertyAccessDestructuringAssignmentES6.ts(5,19): error TS2343: This syntax requires an imported helper named '__classPrivateFieldSet' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
5+
6+
7+
!!! error TS6504: File '/node_modules/tslib/tslib.js' is a JavaScript file. Did you mean to enable the 'allowJs' option?
8+
!!! error TS6504: The file is in the program because:
9+
!!! error TS6504: Root file specified for compilation
10+
==== /privateIdentifierPropertyAccessDestructuringAssignmentES6.ts (1 errors) ====
11+
class Example {
12+
#state = { value: 0 };
13+
14+
update(source: { value: { value: number } }) {
15+
({ value: this.#state } = source);
16+
~~~~~~~~~~~
17+
!!! error TS2343: This syntax requires an imported helper named '__classPrivateFieldSet' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
18+
}
19+
}
20+
21+
new Example().update({ value: { value: 1 } });
22+
23+
export {};
24+
25+
==== /node_modules/tslib/package.json (0 errors) ====
26+
{
27+
"name": "tslib",
28+
"main": "tslib.js",
29+
"typings": "tslib.d.ts"
30+
}
31+
32+
==== /node_modules/tslib/tslib.d.ts (0 errors) ====
33+
export declare function __classPrivateFieldGet(a: any, b: any, c: any, d: any): any;
34+
35+
==== /node_modules/tslib/tslib.js (0 errors) ====
36+
module.exports.__classPrivateFieldGet = function (receiver, state, kind, f) {
37+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
38+
};
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//// [tests/cases/compiler/privateIdentifierPropertyAccessDestructuringAssignmentES6.ts] ////
2+
3+
//// [privateIdentifierPropertyAccessDestructuringAssignmentES6.ts]
4+
class Example {
5+
#state = { value: 0 };
6+
7+
update(source: { value: { value: number } }) {
8+
({ value: this.#state } = source);
9+
}
10+
}
11+
12+
new Example().update({ value: { value: 1 } });
13+
14+
export {};
15+
16+
//// [package.json]
17+
{
18+
"name": "tslib",
19+
"main": "tslib.js",
20+
"typings": "tslib.d.ts"
21+
}
22+
23+
//// [tslib.d.ts]
24+
export declare function __classPrivateFieldGet(a: any, b: any, c: any, d: any): any;
25+
26+
//// [tslib.js]
27+
module.exports.__classPrivateFieldGet = function (receiver, state, kind, f) {
28+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
29+
};
30+
31+
//// [privateIdentifierPropertyAccessDestructuringAssignmentES6.js]
32+
"use strict";
33+
var _Example_state;
34+
Object.defineProperty(exports, "__esModule", { value: true });
35+
const tslib_1 = require("tslib");
36+
class Example {
37+
constructor() {
38+
_Example_state.set(this, { value: 0 });
39+
}
40+
update(source) {
41+
var _a;
42+
(_a = this, { value: ({ set value(_b) { tslib_1.__classPrivateFieldSet(_a, _Example_state, _b, "f"); } }).value } = source);
43+
}
44+
}
45+
_Example_state = new WeakMap();
46+
new Example().update({ value: { value: 1 } });
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/combined.ts(1,1): error TS2343: This syntax requires an imported helper named '__importStar' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
2+
/main.ts(1,1): error TS2343: This syntax requires an imported helper named '__importDefault' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
3+
4+
5+
==== /tsconfig.json (0 errors) ====
6+
{
7+
"compilerOptions": {
8+
"target": "es2015",
9+
"module": "commonjs",
10+
"importHelpers": true,
11+
}
12+
}
13+
14+
==== /main.ts (1 errors) ====
15+
import greet from "./dependency";
16+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17+
!!! error TS2343: This syntax requires an imported helper named '__importDefault' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
18+
19+
export const message = greet("world");
20+
21+
==== /combined.ts (1 errors) ====
22+
import greet, * as dependency from "./dependency";
23+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24+
!!! error TS2343: This syntax requires an imported helper named '__importStar' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
25+
26+
export const message = greet("world");
27+
export const namespaceMessage = dependency.default("namespace");
28+
29+
==== /dependency.ts (0 errors) ====
30+
export default function greet(name: string) {
31+
return `hello, ${name}`;
32+
}
33+
34+
==== /node_modules/tslib/package.json (0 errors) ====
35+
{
36+
"name": "tslib",
37+
"main": "tslib.js",
38+
"typings": "tslib.d.ts"
39+
}
40+
41+
==== /node_modules/tslib/tslib.d.ts (0 errors) ====
42+
export const notAHelper: any;
43+
44+
==== /node_modules/tslib/tslib.js (0 errors) ====
45+
module.exports.notAHelper = 3;
46+
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//// [tests/cases/compiler/tslibImportDefaultHelperCommonJS.ts] ////
2+
3+
//// [package.json]
4+
{
5+
"name": "tslib",
6+
"main": "tslib.js",
7+
"typings": "tslib.d.ts"
8+
}
9+
10+
//// [tslib.d.ts]
11+
export const notAHelper: any;
12+
13+
//// [tslib.js]
14+
module.exports.notAHelper = 3;
15+
16+
//// [main.ts]
17+
import greet from "./dependency";
18+
19+
export const message = greet("world");
20+
21+
//// [combined.ts]
22+
import greet, * as dependency from "./dependency";
23+
24+
export const message = greet("world");
25+
export const namespaceMessage = dependency.default("namespace");
26+
27+
//// [dependency.ts]
28+
export default function greet(name: string) {
29+
return `hello, ${name}`;
30+
}
31+
32+
33+
//// [dependency.js]
34+
"use strict";
35+
Object.defineProperty(exports, "__esModule", { value: true });
36+
exports.default = greet;
37+
function greet(name) {
38+
return `hello, ${name}`;
39+
}
40+
//// [main.js]
41+
"use strict";
42+
Object.defineProperty(exports, "__esModule", { value: true });
43+
exports.message = void 0;
44+
const tslib_1 = require("tslib");
45+
const dependency_1 = tslib_1.__importDefault(require("./dependency"));
46+
exports.message = (0, dependency_1.default)("world");
47+
//// [combined.js]
48+
"use strict";
49+
Object.defineProperty(exports, "__esModule", { value: true });
50+
exports.namespaceMessage = exports.message = void 0;
51+
const tslib_1 = require("tslib");
52+
const dependency_1 = tslib_1.__importStar(require("./dependency")), dependency = dependency_1;
53+
exports.message = (0, dependency_1.default)("world");
54+
exports.namespaceMessage = dependency.default("namespace");

0 commit comments

Comments
 (0)