Skip to content

Commit 76b3493

Browse files
committed
Resolve external helpers module and report errors for missing module/exports
1 parent 6ad0437 commit 76b3493

File tree

8 files changed

+101
-45
lines changed

8 files changed

+101
-45
lines changed

src/compiler/checker.ts

+47-4
Original file line numberDiff line numberDiff line change
@@ -1264,10 +1264,13 @@ namespace ts {
12641264
}
12651265

12661266
const moduleReferenceLiteral = <LiteralExpression>moduleReferenceExpression;
1267+
return resolveExternalModule(location, moduleReferenceLiteral.text, moduleNotFoundError, moduleReferenceLiteral);
1268+
}
12671269

1270+
function resolveExternalModule(location: Node, moduleReference: string, moduleNotFoundError: DiagnosticMessage, errorNode: Node): Symbol {
12681271
// Module names are escaped in our symbol table. However, string literal values aren't.
12691272
// Escape the name in the "require(...)" clause to ensure we find the right symbol.
1270-
const moduleName = escapeIdentifier(moduleReferenceLiteral.text);
1273+
const moduleName = escapeIdentifier(moduleReference);
12711274

12721275
if (moduleName === undefined) {
12731276
return;
@@ -1282,7 +1285,7 @@ namespace ts {
12821285
}
12831286
}
12841287

1285-
const resolvedModule = getResolvedModule(getSourceFileOfNode(location), moduleReferenceLiteral.text);
1288+
const resolvedModule = getResolvedModule(getSourceFileOfNode(location), moduleReference);
12861289
const sourceFile = resolvedModule && host.getSourceFile(resolvedModule.resolvedFileName);
12871290
if (sourceFile) {
12881291
if (sourceFile.symbol) {
@@ -1291,7 +1294,7 @@ namespace ts {
12911294
}
12921295
if (moduleNotFoundError) {
12931296
// report errors only if it was requested
1294-
error(moduleReferenceLiteral, Diagnostics.File_0_is_not_a_module, sourceFile.fileName);
1297+
error(errorNode, Diagnostics.File_0_is_not_a_module, sourceFile.fileName);
12951298
}
12961299
return undefined;
12971300
}
@@ -1305,7 +1308,7 @@ namespace ts {
13051308

13061309
if (moduleNotFoundError) {
13071310
// report errors only if it was requested
1308-
error(moduleReferenceLiteral, moduleNotFoundError, moduleName);
1311+
error(errorNode, moduleNotFoundError, moduleName);
13091312
}
13101313
return undefined;
13111314
}
@@ -17843,6 +17846,46 @@ namespace ts {
1784317846
const symbol = getGlobalSymbol("ReadonlyArray", SymbolFlags.Type, /*diagnostic*/ undefined);
1784417847
globalReadonlyArrayType = symbol && <GenericType>getTypeOfGlobalSymbol(symbol, /*arity*/ 1);
1784517848
anyReadonlyArrayType = globalReadonlyArrayType ? createTypeFromGenericGlobalType(globalReadonlyArrayType, [anyType]) : anyArrayType;
17849+
17850+
// If we have specified that we are importing helpers, we should report global
17851+
// errors if we cannot resolve the helpers external module, or if it does not have
17852+
// the necessary helpers exported.
17853+
if (compilerOptions.importHelpers) {
17854+
forEach(host.getSourceFiles(), sourceFile => {
17855+
const requestedHelpers = sourceFile.flags & NodeFlags.EmitHelperFlags;
17856+
if (requestedHelpers && (compilerOptions.isolatedModules || isExternalModule(sourceFile))) {
17857+
const helpers = resolveExternalModule(sourceFile, externalHelpersModuleNameText, Diagnostics.Cannot_find_module_0, /*errorNode*/ undefined);
17858+
if (helpers) {
17859+
const exports = helpers.exports;
17860+
if (requestedHelpers & NodeFlags.HasClassExtends && languageVersion < ScriptTarget.ES6) {
17861+
verifyHelperSymbol(exports, "__extends", SymbolFlags.Function);
17862+
}
17863+
if (requestedHelpers & NodeFlags.HasJsxSpreadAttributes && compilerOptions.jsx !== JsxEmit.Preserve) {
17864+
verifyHelperSymbol(exports, "__assign", SymbolFlags.Value);
17865+
}
17866+
if (requestedHelpers & NodeFlags.HasDecorators) {
17867+
verifyHelperSymbol(exports, "__decorate", SymbolFlags.Value);
17868+
if (compilerOptions.emitDecoratorMetadata) {
17869+
verifyHelperSymbol(exports, "__metadata", SymbolFlags.Value);
17870+
}
17871+
}
17872+
if (requestedHelpers & NodeFlags.HasParamDecorators) {
17873+
verifyHelperSymbol(exports, "__param", SymbolFlags.Value);
17874+
}
17875+
if (requestedHelpers & NodeFlags.HasAsyncFunctions) {
17876+
verifyHelperSymbol(exports, "__awaiter", SymbolFlags.Value);
17877+
}
17878+
}
17879+
}
17880+
});
17881+
}
17882+
}
17883+
17884+
function verifyHelperSymbol(symbols: SymbolTable, name: string, meaning: SymbolFlags) {
17885+
const symbol = getSymbol(symbols, escapeIdentifier(name), meaning);
17886+
if (!symbol) {
17887+
error(/*location*/ undefined, Diagnostics.Module_0_has_no_exported_member_1, externalHelpersModuleNameText, name);
17888+
}
1784617889
}
1784717890

1784817891
function createInstantiatedPromiseLikeType(): ObjectType {

src/compiler/factory.ts

+16-16
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ namespace ts {
824824
if (node.resolvedTypeReferenceDirectiveNames !== undefined) updated.resolvedTypeReferenceDirectiveNames = node.resolvedTypeReferenceDirectiveNames;
825825
if (node.imports !== undefined) updated.imports = node.imports;
826826
if (node.moduleAugmentations !== undefined) updated.moduleAugmentations = node.moduleAugmentations;
827-
if (node.tslib !== undefined) updated.tslib = node.tslib;
827+
if (node.externalHelpersModuleName !== undefined) updated.externalHelpersModuleName = node.externalHelpersModuleName;
828828
return updateNode(updated, node);
829829
}
830830

@@ -1065,15 +1065,15 @@ namespace ts {
10651065

10661066
// Helpers
10671067

1068-
export function createHelperName(tslib: Identifier | undefined, name: string) {
1069-
return tslib
1070-
? createPropertyAccess(tslib, name)
1068+
export function createHelperName(externalHelpersModuleName: Identifier | undefined, name: string) {
1069+
return externalHelpersModuleName
1070+
? createPropertyAccess(externalHelpersModuleName, name)
10711071
: createIdentifier(name);
10721072
}
10731073

1074-
export function createExtendsHelper(tslib: Identifier | undefined, name: Identifier) {
1074+
export function createExtendsHelper(externalHelpersModuleName: Identifier | undefined, name: Identifier) {
10751075
return createCall(
1076-
createHelperName(tslib, "__extends"),
1076+
createHelperName(externalHelpersModuleName, "__extends"),
10771077
/*typeArguments*/ undefined,
10781078
[
10791079
name,
@@ -1082,17 +1082,17 @@ namespace ts {
10821082
);
10831083
}
10841084

1085-
export function createAssignHelper(tslib: Identifier | undefined, attributesSegments: Expression[]) {
1085+
export function createAssignHelper(externalHelpersModuleName: Identifier | undefined, attributesSegments: Expression[]) {
10861086
return createCall(
1087-
createHelperName(tslib, "__assign"),
1087+
createHelperName(externalHelpersModuleName, "__assign"),
10881088
/*typeArguments*/ undefined,
10891089
attributesSegments
10901090
);
10911091
}
10921092

1093-
export function createParamHelper(tslib: Identifier | undefined, expression: Expression, parameterOffset: number, location?: TextRange) {
1093+
export function createParamHelper(externalHelpersModuleName: Identifier | undefined, expression: Expression, parameterOffset: number, location?: TextRange) {
10941094
return createCall(
1095-
createHelperName(tslib, "__param"),
1095+
createHelperName(externalHelpersModuleName, "__param"),
10961096
/*typeArguments*/ undefined,
10971097
[
10981098
createLiteral(parameterOffset),
@@ -1102,9 +1102,9 @@ namespace ts {
11021102
);
11031103
}
11041104

1105-
export function createMetadataHelper(tslib: Identifier | undefined, metadataKey: string, metadataValue: Expression) {
1105+
export function createMetadataHelper(externalHelpersModuleName: Identifier | undefined, metadataKey: string, metadataValue: Expression) {
11061106
return createCall(
1107-
createHelperName(tslib, "__metadata"),
1107+
createHelperName(externalHelpersModuleName, "__metadata"),
11081108
/*typeArguments*/ undefined,
11091109
[
11101110
createLiteral(metadataKey),
@@ -1113,7 +1113,7 @@ namespace ts {
11131113
);
11141114
}
11151115

1116-
export function createDecorateHelper(tslib: Identifier | undefined, decoratorExpressions: Expression[], target: Expression, memberName?: Expression, descriptor?: Expression, location?: TextRange) {
1116+
export function createDecorateHelper(externalHelpersModuleName: Identifier | undefined, decoratorExpressions: Expression[], target: Expression, memberName?: Expression, descriptor?: Expression, location?: TextRange) {
11171117
const argumentsArray: Expression[] = [];
11181118
argumentsArray.push(createArrayLiteral(decoratorExpressions, /*location*/ undefined, /*multiLine*/ true));
11191119
argumentsArray.push(target);
@@ -1124,12 +1124,12 @@ namespace ts {
11241124
}
11251125
}
11261126

1127-
return createCall(createHelperName(tslib, "__decorate"), /*typeArguments*/ undefined, argumentsArray, location);
1127+
return createCall(createHelperName(externalHelpersModuleName, "__decorate"), /*typeArguments*/ undefined, argumentsArray, location);
11281128
}
11291129

1130-
export function createAwaiterHelper(tslib: Identifier | undefined, hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression, body: Block) {
1130+
export function createAwaiterHelper(externalHelpersModuleName: Identifier | undefined, hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression, body: Block) {
11311131
return createCall(
1132-
createHelperName(tslib, "__awaiter"),
1132+
createHelperName(externalHelpersModuleName, "__awaiter"),
11331133
/*typeArguments*/ undefined,
11341134
[
11351135
createThis(),

src/compiler/program.ts

+11
Original file line numberDiff line numberDiff line change
@@ -1723,6 +1723,17 @@ namespace ts {
17231723
let imports: LiteralExpression[];
17241724
let moduleAugmentations: LiteralExpression[];
17251725

1726+
// If we are importing helpers, we need to add a synthetic reference to resolve the
1727+
// helpers library.
1728+
if (options.importHelpers
1729+
&& (options.isolatedModules || isExternalModuleFile)
1730+
&& !file.isDeclarationFile) {
1731+
const externalHelpersModuleReference = <StringLiteral>createNode(SyntaxKind.StringLiteral);
1732+
externalHelpersModuleReference.text = externalHelpersModuleNameText;
1733+
externalHelpersModuleReference.parent = file;
1734+
imports = [externalHelpersModuleReference];
1735+
}
1736+
17261737
for (const node of file.statements) {
17271738
collectModuleReferences(node, /*inAmbientModule*/ false);
17281739
if (isJavaScriptFile) {

src/compiler/transformers/es6.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ namespace ts {
702702
if (extendsClauseElement) {
703703
statements.push(
704704
createStatement(
705-
createExtendsHelper(currentSourceFile.tslib, getDeclarationName(node)),
705+
createExtendsHelper(currentSourceFile.externalHelpersModuleName, getDeclarationName(node)),
706706
/*location*/ extendsClauseElement
707707
)
708708
);

src/compiler/transformers/jsx.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ namespace ts {
106106
// Either emit one big object literal (no spread attribs), or
107107
// a call to the __assign helper.
108108
objectProperties = singleOrUndefined(segments)
109-
|| createAssignHelper(currentSourceFile.tslib, segments);
109+
|| createAssignHelper(currentSourceFile.externalHelpersModuleName, segments);
110110
}
111111

112112
const element = createReactCreateElement(

src/compiler/transformers/ts.ts

+21-21
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ namespace ts {
5151
let currentNamespace: ModuleDeclaration;
5252
let currentNamespaceContainerName: Identifier;
5353
let currentScope: SourceFile | Block | ModuleBlock | CaseBlock;
54-
let currentSourceFileTslib: Identifier;
54+
let currentSourceFileExternalHelpersModuleName: Identifier;
5555

5656
/**
5757
* Keeps track of whether expression substitution has been enabled for specific edge cases.
@@ -432,22 +432,22 @@ namespace ts {
432432
startLexicalEnvironment();
433433
const statements: Statement[] = [];
434434
const statementOffset = addPrologueDirectives(statements, node.statements);
435-
const tslib = createUniqueName("tslib");
436-
const tslibImport = createImportDeclaration(
437-
createImportClause(/*name*/ undefined, createNamespaceImport(tslib)),
438-
createLiteral("tslib")
435+
const externalHelpersModuleName = createUniqueName(externalHelpersModuleNameText);
436+
const externalHelpersModuleImport = createImportDeclaration(
437+
createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)),
438+
createLiteral(externalHelpersModuleNameText)
439439
);
440-
tslibImport.parent = node;
441-
tslibImport.flags &= ~NodeFlags.Synthesized;
442-
statements.push(tslibImport);
440+
externalHelpersModuleImport.parent = node;
441+
externalHelpersModuleImport.flags &= ~NodeFlags.Synthesized;
442+
statements.push(externalHelpersModuleImport);
443443

444-
currentSourceFileTslib = tslib;
444+
currentSourceFileExternalHelpersModuleName = externalHelpersModuleName;
445445
addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset));
446446
addRange(statements, endLexicalEnvironment());
447-
currentSourceFileTslib = undefined;
447+
currentSourceFileExternalHelpersModuleName = undefined;
448448

449449
node = updateSourceFileNode(node, createNodeArray(statements, node.statements));
450-
node.tslib = tslib;
450+
node.externalHelpersModuleName = externalHelpersModuleName;
451451
}
452452
else {
453453
node = visitEachChild(node, visitor, context);
@@ -1382,7 +1382,7 @@ namespace ts {
13821382
: undefined;
13831383

13841384
const helper = createDecorateHelper(
1385-
currentSourceFileTslib,
1385+
currentSourceFileExternalHelpersModuleName,
13861386
decoratorExpressions,
13871387
prefix,
13881388
memberName,
@@ -1432,7 +1432,7 @@ namespace ts {
14321432
const expression = createAssignment(
14331433
decoratedClassAlias,
14341434
createDecorateHelper(
1435-
currentSourceFileTslib,
1435+
currentSourceFileExternalHelpersModuleName,
14361436
decoratorExpressions,
14371437
getDeclarationName(node)
14381438
)
@@ -1456,7 +1456,7 @@ namespace ts {
14561456
const result = createAssignment(
14571457
getDeclarationName(node),
14581458
createDecorateHelper(
1459-
currentSourceFileTslib,
1459+
currentSourceFileExternalHelpersModuleName,
14601460
decoratorExpressions,
14611461
getDeclarationName(node)
14621462
),
@@ -1489,7 +1489,7 @@ namespace ts {
14891489
expressions = [];
14901490
for (const decorator of decorators) {
14911491
const helper = createParamHelper(
1492-
currentSourceFileTslib,
1492+
currentSourceFileExternalHelpersModuleName,
14931493
transformDecorator(decorator),
14941494
parameterOffset,
14951495
/*location*/ decorator.expression);
@@ -1519,13 +1519,13 @@ namespace ts {
15191519
function addOldTypeMetadata(node: Declaration, decoratorExpressions: Expression[]) {
15201520
if (compilerOptions.emitDecoratorMetadata) {
15211521
if (shouldAddTypeMetadata(node)) {
1522-
decoratorExpressions.push(createMetadataHelper(currentSourceFileTslib, "design:type", serializeTypeOfNode(node)));
1522+
decoratorExpressions.push(createMetadataHelper(currentSourceFileExternalHelpersModuleName, "design:type", serializeTypeOfNode(node)));
15231523
}
15241524
if (shouldAddParamTypesMetadata(node)) {
1525-
decoratorExpressions.push(createMetadataHelper(currentSourceFileTslib, "design:paramtypes", serializeParameterTypesOfNode(node)));
1525+
decoratorExpressions.push(createMetadataHelper(currentSourceFileExternalHelpersModuleName, "design:paramtypes", serializeParameterTypesOfNode(node)));
15261526
}
15271527
if (shouldAddReturnTypeMetadata(node)) {
1528-
decoratorExpressions.push(createMetadataHelper(currentSourceFileTslib, "design:returntype", serializeReturnTypeOfNode(node)));
1528+
decoratorExpressions.push(createMetadataHelper(currentSourceFileExternalHelpersModuleName, "design:returntype", serializeReturnTypeOfNode(node)));
15291529
}
15301530
}
15311531
}
@@ -1543,7 +1543,7 @@ namespace ts {
15431543
(properties || (properties = [])).push(createPropertyAssignment("returnType", createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, serializeReturnTypeOfNode(node))));
15441544
}
15451545
if (properties) {
1546-
decoratorExpressions.push(createMetadataHelper(currentSourceFileTslib, "design:typeinfo", createObjectLiteral(properties, /*location*/ undefined, /*multiLine*/ true)));
1546+
decoratorExpressions.push(createMetadataHelper(currentSourceFileExternalHelpersModuleName, "design:typeinfo", createObjectLiteral(properties, /*location*/ undefined, /*multiLine*/ true)));
15471547
}
15481548
}
15491549
}
@@ -2234,7 +2234,7 @@ namespace ts {
22342234
statements.push(
22352235
createReturn(
22362236
createAwaiterHelper(
2237-
currentSourceFileTslib,
2237+
currentSourceFileExternalHelpersModuleName,
22382238
hasLexicalArguments,
22392239
promiseConstructor,
22402240
transformFunctionBodyWorker(<Block>node.body)
@@ -2261,7 +2261,7 @@ namespace ts {
22612261
}
22622262
else {
22632263
return createAwaiterHelper(
2264-
currentSourceFileTslib,
2264+
currentSourceFileExternalHelpersModuleName,
22652265
hasLexicalArguments,
22662266
promiseConstructor,
22672267
<Block>transformConciseBodyWorker(node.body, /*forceBlockFunctionBody*/ true)

src/compiler/types.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1726,8 +1726,8 @@ namespace ts {
17261726
/* @internal */ imports: LiteralExpression[];
17271727
/* @internal */ moduleAugmentations: LiteralExpression[];
17281728
/* @internal */ patternAmbientModules?: PatternAmbientModule[];
1729-
// The synthesized identifier for an imported tslib helpers runtime.
1730-
/* @internal */ tslib?: Identifier;
1729+
// The synthesized identifier for an imported external helpers module.
1730+
/* @internal */ externalHelpersModuleName?: Identifier;
17311731
}
17321732

17331733
export interface ScriptReferenceHost {

src/compiler/utilities.ts

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
/* @internal */
44
namespace ts {
5+
export const externalHelpersModuleNameText = "tslib";
6+
57
export interface ReferencePathMatchResult {
68
fileReference?: FileReference;
79
diagnosticMessage?: DiagnosticMessage;

0 commit comments

Comments
 (0)