Resolve external helpers module and report errors for missing module/exports

This commit is contained in:
Ron Buckton 2016-06-14 16:24:01 -07:00
parent 6ad04375c4
commit 76b34939d0
8 changed files with 101 additions and 45 deletions

View File

@ -1264,10 +1264,13 @@ namespace ts {
}
const moduleReferenceLiteral = <LiteralExpression>moduleReferenceExpression;
return resolveExternalModule(location, moduleReferenceLiteral.text, moduleNotFoundError, moduleReferenceLiteral);
}
function resolveExternalModule(location: Node, moduleReference: string, moduleNotFoundError: DiagnosticMessage, errorNode: Node): Symbol {
// Module names are escaped in our symbol table. However, string literal values aren't.
// Escape the name in the "require(...)" clause to ensure we find the right symbol.
const moduleName = escapeIdentifier(moduleReferenceLiteral.text);
const moduleName = escapeIdentifier(moduleReference);
if (moduleName === undefined) {
return;
@ -1282,7 +1285,7 @@ namespace ts {
}
}
const resolvedModule = getResolvedModule(getSourceFileOfNode(location), moduleReferenceLiteral.text);
const resolvedModule = getResolvedModule(getSourceFileOfNode(location), moduleReference);
const sourceFile = resolvedModule && host.getSourceFile(resolvedModule.resolvedFileName);
if (sourceFile) {
if (sourceFile.symbol) {
@ -1291,7 +1294,7 @@ namespace ts {
}
if (moduleNotFoundError) {
// report errors only if it was requested
error(moduleReferenceLiteral, Diagnostics.File_0_is_not_a_module, sourceFile.fileName);
error(errorNode, Diagnostics.File_0_is_not_a_module, sourceFile.fileName);
}
return undefined;
}
@ -1305,7 +1308,7 @@ namespace ts {
if (moduleNotFoundError) {
// report errors only if it was requested
error(moduleReferenceLiteral, moduleNotFoundError, moduleName);
error(errorNode, moduleNotFoundError, moduleName);
}
return undefined;
}
@ -17843,6 +17846,46 @@ namespace ts {
const symbol = getGlobalSymbol("ReadonlyArray", SymbolFlags.Type, /*diagnostic*/ undefined);
globalReadonlyArrayType = symbol && <GenericType>getTypeOfGlobalSymbol(symbol, /*arity*/ 1);
anyReadonlyArrayType = globalReadonlyArrayType ? createTypeFromGenericGlobalType(globalReadonlyArrayType, [anyType]) : anyArrayType;
// If we have specified that we are importing helpers, we should report global
// errors if we cannot resolve the helpers external module, or if it does not have
// the necessary helpers exported.
if (compilerOptions.importHelpers) {
forEach(host.getSourceFiles(), sourceFile => {
const requestedHelpers = sourceFile.flags & NodeFlags.EmitHelperFlags;
if (requestedHelpers && (compilerOptions.isolatedModules || isExternalModule(sourceFile))) {
const helpers = resolveExternalModule(sourceFile, externalHelpersModuleNameText, Diagnostics.Cannot_find_module_0, /*errorNode*/ undefined);
if (helpers) {
const exports = helpers.exports;
if (requestedHelpers & NodeFlags.HasClassExtends && languageVersion < ScriptTarget.ES6) {
verifyHelperSymbol(exports, "__extends", SymbolFlags.Function);
}
if (requestedHelpers & NodeFlags.HasJsxSpreadAttributes && compilerOptions.jsx !== JsxEmit.Preserve) {
verifyHelperSymbol(exports, "__assign", SymbolFlags.Value);
}
if (requestedHelpers & NodeFlags.HasDecorators) {
verifyHelperSymbol(exports, "__decorate", SymbolFlags.Value);
if (compilerOptions.emitDecoratorMetadata) {
verifyHelperSymbol(exports, "__metadata", SymbolFlags.Value);
}
}
if (requestedHelpers & NodeFlags.HasParamDecorators) {
verifyHelperSymbol(exports, "__param", SymbolFlags.Value);
}
if (requestedHelpers & NodeFlags.HasAsyncFunctions) {
verifyHelperSymbol(exports, "__awaiter", SymbolFlags.Value);
}
}
}
});
}
}
function verifyHelperSymbol(symbols: SymbolTable, name: string, meaning: SymbolFlags) {
const symbol = getSymbol(symbols, escapeIdentifier(name), meaning);
if (!symbol) {
error(/*location*/ undefined, Diagnostics.Module_0_has_no_exported_member_1, externalHelpersModuleNameText, name);
}
}
function createInstantiatedPromiseLikeType(): ObjectType {

View File

@ -824,7 +824,7 @@ namespace ts {
if (node.resolvedTypeReferenceDirectiveNames !== undefined) updated.resolvedTypeReferenceDirectiveNames = node.resolvedTypeReferenceDirectiveNames;
if (node.imports !== undefined) updated.imports = node.imports;
if (node.moduleAugmentations !== undefined) updated.moduleAugmentations = node.moduleAugmentations;
if (node.tslib !== undefined) updated.tslib = node.tslib;
if (node.externalHelpersModuleName !== undefined) updated.externalHelpersModuleName = node.externalHelpersModuleName;
return updateNode(updated, node);
}
@ -1065,15 +1065,15 @@ namespace ts {
// Helpers
export function createHelperName(tslib: Identifier | undefined, name: string) {
return tslib
? createPropertyAccess(tslib, name)
export function createHelperName(externalHelpersModuleName: Identifier | undefined, name: string) {
return externalHelpersModuleName
? createPropertyAccess(externalHelpersModuleName, name)
: createIdentifier(name);
}
export function createExtendsHelper(tslib: Identifier | undefined, name: Identifier) {
export function createExtendsHelper(externalHelpersModuleName: Identifier | undefined, name: Identifier) {
return createCall(
createHelperName(tslib, "__extends"),
createHelperName(externalHelpersModuleName, "__extends"),
/*typeArguments*/ undefined,
[
name,
@ -1082,17 +1082,17 @@ namespace ts {
);
}
export function createAssignHelper(tslib: Identifier | undefined, attributesSegments: Expression[]) {
export function createAssignHelper(externalHelpersModuleName: Identifier | undefined, attributesSegments: Expression[]) {
return createCall(
createHelperName(tslib, "__assign"),
createHelperName(externalHelpersModuleName, "__assign"),
/*typeArguments*/ undefined,
attributesSegments
);
}
export function createParamHelper(tslib: Identifier | undefined, expression: Expression, parameterOffset: number, location?: TextRange) {
export function createParamHelper(externalHelpersModuleName: Identifier | undefined, expression: Expression, parameterOffset: number, location?: TextRange) {
return createCall(
createHelperName(tslib, "__param"),
createHelperName(externalHelpersModuleName, "__param"),
/*typeArguments*/ undefined,
[
createLiteral(parameterOffset),
@ -1102,9 +1102,9 @@ namespace ts {
);
}
export function createMetadataHelper(tslib: Identifier | undefined, metadataKey: string, metadataValue: Expression) {
export function createMetadataHelper(externalHelpersModuleName: Identifier | undefined, metadataKey: string, metadataValue: Expression) {
return createCall(
createHelperName(tslib, "__metadata"),
createHelperName(externalHelpersModuleName, "__metadata"),
/*typeArguments*/ undefined,
[
createLiteral(metadataKey),
@ -1113,7 +1113,7 @@ namespace ts {
);
}
export function createDecorateHelper(tslib: Identifier | undefined, decoratorExpressions: Expression[], target: Expression, memberName?: Expression, descriptor?: Expression, location?: TextRange) {
export function createDecorateHelper(externalHelpersModuleName: Identifier | undefined, decoratorExpressions: Expression[], target: Expression, memberName?: Expression, descriptor?: Expression, location?: TextRange) {
const argumentsArray: Expression[] = [];
argumentsArray.push(createArrayLiteral(decoratorExpressions, /*location*/ undefined, /*multiLine*/ true));
argumentsArray.push(target);
@ -1124,12 +1124,12 @@ namespace ts {
}
}
return createCall(createHelperName(tslib, "__decorate"), /*typeArguments*/ undefined, argumentsArray, location);
return createCall(createHelperName(externalHelpersModuleName, "__decorate"), /*typeArguments*/ undefined, argumentsArray, location);
}
export function createAwaiterHelper(tslib: Identifier | undefined, hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression, body: Block) {
export function createAwaiterHelper(externalHelpersModuleName: Identifier | undefined, hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression, body: Block) {
return createCall(
createHelperName(tslib, "__awaiter"),
createHelperName(externalHelpersModuleName, "__awaiter"),
/*typeArguments*/ undefined,
[
createThis(),

View File

@ -1723,6 +1723,17 @@ namespace ts {
let imports: LiteralExpression[];
let moduleAugmentations: LiteralExpression[];
// If we are importing helpers, we need to add a synthetic reference to resolve the
// helpers library.
if (options.importHelpers
&& (options.isolatedModules || isExternalModuleFile)
&& !file.isDeclarationFile) {
const externalHelpersModuleReference = <StringLiteral>createNode(SyntaxKind.StringLiteral);
externalHelpersModuleReference.text = externalHelpersModuleNameText;
externalHelpersModuleReference.parent = file;
imports = [externalHelpersModuleReference];
}
for (const node of file.statements) {
collectModuleReferences(node, /*inAmbientModule*/ false);
if (isJavaScriptFile) {

View File

@ -702,7 +702,7 @@ namespace ts {
if (extendsClauseElement) {
statements.push(
createStatement(
createExtendsHelper(currentSourceFile.tslib, getDeclarationName(node)),
createExtendsHelper(currentSourceFile.externalHelpersModuleName, getDeclarationName(node)),
/*location*/ extendsClauseElement
)
);

View File

@ -106,7 +106,7 @@ namespace ts {
// Either emit one big object literal (no spread attribs), or
// a call to the __assign helper.
objectProperties = singleOrUndefined(segments)
|| createAssignHelper(currentSourceFile.tslib, segments);
|| createAssignHelper(currentSourceFile.externalHelpersModuleName, segments);
}
const element = createReactCreateElement(

View File

@ -51,7 +51,7 @@ namespace ts {
let currentNamespace: ModuleDeclaration;
let currentNamespaceContainerName: Identifier;
let currentScope: SourceFile | Block | ModuleBlock | CaseBlock;
let currentSourceFileTslib: Identifier;
let currentSourceFileExternalHelpersModuleName: Identifier;
/**
* Keeps track of whether expression substitution has been enabled for specific edge cases.
@ -432,22 +432,22 @@ namespace ts {
startLexicalEnvironment();
const statements: Statement[] = [];
const statementOffset = addPrologueDirectives(statements, node.statements);
const tslib = createUniqueName("tslib");
const tslibImport = createImportDeclaration(
createImportClause(/*name*/ undefined, createNamespaceImport(tslib)),
createLiteral("tslib")
const externalHelpersModuleName = createUniqueName(externalHelpersModuleNameText);
const externalHelpersModuleImport = createImportDeclaration(
createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)),
createLiteral(externalHelpersModuleNameText)
);
tslibImport.parent = node;
tslibImport.flags &= ~NodeFlags.Synthesized;
statements.push(tslibImport);
externalHelpersModuleImport.parent = node;
externalHelpersModuleImport.flags &= ~NodeFlags.Synthesized;
statements.push(externalHelpersModuleImport);
currentSourceFileTslib = tslib;
currentSourceFileExternalHelpersModuleName = externalHelpersModuleName;
addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset));
addRange(statements, endLexicalEnvironment());
currentSourceFileTslib = undefined;
currentSourceFileExternalHelpersModuleName = undefined;
node = updateSourceFileNode(node, createNodeArray(statements, node.statements));
node.tslib = tslib;
node.externalHelpersModuleName = externalHelpersModuleName;
}
else {
node = visitEachChild(node, visitor, context);
@ -1382,7 +1382,7 @@ namespace ts {
: undefined;
const helper = createDecorateHelper(
currentSourceFileTslib,
currentSourceFileExternalHelpersModuleName,
decoratorExpressions,
prefix,
memberName,
@ -1432,7 +1432,7 @@ namespace ts {
const expression = createAssignment(
decoratedClassAlias,
createDecorateHelper(
currentSourceFileTslib,
currentSourceFileExternalHelpersModuleName,
decoratorExpressions,
getDeclarationName(node)
)
@ -1456,7 +1456,7 @@ namespace ts {
const result = createAssignment(
getDeclarationName(node),
createDecorateHelper(
currentSourceFileTslib,
currentSourceFileExternalHelpersModuleName,
decoratorExpressions,
getDeclarationName(node)
),
@ -1489,7 +1489,7 @@ namespace ts {
expressions = [];
for (const decorator of decorators) {
const helper = createParamHelper(
currentSourceFileTslib,
currentSourceFileExternalHelpersModuleName,
transformDecorator(decorator),
parameterOffset,
/*location*/ decorator.expression);
@ -1519,13 +1519,13 @@ namespace ts {
function addOldTypeMetadata(node: Declaration, decoratorExpressions: Expression[]) {
if (compilerOptions.emitDecoratorMetadata) {
if (shouldAddTypeMetadata(node)) {
decoratorExpressions.push(createMetadataHelper(currentSourceFileTslib, "design:type", serializeTypeOfNode(node)));
decoratorExpressions.push(createMetadataHelper(currentSourceFileExternalHelpersModuleName, "design:type", serializeTypeOfNode(node)));
}
if (shouldAddParamTypesMetadata(node)) {
decoratorExpressions.push(createMetadataHelper(currentSourceFileTslib, "design:paramtypes", serializeParameterTypesOfNode(node)));
decoratorExpressions.push(createMetadataHelper(currentSourceFileExternalHelpersModuleName, "design:paramtypes", serializeParameterTypesOfNode(node)));
}
if (shouldAddReturnTypeMetadata(node)) {
decoratorExpressions.push(createMetadataHelper(currentSourceFileTslib, "design:returntype", serializeReturnTypeOfNode(node)));
decoratorExpressions.push(createMetadataHelper(currentSourceFileExternalHelpersModuleName, "design:returntype", serializeReturnTypeOfNode(node)));
}
}
}
@ -1543,7 +1543,7 @@ namespace ts {
(properties || (properties = [])).push(createPropertyAssignment("returnType", createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, serializeReturnTypeOfNode(node))));
}
if (properties) {
decoratorExpressions.push(createMetadataHelper(currentSourceFileTslib, "design:typeinfo", createObjectLiteral(properties, /*location*/ undefined, /*multiLine*/ true)));
decoratorExpressions.push(createMetadataHelper(currentSourceFileExternalHelpersModuleName, "design:typeinfo", createObjectLiteral(properties, /*location*/ undefined, /*multiLine*/ true)));
}
}
}
@ -2234,7 +2234,7 @@ namespace ts {
statements.push(
createReturn(
createAwaiterHelper(
currentSourceFileTslib,
currentSourceFileExternalHelpersModuleName,
hasLexicalArguments,
promiseConstructor,
transformFunctionBodyWorker(<Block>node.body)
@ -2261,7 +2261,7 @@ namespace ts {
}
else {
return createAwaiterHelper(
currentSourceFileTslib,
currentSourceFileExternalHelpersModuleName,
hasLexicalArguments,
promiseConstructor,
<Block>transformConciseBodyWorker(node.body, /*forceBlockFunctionBody*/ true)

View File

@ -1726,8 +1726,8 @@ namespace ts {
/* @internal */ imports: LiteralExpression[];
/* @internal */ moduleAugmentations: LiteralExpression[];
/* @internal */ patternAmbientModules?: PatternAmbientModule[];
// The synthesized identifier for an imported tslib helpers runtime.
/* @internal */ tslib?: Identifier;
// The synthesized identifier for an imported external helpers module.
/* @internal */ externalHelpersModuleName?: Identifier;
}
export interface ScriptReferenceHost {

View File

@ -2,6 +2,8 @@
/* @internal */
namespace ts {
export const externalHelpersModuleNameText = "tslib";
export interface ReferencePathMatchResult {
fileReference?: FileReference;
diagnosticMessage?: DiagnosticMessage;