Module or import types (#22592)

* Type side of import types

* Value side of import types

* Accept library changes

* Refined implementation, more tests

* Allow resolutions to be performed late if the resolution still results in a file already in the build

* Add another test case

* Add some jsdoc usages

* Allow nodebuilder to use import types where appropriate

* Parse & check generic instantiations

* use import types in nodebuilder for typeof module symbols

* Wire up go to definition for import types

* Accept updated type/symbol baselines now that symbols are wired in

* PR feedback

* Fix changes from merge

* Walk back late import handling

* Remove unused diagnostic

* Remove unrelated changes

* Use recursive function over loop

* Emit type arguments

* undo unrelated change

* Test for and support import type nodes in bundled declaration emit
This commit is contained in:
Wesley Wigham
2018-04-02 10:18:23 -07:00
committed by GitHub
parent 5c442419dc
commit 414bc49cc4
287 changed files with 3826 additions and 1279 deletions
+163 -25
View File
@@ -2115,7 +2115,8 @@ namespace ts {
if (ambientModule) {
return ambientModule;
}
const resolvedModule = getResolvedModule(getSourceFileOfNode(location), moduleReference);
const currentSourceFile = getSourceFileOfNode(location);
const resolvedModule = getResolvedModule(currentSourceFile, moduleReference);
const resolutionDiagnostic = resolvedModule && getResolutionDiagnostic(compilerOptions, resolvedModule);
const sourceFile = resolvedModule && !resolutionDiagnostic && host.getSourceFile(resolvedModule.resolvedFileName);
if (sourceFile) {
@@ -2193,15 +2194,15 @@ namespace ts {
// An external module with an 'export =' declaration may be referenced as an ES6 module provided the 'export ='
// references a symbol that is at least declared as a module or a variable. The target of the 'export =' may
// combine other declarations with the module or variable (e.g. a class/module, function/module, interface/variable).
function resolveESModuleSymbol(moduleSymbol: Symbol, moduleReferenceExpression: Expression, dontResolveAlias: boolean): Symbol {
function resolveESModuleSymbol(moduleSymbol: Symbol, referencingLocation: Node, dontResolveAlias: boolean): Symbol {
const symbol = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias);
if (!dontResolveAlias && symbol) {
if (!(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable))) {
error(moduleReferenceExpression, Diagnostics.Module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct, symbolToString(moduleSymbol));
error(referencingLocation, Diagnostics.Module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct, symbolToString(moduleSymbol));
return symbol;
}
if (compilerOptions.esModuleInterop) {
const referenceParent = moduleReferenceExpression.parent;
const referenceParent = referencingLocation.parent;
if (
(isImportDeclaration(referenceParent) && getNamespaceDeclarationNode(referenceParent)) ||
isImportCall(referenceParent)
@@ -2951,7 +2952,7 @@ namespace ts {
if (type.flags & TypeFlags.UniqueESSymbol) {
if (!(context.flags & NodeBuilderFlags.AllowUniqueESSymbolType)) {
if (isValueSymbolAccessible(type.symbol, context.enclosingDeclaration)) {
return createTypeQueryNode(symbolToName(type.symbol, context, SymbolFlags.Value, /*expectsIdentifier*/ false));
return symbolToTypeNode(type.symbol, context, SymbolFlags.Value);
}
if (context.tracker.reportInaccessibleUniqueSymbolError) {
context.tracker.reportInaccessibleUniqueSymbolError();
@@ -3070,15 +3071,14 @@ namespace ts {
if (symbol.flags & SymbolFlags.Class && !getBaseTypeVariableOfClass(symbol) && !(symbol.valueDeclaration.kind === SyntaxKind.ClassExpression && context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral) ||
symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule) ||
shouldWriteTypeOfFunctionSymbol()) {
return createTypeQueryNodeFromSymbol(symbol, SymbolFlags.Value);
return symbolToTypeNode(symbol, context, SymbolFlags.Value);
}
else if (contains(context.symbolStack, symbol)) {
// If type is an anonymous type literal in a type alias declaration, use type alias name
const typeAlias = getTypeAliasForTypeLiteral(type);
if (typeAlias) {
// The specified symbol flags need to be reinterpreted as type flags
const entityName = symbolToName(typeAlias, context, SymbolFlags.Type, /*expectsIdentifier*/ false);
return createTypeReferenceNode(entityName, /*typeArguments*/ undefined);
return symbolToTypeNode(typeAlias, context, SymbolFlags.Type);
}
else {
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
@@ -3156,11 +3156,6 @@ namespace ts {
return setEmitFlags(typeLiteralNode, (context.flags & NodeBuilderFlags.MultilineObjectLiterals) ? 0 : EmitFlags.SingleLine);
}
function createTypeQueryNodeFromSymbol(symbol: Symbol, symbolFlags: SymbolFlags) {
const entityName = symbolToName(symbol, context, symbolFlags, /*expectsIdentifier*/ false);
return createTypeQueryNode(entityName);
}
function symbolToTypeReferenceName(symbol: Symbol) {
// Unnamed function expressions and arrow functions have reserved names that we don't want to display
const entityName = symbol.flags & SymbolFlags.Class || !isReservedMemberName(symbol.escapedName) ? symbolToName(symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false) : createIdentifier("");
@@ -3566,6 +3561,42 @@ namespace ts {
return typeParameterNodes;
}
function symbolToTypeNode(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags): TypeQueryNode | TypeReferenceNode | ImportTypeNode {
const chain = lookupSymbolChain(symbol, context, meaning);
context.flags |= NodeBuilderFlags.InInitialEntityName;
const rootName = getNameOfSymbolAsWritten(chain[0], context);
context.flags ^= NodeBuilderFlags.InInitialEntityName;
const isTypeOf = meaning === SymbolFlags.Value;
if (ambientModuleSymbolRegex.test(rootName)) {
// module is root, must use `ImportTypeNode`
const nonRootParts = chain.length > 1 ? createEntityNameFromSymbolChain(chain, chain.length - 1, 1) : undefined;
const typeParameterNodes = lookupTypeParameterNodes(chain, 0, context);
return createImportTypeNode(createLiteralTypeNode(createLiteral(rootName.substring(1, rootName.length - 1))), nonRootParts, typeParameterNodes as ReadonlyArray<TypeNode>, isTypeOf);
}
const entityName = createEntityNameFromSymbolChain(chain, chain.length - 1, 0);
return isTypeOf ? createTypeQueryNode(entityName) : createTypeReferenceNode(entityName, /*typeArguments*/ undefined);
function createEntityNameFromSymbolChain(chain: Symbol[], index: number, stopper: number): EntityName {
const typeParameterNodes = lookupTypeParameterNodes(chain, index, context);
const symbol = chain[index];
if (index === 0) {
context.flags |= NodeBuilderFlags.InInitialEntityName;
}
const symbolName = getNameOfSymbolAsWritten(symbol, context);
if (index === 0) {
context.flags ^= NodeBuilderFlags.InInitialEntityName;
}
const identifier = setEmitFlags(createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping);
identifier.symbol = symbol;
return index > stopper ? createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1, stopper), identifier) : identifier;
}
}
function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: true): Identifier;
function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: false): EntityName;
function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: boolean): EntityName {
@@ -7246,7 +7277,7 @@ namespace ts {
/**
* Get type from type-reference that reference to class or interface
*/
function getTypeFromClassOrInterfaceReference(node: TypeReferenceType, symbol: Symbol, typeArgs: Type[]): Type {
function getTypeFromClassOrInterfaceReference(node: NodeWithTypeArguments, symbol: Symbol, typeArgs: Type[]): Type {
const type = <InterfaceType>getDeclaredTypeOfSymbol(getMergedSymbol(symbol));
const typeParameters = type.localTypeParameters;
if (typeParameters) {
@@ -7296,7 +7327,7 @@ namespace ts {
* references to the type parameters of the alias. We replace those with the actual type arguments by instantiating the
* declared type. Instantiations are cached using the type identities of the type arguments as the key.
*/
function getTypeFromTypeAliasReference(node: TypeReferenceType, symbol: Symbol, typeArguments: Type[]): Type {
function getTypeFromTypeAliasReference(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[]): Type {
const type = getDeclaredTypeOfSymbol(symbol);
const typeParameters = getSymbolLinks(symbol).typeParameters;
if (typeParameters) {
@@ -7342,7 +7373,7 @@ namespace ts {
return resolveEntityName(typeReferenceName, meaning) || unknownSymbol;
}
function getTypeReferenceType(node: TypeReferenceType, symbol: Symbol) {
function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol) {
const typeArguments = typeArgumentsFromTypeReferenceNode(node); // Do unconditionally so we mark type arguments as referenced.
if (symbol === unknownSymbol) {
return unknownType;
@@ -7380,7 +7411,7 @@ namespace ts {
return valueType;
}
function getTypeReferenceTypeWorker(node: TypeReferenceType, symbol: Symbol, typeArguments: Type[]): Type | undefined {
function getTypeReferenceTypeWorker(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[]): Type | undefined {
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
return getTypeFromClassOrInterfaceReference(node, symbol, typeArguments);
}
@@ -7428,13 +7459,13 @@ namespace ts {
return constraints ? getSubstitutionType(typeVariable, getIntersectionType(append(constraints, typeVariable))) : typeVariable;
}
function isJSDocTypeReference(node: TypeReferenceType): node is TypeReferenceNode {
function isJSDocTypeReference(node: NodeWithTypeArguments): node is TypeReferenceNode {
return node.flags & NodeFlags.JSDoc && node.kind === SyntaxKind.TypeReference;
}
function checkNoTypeArguments(node: TypeReferenceType, symbol?: Symbol) {
function checkNoTypeArguments(node: NodeWithTypeArguments, symbol?: Symbol) {
if (node.typeArguments) {
error(node, Diagnostics.Type_0_is_not_generic, symbol ? symbolToString(symbol) : declarationNameToString((<TypeReferenceNode>node).typeName));
error(node, Diagnostics.Type_0_is_not_generic, symbol ? symbolToString(symbol) : (<TypeReferenceNode>node).typeName ? declarationNameToString((<TypeReferenceNode>node).typeName) : "(anonymous)");
return false;
}
return true;
@@ -7515,7 +7546,7 @@ namespace ts {
return links.resolvedType;
}
function typeArgumentsFromTypeReferenceNode(node: TypeReferenceType): Type[] {
function typeArgumentsFromTypeReferenceNode(node: NodeWithTypeArguments): Type[] {
return map(node.typeArguments, getTypeFromTypeNode);
}
@@ -8479,6 +8510,79 @@ namespace ts {
return links.resolvedType;
}
function getIdentifierChain(node: EntityName): Identifier[] {
if (isIdentifier(node)) {
return [node];
}
else {
return append(getIdentifierChain(node.left), node.right);
}
}
function getTypeFromImportTypeNode(node: ImportTypeNode): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
if (node.isTypeOf && node.typeArguments) { // Only the non-typeof form can make use of type arguments
error(node, Diagnostics.Type_arguments_cannot_be_used_here);
links.resolvedSymbol = unknownSymbol;
return links.resolvedType = unknownType;
}
if (!isLiteralImportTypeNode(node)) {
error(node.argument, Diagnostics.String_literal_expected);
links.resolvedSymbol = unknownSymbol;
return links.resolvedType = unknownType;
}
const argumentType = getTypeFromTypeNode(node.argument);
const targetMeaning = node.isTypeOf ? SymbolFlags.Value : SymbolFlags.Type;
// TODO: Future work: support unions/generics/whatever via a deferred import-type
const moduleName = (argumentType as StringLiteralType).value;
const innerModuleSymbol = resolveExternalModule(node, moduleName, Diagnostics.Cannot_find_module_0, node, /*isForAugmentation*/ false);
if (!innerModuleSymbol) {
links.resolvedSymbol = unknownSymbol;
return links.resolvedType = unknownType;
}
const moduleSymbol = resolveExternalModuleSymbol(innerModuleSymbol, /*dontResolveAlias*/ false);
if (node.qualifier) {
const nameStack: Identifier[] = getIdentifierChain(node.qualifier);
let currentNamespace = moduleSymbol;
let current: Identifier | undefined;
while (current = nameStack.shift()) {
const meaning = nameStack.length ? SymbolFlags.Namespace : targetMeaning;
const next = getSymbol(getExportsOfSymbol(getMergedSymbol(resolveSymbol(currentNamespace))), current.escapedText, meaning);
if (!next) {
error(current, Diagnostics.Namespace_0_has_no_exported_member_1, getFullyQualifiedName(currentNamespace), declarationNameToString(current));
return links.resolvedType = unknownType;
}
getNodeLinks(current).resolvedSymbol = next;
getNodeLinks(current.parent).resolvedSymbol = next;
currentNamespace = next;
}
resolveImportSymbolType(node, links, currentNamespace, targetMeaning);
}
else {
if (moduleSymbol.flags & targetMeaning) {
resolveImportSymbolType(node, links, moduleSymbol, targetMeaning);
}
else {
error(node, targetMeaning === SymbolFlags.Value ? Diagnostics.Module_0_does_not_refer_to_a_value_but_is_used_as_a_value_here : Diagnostics.Module_0_does_not_refer_to_a_type_but_is_used_as_a_type_here, moduleName);
links.resolvedSymbol = unknownSymbol;
links.resolvedType = unknownType;
}
}
}
return links.resolvedType;
}
function resolveImportSymbolType(node: ImportTypeNode, links: NodeLinks, symbol: Symbol, meaning: SymbolFlags) {
links.resolvedSymbol = symbol;
if (meaning === SymbolFlags.Value) {
return links.resolvedType = getTypeOfSymbol(symbol);
}
else {
return links.resolvedType = getTypeReferenceType(node, symbol);
}
}
function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: TypeNode): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
@@ -8772,6 +8876,8 @@ namespace ts {
return getTypeFromConditionalTypeNode(<ConditionalTypeNode>node);
case SyntaxKind.InferType:
return getTypeFromInferTypeNode(<InferTypeNode>node);
case SyntaxKind.ImportTypeNode:
return getTypeFromImportTypeNode(<ImportTypeNode>node);
// This function assumes that an identifier or qualified name is a type expression
// Callers should first ensure this by calling isTypeNode
case SyntaxKind.Identifier:
@@ -20756,6 +20862,11 @@ namespace ts {
checkSourceElement(node.typeParameter);
}
function checkImportType(node: ImportTypeNode) {
checkSourceElement(node.argument);
getTypeFromTypeNode(node);
}
function isPrivateWithinAmbient(node: Node): boolean {
return hasModifier(node, ModifierFlags.Private) && !!(node.flags & NodeFlags.Ambient);
}
@@ -24483,6 +24594,8 @@ namespace ts {
return checkConditionalType(<ConditionalTypeNode>node);
case SyntaxKind.InferType:
return checkInferType(<InferTypeNode>node);
case SyntaxKind.ImportTypeNode:
return checkImportType(<ImportTypeNode>node);
case SyntaxKind.JSDocAugmentsTag:
return checkJSDocAugmentsTag(node as JSDocAugmentsTag);
case SyntaxKind.JSDocTypedefTag:
@@ -24993,6 +25106,18 @@ namespace ts {
}
}
function isImportTypeQualifierPart(node: EntityName): ImportTypeNode | undefined {
let parent = node.parent;
while (isQualifiedName(parent)) {
node = parent;
parent = parent.parent;
}
if (parent && parent.kind === SyntaxKind.ImportTypeNode && (parent as ImportTypeNode).qualifier === node) {
return parent as ImportTypeNode;
}
return undefined;
}
function getSymbolOfEntityNameOrPropertyAccessExpression(entityName: EntityName | PropertyAccessExpression): Symbol | undefined {
if (isDeclarationName(entityName)) {
return getSymbolOfNode(entityName.parent);
@@ -25016,13 +25141,23 @@ namespace ts {
return success;
}
}
else if (entityName.kind !== SyntaxKind.PropertyAccessExpression && isInRightSideOfImportOrExportAssignment(entityName)) {
else if (!isPropertyAccessExpression(entityName) && isInRightSideOfImportOrExportAssignment(entityName)) {
// Since we already checked for ExportAssignment, this really could only be an Import
const importEqualsDeclaration = getAncestor(entityName, SyntaxKind.ImportEqualsDeclaration);
Debug.assert(importEqualsDeclaration !== undefined);
return getSymbolOfPartOfRightHandSideOfImportEquals(entityName, /*dontResolveAlias*/ true);
}
if (isRightSideOfQualifiedNameOrPropertyAccess(entityName)) {
if (!isPropertyAccessExpression(entityName)) {
const possibleImportNode = isImportTypeQualifierPart(entityName);
if (possibleImportNode) {
getTypeFromTypeNode(possibleImportNode);
const sym = getNodeLinks(entityName).resolvedSymbol;
return sym === unknownSymbol ? undefined : sym;
}
}
while (isRightSideOfQualifiedNameOrPropertyAccess(entityName)) {
entityName = <QualifiedName | PropertyAccessEntityNameExpression>entityName.parent;
}
@@ -25175,9 +25310,12 @@ namespace ts {
// 1). import x = require("./mo/*gotToDefinitionHere*/d")
// 2). External module name in an import declaration
// 3). Dynamic import call or require in javascript
// 4). type A = import("./f/*gotToDefinitionHere*/oo")
if ((isExternalModuleImportEqualsDeclaration(node.parent.parent) && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node) ||
((node.parent.kind === SyntaxKind.ImportDeclaration || node.parent.kind === SyntaxKind.ExportDeclaration) && (<ImportDeclaration>node.parent).moduleSpecifier === node) ||
((isInJavaScriptFile(node) && isRequireCall(node.parent, /*checkArgumentIsStringLiteralLike*/ false)) || isImportCall(node.parent))) {
((isInJavaScriptFile(node) && isRequireCall(node.parent, /*checkArgumentIsStringLiteralLike*/ false)) || isImportCall(node.parent)) ||
(isLiteralTypeNode(node.parent) && isLiteralImportTypeNode(node.parent.parent) && node.parent.parent.argument === node.parent)
) {
return resolveExternalModuleName(node, <LiteralExpression>node);
}
// falls through
@@ -26022,7 +26160,7 @@ namespace ts {
}
}
function getExternalModuleFileFromDeclaration(declaration: AnyImportOrReExport | ModuleDeclaration): SourceFile {
function getExternalModuleFileFromDeclaration(declaration: AnyImportOrReExport | ModuleDeclaration | ImportTypeNode): SourceFile {
const specifier = declaration.kind === SyntaxKind.ModuleDeclaration ? tryCast(declaration.name, isStringLiteral) : getExternalModuleName(declaration);
const moduleSymbol = resolveExternalModuleNameWorker(specifier, specifier, /*moduleNotFoundError*/ undefined);
if (!moduleSymbol) {
+12
View File
@@ -955,6 +955,18 @@
"category": "Error",
"code": 1338
},
"Module '{0}' does not refer to a value, but is used as a value here.": {
"category": "Error",
"code": 1339
},
"Module '{0}' does not refer to a type, but is used as a type here.": {
"category": "Error",
"code": 1340
},
"Type arguments cannot be used here.": {
"category": "Error",
"code": 1342
},
"Duplicate identifier '{0}'.": {
"category": "Error",
+18
View File
@@ -615,6 +615,8 @@ namespace ts {
return emitMappedType(<MappedTypeNode>node);
case SyntaxKind.LiteralType:
return emitLiteralType(<LiteralTypeNode>node);
case SyntaxKind.ImportTypeNode:
return emitImportTypeNode(<ImportTypeNode>node);
case SyntaxKind.JSDocAllType:
write("*");
return;
@@ -1327,6 +1329,22 @@ namespace ts {
emitExpression(node.literal);
}
function emitImportTypeNode(node: ImportTypeNode) {
if (node.isTypeOf) {
writeKeyword("typeof");
writeSpace();
}
writeKeyword("import");
writePunctuation("(");
emit(node.argument);
writePunctuation(")");
if (node.qualifier) {
writePunctuation(".");
emit(node.qualifier);
}
emitTypeArguments(node, node.typeArguments);
}
//
// Binding patterns
//
+18
View File
@@ -809,6 +809,24 @@ namespace ts {
: node;
}
export function createImportTypeNode(argument: TypeNode, qualifier?: EntityName, typeArguments?: ReadonlyArray<TypeNode>, isTypeOf?: boolean) {
const node = <ImportTypeNode>createSynthesizedNode(SyntaxKind.ImportTypeNode);
node.argument = argument;
node.qualifier = qualifier;
node.typeArguments = asNodeArray(typeArguments);
node.isTypeOf = isTypeOf;
return node;
}
export function updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, qualifier?: EntityName, typeArguments?: ReadonlyArray<TypeNode>, isTypeOf?: boolean) {
return node.argument !== argument
|| node.qualifier !== qualifier
|| node.typeArguments !== typeArguments
|| node.isTypeOf !== isTypeOf
? updateNode(createImportTypeNode(argument, qualifier, typeArguments, isTypeOf), node)
: node;
}
export function createParenthesizedType(type: TypeNode) {
const node = <ParenthesizedTypeNode>createSynthesizedNode(SyntaxKind.ParenthesizedType);
node.type = type;
+30 -1
View File
@@ -189,6 +189,10 @@ namespace ts {
visitNode(cbNode, (<ConditionalTypeNode>node).falseType);
case SyntaxKind.InferType:
return visitNode(cbNode, (<InferTypeNode>node).typeParameter);
case SyntaxKind.ImportTypeNode:
return visitNode(cbNode, (<ImportTypeNode>node).argument) ||
visitNode(cbNode, (<ImportTypeNode>node).qualifier) ||
visitNodes(cbNode, cbNodes, (<ImportTypeNode>node).typeArguments);
case SyntaxKind.ParenthesizedType:
case SyntaxKind.TypeOperator:
return visitNode(cbNode, (<ParenthesizedTypeNode | TypeOperatorNode>node).type);
@@ -2733,6 +2737,28 @@ namespace ts {
return finishNode(node);
}
function isStartOfTypeOfImportType() {
nextToken();
return token() === SyntaxKind.ImportKeyword;
}
function parseImportType(): ImportTypeNode {
sourceFile.flags |= NodeFlags.PossiblyContainsDynamicImport;
const node = createNode(SyntaxKind.ImportTypeNode) as ImportTypeNode;
if (parseOptional(SyntaxKind.TypeOfKeyword)) {
node.isTypeOf = true;
}
parseExpected(SyntaxKind.ImportKeyword);
parseExpected(SyntaxKind.OpenParenToken);
node.argument = parseType();
parseExpected(SyntaxKind.CloseParenToken);
if (parseOptional(SyntaxKind.DotToken)) {
node.qualifier = parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected);
}
node.typeArguments = tryParseTypeArguments();
return finishNode(node);
}
function nextTokenIsNumericLiteral() {
return nextToken() === SyntaxKind.NumericLiteral;
}
@@ -2780,13 +2806,15 @@ namespace ts {
}
}
case SyntaxKind.TypeOfKeyword:
return parseTypeQuery();
return lookAhead(isStartOfTypeOfImportType) ? parseImportType() : parseTypeQuery();
case SyntaxKind.OpenBraceToken:
return lookAhead(isStartOfMappedType) ? parseMappedType() : parseTypeLiteral();
case SyntaxKind.OpenBracketToken:
return parseTupleType();
case SyntaxKind.OpenParenToken:
return parseParenthesizedType();
case SyntaxKind.ImportKeyword:
return parseImportType();
default:
return parseTypeReference();
}
@@ -2822,6 +2850,7 @@ namespace ts {
case SyntaxKind.ExclamationToken:
case SyntaxKind.DotDotDotToken:
case SyntaxKind.InferKeyword:
case SyntaxKind.ImportKeyword:
return true;
case SyntaxKind.MinusToken:
return !inStartOfParameter && lookAhead(nextTokenIsNumericLiteral);
+12 -2
View File
@@ -1686,9 +1686,19 @@ namespace ts {
else if (isImportCall(node) && node.arguments.length === 1 && isStringLiteralLike(node.arguments[0])) {
imports = append(imports, node.arguments[0] as StringLiteralLike);
}
else {
forEachChild(node, collectDynamicImportOrRequireCalls);
else if (isLiteralImportTypeNode(node)) {
imports = append(imports, node.argument.literal);
}
else {
collectDynamicImportOrRequireCallsForEachChild(node);
if (hasJSDocNodes(node)) {
forEach(node.jsDoc, collectDynamicImportOrRequireCallsForEachChild);
}
}
}
function collectDynamicImportOrRequireCallsForEachChild(node: Node) {
forEachChild(node, collectDynamicImportOrRequireCalls);
}
}
+15 -3
View File
@@ -450,9 +450,9 @@ namespace ts {
return setCommentRange(updated, getCommentRange(original));
}
function rewriteModuleSpecifier<T extends Node>(parent: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration, input: T): T | StringLiteral {
function rewriteModuleSpecifier<T extends Node>(parent: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode, input: T): T | StringLiteral {
if (!input) return;
resultHasExternalModuleIndicator = resultHasExternalModuleIndicator || parent.kind !== SyntaxKind.ModuleDeclaration;
resultHasExternalModuleIndicator = resultHasExternalModuleIndicator || (parent.kind !== SyntaxKind.ModuleDeclaration && parent.kind !== SyntaxKind.ImportTypeNode);
if (input.kind === SyntaxKind.StringLiteral && isBundledEmit) {
const newName = getExternalModuleNameFromDeclaration(context.getEmitHost(), resolver, parent);
if (newName) {
@@ -765,6 +765,16 @@ namespace ts {
case SyntaxKind.ConstructorType: {
return cleanup(updateConstructorTypeNode(input, visitNodes(input.typeParameters, visitDeclarationSubtree), updateParamsList(input, input.parameters), visitNode(input.type, visitDeclarationSubtree)));
}
case SyntaxKind.ImportTypeNode: {
if (!isLiteralImportTypeNode(input)) return cleanup(input);
return cleanup(updateImportTypeNode(
input,
updateLiteralTypeNode(input.argument, rewriteModuleSpecifier(input, input.argument.literal)),
input.qualifier,
visitNodes(input.typeArguments, visitDeclarationSubtree, isTypeNode),
input.isTypeOf
));
}
default: Debug.assertNever(input, `Attempted to process unhandled node kind: ${(ts as any).SyntaxKind[(input as any).kind]}`);
}
}
@@ -1264,7 +1274,8 @@ namespace ts {
| TypeReferenceNode
| ConditionalTypeNode
| FunctionTypeNode
| ConstructorTypeNode;
| ConstructorTypeNode
| ImportTypeNode;
function isProcessedComponent(node: Node): node is ProcessedComponent {
switch (node.kind) {
@@ -1285,6 +1296,7 @@ namespace ts {
case SyntaxKind.ConditionalType:
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructorType:
case SyntaxKind.ImportTypeNode:
return true;
}
return false;
+19 -6
View File
@@ -284,6 +284,7 @@ namespace ts {
IndexedAccessType,
MappedType,
LiteralType,
ImportTypeNode,
// Binding patterns
ObjectBindingPattern,
ArrayBindingPattern,
@@ -445,7 +446,7 @@ namespace ts {
FirstFutureReservedWord = ImplementsKeyword,
LastFutureReservedWord = YieldKeyword,
FirstTypeNode = TypePredicate,
LastTypeNode = LiteralType,
LastTypeNode = ImportTypeNode,
FirstPunctuation = OpenBraceToken,
LastPunctuation = CaretEqualsToken,
FirstToken = Unknown,
@@ -1067,6 +1068,16 @@ namespace ts {
| SyntaxKind.NeverKeyword;
}
export interface ImportTypeNode extends NodeWithTypeArguments {
kind: SyntaxKind.ImportTypeNode;
isTypeOf?: boolean;
argument: TypeNode;
qualifier?: EntityName;
}
/* @internal */
export type LiteralImportTypeNode = ImportTypeNode & { argument: LiteralTypeNode & { literal: StringLiteral } };
export interface ThisTypeNode extends TypeNode {
kind: SyntaxKind.ThisType;
}
@@ -1081,12 +1092,15 @@ namespace ts {
kind: SyntaxKind.ConstructorType;
}
export interface NodeWithTypeArguments extends TypeNode {
typeArguments?: NodeArray<TypeNode>;
}
export type TypeReferenceType = TypeReferenceNode | ExpressionWithTypeArguments;
export interface TypeReferenceNode extends TypeNode {
export interface TypeReferenceNode extends NodeWithTypeArguments {
kind: SyntaxKind.TypeReference;
typeName: EntityName;
typeArguments?: NodeArray<TypeNode>;
}
export interface TypePredicateNode extends TypeNode {
@@ -1696,11 +1710,10 @@ namespace ts {
expression: ImportExpression;
}
export interface ExpressionWithTypeArguments extends TypeNode {
export interface ExpressionWithTypeArguments extends NodeWithTypeArguments {
kind: SyntaxKind.ExpressionWithTypeArguments;
parent?: HeritageClause;
expression: LeftHandSideExpression;
typeArguments?: NodeArray<TypeNode>;
}
export interface NewExpression extends PrimaryExpression, Declaration {
@@ -3244,7 +3257,7 @@ namespace ts {
isOptionalParameter(node: ParameterDeclaration): boolean;
moduleExportsSomeValue(moduleReferenceExpression: Expression): boolean;
isArgumentsLocalBinding(node: Identifier): boolean;
getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration): SourceFile;
getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode): SourceFile;
getTypeReferenceDirectivesForEntityName(name: EntityNameOrEntityNameExpression): string[];
getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): string[];
isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean;
+10 -2
View File
@@ -734,6 +734,12 @@ namespace ts {
return n.kind === SyntaxKind.CallExpression && (<CallExpression>n).expression.kind === SyntaxKind.ImportKeyword;
}
export function isLiteralImportTypeNode(n: Node): n is LiteralImportTypeNode {
return n.kind === SyntaxKind.ImportTypeNode &&
(n as ImportTypeNode).argument.kind === SyntaxKind.LiteralType &&
isStringLiteral(((n as ImportTypeNode).argument as LiteralTypeNode).literal);
}
export function isPrologueDirective(node: Node): node is PrologueDirective {
return node.kind === SyntaxKind.ExpressionStatement
&& (<ExpressionStatement>node).expression.kind === SyntaxKind.StringLiteral;
@@ -1697,13 +1703,15 @@ namespace ts {
}
}
export function getExternalModuleName(node: AnyImportOrReExport): Expression {
export function getExternalModuleName(node: AnyImportOrReExport | ImportTypeNode): Expression {
switch (node.kind) {
case SyntaxKind.ImportDeclaration:
case SyntaxKind.ExportDeclaration:
return node.moduleSpecifier;
case SyntaxKind.ImportEqualsDeclaration:
return node.moduleReference.kind === SyntaxKind.ExternalModuleReference ? node.moduleReference.expression : undefined;
case SyntaxKind.ImportTypeNode:
return isLiteralImportTypeNode(node) ? node.argument.literal : undefined;
default:
return Debug.assertNever(node);
}
@@ -2809,7 +2817,7 @@ namespace ts {
return file.moduleName || getExternalModuleNameFromPath(host, file.fileName);
}
export function getExternalModuleNameFromDeclaration(host: EmitHost, resolver: EmitResolver, declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration): string {
export function getExternalModuleNameFromDeclaration(host: EmitHost, resolver: EmitResolver, declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode): string {
const file = resolver.getExternalModuleFileFromDeclaration(declaration);
if (!file || file.isDeclarationFile) {
return undefined;
+8
View File
@@ -398,6 +398,14 @@ namespace ts {
return updateInferTypeNode(<InferTypeNode>node,
visitNode((<InferTypeNode>node).typeParameter, visitor, isTypeParameterDeclaration));
case SyntaxKind.ImportTypeNode:
return updateImportTypeNode(<ImportTypeNode>node,
visitNode((<ImportTypeNode>node).argument, visitor, isTypeNode),
visitNode((<ImportTypeNode>node).qualifier, visitor, isEntityName),
visitNodes((<ImportTypeNode>node).typeArguments, visitor, isTypeNode),
(<ImportTypeNode>node).isTypeOf
);
case SyntaxKind.ParenthesizedType:
return updateParenthesizedType(<ParenthesizedTypeNode>node,
visitNode((<ParenthesizedTypeNode>node).type, visitor, isTypeNode));