From 7e9cb46a1ace774a29b34b928db0fd46c72a9b99 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Thu, 2 Jun 2016 09:15:48 -0700 Subject: [PATCH 1/6] Support shorthand ambient module declarations --- src/compiler/binder.ts | 5 ++-- src/compiler/checker.ts | 26 ++++++++++++++----- src/compiler/declarationEmitter.ts | 25 +++++++++++------- src/compiler/emitter.ts | 3 ++- src/compiler/parser.ts | 9 ++++++- src/compiler/program.ts | 9 ++++--- src/compiler/types.ts | 2 +- src/compiler/utilities.ts | 5 ++++ src/services/navigationBar.ts | 10 ++++--- src/services/services.ts | 2 +- tests/baselines/reference/ambientShorthand.js | 24 +++++++++++++++++ .../reference/ambientShorthand.symbols | 20 ++++++++++++++ .../reference/ambientShorthand.types | 21 +++++++++++++++ .../ambientShorthand_declarationEmit.js | 9 +++++++ .../ambientShorthand_declarationEmit.symbols | 4 +++ .../ambientShorthand_declarationEmit.types | 4 +++ .../conformance/ambient/ambientShorthand.ts | 10 +++++++ .../ambientShorthand_declarationEmit.ts | 2 ++ 18 files changed, 162 insertions(+), 28 deletions(-) create mode 100644 tests/baselines/reference/ambientShorthand.js create mode 100644 tests/baselines/reference/ambientShorthand.symbols create mode 100644 tests/baselines/reference/ambientShorthand.types create mode 100644 tests/baselines/reference/ambientShorthand_declarationEmit.js create mode 100644 tests/baselines/reference/ambientShorthand_declarationEmit.symbols create mode 100644 tests/baselines/reference/ambientShorthand_declarationEmit.types create mode 100644 tests/cases/conformance/ambient/ambientShorthand.ts create mode 100644 tests/cases/conformance/ambient/ambientShorthand_declarationEmit.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 5fdfc7f02be..d6ede3049c2 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -53,7 +53,8 @@ namespace ts { return state; } else if (node.kind === SyntaxKind.ModuleDeclaration) { - return getModuleInstanceState((node).body); + const body = (node).body; + return body ? getModuleInstanceState(body) : ModuleInstanceState.NonInstantiated; } else { return ModuleInstanceState.Instantiated; @@ -1256,7 +1257,7 @@ namespace ts { function hasExportDeclarations(node: ModuleDeclaration | SourceFile): boolean { const body = node.kind === SyntaxKind.SourceFile ? node : (node).body; - if (body.kind === SyntaxKind.SourceFile || body.kind === SyntaxKind.ModuleBlock) { + if (body && (body.kind === SyntaxKind.SourceFile || body.kind === SyntaxKind.ModuleBlock)) { for (const stat of (body).statements) { if (stat.kind === SyntaxKind.ExportDeclaration || stat.kind === SyntaxKind.ExportAssignment) { return true; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 06ef2463402..50f1ce0d208 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -380,6 +380,7 @@ namespace ts { } function mergeSymbol(target: Symbol, source: Symbol) { + //TODO: how to merge w/ shorthand ambient module? if (!(target.flags & getExcludedSymbolFlags(source.flags))) { if (source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule && target.constEnumOnlyModule && !source.constEnumOnlyModule) { // reset flag when merging instantiated module into value module that has only const enums @@ -986,7 +987,9 @@ namespace ts { const moduleSymbol = resolveExternalModuleName(node, (node.parent).moduleSpecifier); if (moduleSymbol) { - const exportDefaultSymbol = moduleSymbol.exports["export="] ? + const exportDefaultSymbol = isShorthandAmbientModule(moduleSymbol.valueDeclaration) ? + moduleSymbol : + moduleSymbol.exports["export="] ? getPropertyOfType(getTypeOfSymbol(moduleSymbol.exports["export="]), "default") : resolveSymbol(moduleSymbol.exports["default"]); @@ -1060,6 +1063,10 @@ namespace ts { if (targetSymbol) { const name = specifier.propertyName || specifier.name; if (name.text) { + if (isShorthandAmbientModule(moduleSymbol.valueDeclaration)) { + return moduleSymbol; + } + let symbolFromVariable: Symbol; // First check if module was specified with "export=". If so, get the member from the resolved type if (moduleSymbol && moduleSymbol.exports && moduleSymbol.exports["export="]) { @@ -3220,9 +3227,14 @@ namespace ts { function getTypeOfFuncClassEnumModule(symbol: Symbol): Type { const links = getSymbolLinks(symbol); if (!links.type) { - const type = createObjectType(TypeFlags.Anonymous, symbol); - links.type = strictNullChecks && symbol.flags & SymbolFlags.Optional ? - addNullableKind(type, TypeFlags.Undefined) : type; + if (symbol.valueDeclaration.kind === SyntaxKind.ModuleDeclaration && isShorthandAmbientModule(symbol.valueDeclaration)) { + links.type = anyType; + } + else { + const type = createObjectType(TypeFlags.Anonymous, symbol); + links.type = strictNullChecks && symbol.flags & SymbolFlags.Optional ? + addNullableKind(type, TypeFlags.Undefined) : type; + } } return links.type; } @@ -16010,7 +16022,7 @@ namespace ts { // - augmentation for a global scope is always applied // - augmentation for some external module is applied if symbol for augmentation is merged (it was combined with target module). const checkBody = isGlobalAugmentation || (getSymbolOfNode(node).flags & SymbolFlags.Merged); - if (checkBody) { + if (checkBody && node.body) { // body of ambient external module is always a module block for (const statement of (node.body).statements) { checkModuleAugmentationElement(statement, isGlobalAugmentation); @@ -16037,7 +16049,9 @@ namespace ts { } } } - checkSourceElement(node.body); + if (node.body) { + checkSourceElement(node.body); + } } function checkModuleAugmentationElement(node: Node, isGlobalAugmentation: boolean): void { diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 397b135bf23..f44298a4206 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -853,21 +853,26 @@ namespace ts { writeTextOfNode(currentText, node.name); } } - while (node.body.kind !== SyntaxKind.ModuleBlock) { + while (node.body && node.body.kind !== SyntaxKind.ModuleBlock) { node = node.body; write("."); writeTextOfNode(currentText, node.name); } const prevEnclosingDeclaration = enclosingDeclaration; - enclosingDeclaration = node; - write(" {"); - writeLine(); - increaseIndent(); - emitLines((node.body).statements); - decreaseIndent(); - write("}"); - writeLine(); - enclosingDeclaration = prevEnclosingDeclaration; + if (node.body) { + enclosingDeclaration = node; + write(" {"); + writeLine(); + increaseIndent(); + emitLines((node.body).statements); + decreaseIndent(); + write("}"); + writeLine(); + enclosingDeclaration = prevEnclosingDeclaration; + } + else { + write(";"); + } } function writeTypeAliasDeclaration(node: TypeAliasDeclaration) { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index f225b4cacf8..88895531d16 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -6246,7 +6246,7 @@ const _super = (function (geti, seti) { } function getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration: ModuleDeclaration): ModuleDeclaration { - if (moduleDeclaration.body.kind === SyntaxKind.ModuleDeclaration) { + if (moduleDeclaration.body && moduleDeclaration.body.kind === SyntaxKind.ModuleDeclaration) { const recursiveInnerModule = getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration.body); return recursiveInnerModule || moduleDeclaration.body; } @@ -6295,6 +6295,7 @@ const _super = (function (geti, seti) { write(getGeneratedNameForNode(node)); emitEnd(node.name); write(") "); + // node.body must exist, as this is a non-ambient module if (node.body.kind === SyntaxKind.ModuleBlock) { const saveConvertedLoopState = convertedLoopState; const saveTempFlags = tempFlags; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 6f042627c6b..8af258ebfc8 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -5330,7 +5330,14 @@ namespace ts { else { node.name = parseLiteralNode(/*internName*/ true); } - node.body = parseModuleBlock(); + + if (token === SyntaxKind.OpenBraceToken) { + node.body = parseModuleBlock(); + } + else { + parseSemicolon(); + } + return finishNode(node); } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index bab554927e7..d94e25c786e 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1712,9 +1712,12 @@ namespace ts { // The StringLiteral must specify a top - level external module name. // Relative external module names are not permitted - // NOTE: body of ambient module is always a module block - for (const statement of ((node).body).statements) { - collectModuleReferences(statement, /*inAmbientModule*/ true); + // NOTE: body of ambient module is always a module block, if it exists + const body = (node).body; + if (body) { + for (const statement of body.statements) { + collectModuleReferences(statement, /*inAmbientModule*/ true); + } } } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c7e14a10031..5f56c017c7e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1301,7 +1301,7 @@ namespace ts { // @kind(SyntaxKind.ModuleDeclaration) export interface ModuleDeclaration extends DeclarationStatement { name: Identifier | LiteralExpression; - body: ModuleBlock | ModuleDeclaration; + body?: ModuleBlock | ModuleDeclaration; } // @kind(SyntaxKind.ModuleBlock) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 74ea3459b23..56de65b5dc0 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -372,6 +372,11 @@ namespace ts { ((node).name.kind === SyntaxKind.StringLiteral || isGlobalScopeAugmentation(node)); } + export function isShorthandAmbientModule(node: Node): boolean { + // The only kind of module that can be missing a body is a shorthand ambient module. + return node.kind === SyntaxKind.ModuleDeclaration && (!(node).body); + } + export function isBlockScopedContainerTopLevel(node: Node): boolean { return node.kind === SyntaxKind.SourceFile || node.kind === SyntaxKind.ModuleDeclaration || diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index 92cf64eac94..59dc4a38283 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -188,7 +188,10 @@ namespace ts.NavigationBar { case SyntaxKind.ModuleDeclaration: let moduleDeclaration = node; topLevelNodes.push(node); - addTopLevelNodes((getInnermostModule(moduleDeclaration).body).statements, topLevelNodes); + const inner = getInnermostModule(moduleDeclaration); + if (inner.body) { + addTopLevelNodes((inner.body).statements, topLevelNodes); + } break; case SyntaxKind.FunctionDeclaration: @@ -453,7 +456,8 @@ namespace ts.NavigationBar { function createModuleItem(node: ModuleDeclaration): NavigationBarItem { const moduleName = getModuleName(node); - const childItems = getItemsWorker(getChildNodes((getInnermostModule(node).body).statements), createChildItem); + const body = getInnermostModule(node).body; + const childItems = body ? getItemsWorker(getChildNodes(body.statements), createChildItem) : []; return getNavigationBarItem(moduleName, ts.ScriptElementKind.moduleElement, @@ -611,7 +615,7 @@ namespace ts.NavigationBar { } function getInnermostModule(node: ModuleDeclaration): ModuleDeclaration { - while (node.body.kind === SyntaxKind.ModuleDeclaration) { + while (node.body && node.body.kind === SyntaxKind.ModuleDeclaration) { node = node.body; } diff --git a/src/services/services.ts b/src/services/services.ts index 90740b257c6..6bc40b80b31 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -415,7 +415,7 @@ namespace ts { } // If this is left side of dotted module declaration, there is no doc comments associated with this node - if (declaration.kind === SyntaxKind.ModuleDeclaration && (declaration).body.kind === SyntaxKind.ModuleDeclaration) { + if (declaration.kind === SyntaxKind.ModuleDeclaration && (declaration).body && (declaration).body.kind === SyntaxKind.ModuleDeclaration) { return; } diff --git a/tests/baselines/reference/ambientShorthand.js b/tests/baselines/reference/ambientShorthand.js new file mode 100644 index 00000000000..76a3b482994 --- /dev/null +++ b/tests/baselines/reference/ambientShorthand.js @@ -0,0 +1,24 @@ +//// [tests/cases/conformance/ambient/ambientShorthand.ts] //// + +//// [declarations.d.ts] +declare module "jquery" +// Semicolon is optional +declare module "fs"; + +//// [user.ts] +/// +import foo, {bar} from "jquery"; +import * as baz from "fs"; +foo(bar, baz); + + +//// [user.js] +"use strict"; +/// +var jquery_1 = require("jquery"); +var baz = require("fs"); +jquery_1["default"](jquery_1.bar, baz); + + +//// [user.d.ts] +/// diff --git a/tests/baselines/reference/ambientShorthand.symbols b/tests/baselines/reference/ambientShorthand.symbols new file mode 100644 index 00000000000..91cefe8d4c4 --- /dev/null +++ b/tests/baselines/reference/ambientShorthand.symbols @@ -0,0 +1,20 @@ +=== tests/cases/conformance/ambient/user.ts === +/// +import foo, {bar} from "jquery"; +>foo : Symbol(foo, Decl(user.ts, 1, 6)) +>bar : Symbol(bar, Decl(user.ts, 1, 13)) + +import * as baz from "fs"; +>baz : Symbol(baz, Decl(user.ts, 2, 6)) + +foo(bar, baz); +>foo : Symbol(foo, Decl(user.ts, 1, 6)) +>bar : Symbol(bar, Decl(user.ts, 1, 13)) +>baz : Symbol(baz, Decl(user.ts, 2, 6)) + +=== tests/cases/conformance/ambient/declarations.d.ts === +declare module "jquery" +No type information for this code.// Semicolon is optional +No type information for this code.declare module "fs"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/ambientShorthand.types b/tests/baselines/reference/ambientShorthand.types new file mode 100644 index 00000000000..12b18953e88 --- /dev/null +++ b/tests/baselines/reference/ambientShorthand.types @@ -0,0 +1,21 @@ +=== tests/cases/conformance/ambient/user.ts === +/// +import foo, {bar} from "jquery"; +>foo : any +>bar : any + +import * as baz from "fs"; +>baz : any + +foo(bar, baz); +>foo(bar, baz) : any +>foo : any +>bar : any +>baz : any + +=== tests/cases/conformance/ambient/declarations.d.ts === +declare module "jquery" +No type information for this code.// Semicolon is optional +No type information for this code.declare module "fs"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/ambientShorthand_declarationEmit.js b/tests/baselines/reference/ambientShorthand_declarationEmit.js new file mode 100644 index 00000000000..d758b57efd2 --- /dev/null +++ b/tests/baselines/reference/ambientShorthand_declarationEmit.js @@ -0,0 +1,9 @@ +//// [ambientShorthand_declarationEmit.ts] +declare module "foo"; + + +//// [ambientShorthand_declarationEmit.js] + + +//// [ambientShorthand_declarationEmit.d.ts] +declare module "foo"; \ No newline at end of file diff --git a/tests/baselines/reference/ambientShorthand_declarationEmit.symbols b/tests/baselines/reference/ambientShorthand_declarationEmit.symbols new file mode 100644 index 00000000000..f1b3284b0f2 --- /dev/null +++ b/tests/baselines/reference/ambientShorthand_declarationEmit.symbols @@ -0,0 +1,4 @@ +=== tests/cases/conformance/ambient/ambientShorthand_declarationEmit.ts === +declare module "foo"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/ambientShorthand_declarationEmit.types b/tests/baselines/reference/ambientShorthand_declarationEmit.types new file mode 100644 index 00000000000..f1b3284b0f2 --- /dev/null +++ b/tests/baselines/reference/ambientShorthand_declarationEmit.types @@ -0,0 +1,4 @@ +=== tests/cases/conformance/ambient/ambientShorthand_declarationEmit.ts === +declare module "foo"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/cases/conformance/ambient/ambientShorthand.ts b/tests/cases/conformance/ambient/ambientShorthand.ts new file mode 100644 index 00000000000..3070abff595 --- /dev/null +++ b/tests/cases/conformance/ambient/ambientShorthand.ts @@ -0,0 +1,10 @@ +// @Filename: declarations.d.ts +declare module "jquery" +// Semicolon is optional +declare module "fs"; + +// @Filename: user.ts +/// +import foo, {bar} from "jquery"; +import * as baz from "fs"; +foo(bar, baz); diff --git a/tests/cases/conformance/ambient/ambientShorthand_declarationEmit.ts b/tests/cases/conformance/ambient/ambientShorthand_declarationEmit.ts new file mode 100644 index 00000000000..13053868e5b --- /dev/null +++ b/tests/cases/conformance/ambient/ambientShorthand_declarationEmit.ts @@ -0,0 +1,2 @@ +// @declaration: true +declare module "foo"; From 1541ebe781d5c0f27a4c0195720c5b63f4dda647 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 3 Jun 2016 06:34:33 -0700 Subject: [PATCH 2/6] Respond to PR comments --- src/compiler/binder.ts | 2 +- src/compiler/emitter.ts | 2 +- tests/baselines/reference/ambientShorthand.js | 4 ---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index d6ede3049c2..0b678537208 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -54,7 +54,7 @@ namespace ts { } else if (node.kind === SyntaxKind.ModuleDeclaration) { const body = (node).body; - return body ? getModuleInstanceState(body) : ModuleInstanceState.NonInstantiated; + return body ? getModuleInstanceState(body) : ModuleInstanceState.Instantiated; } else { return ModuleInstanceState.Instantiated; diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 88895531d16..e86f13b5676 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -6295,7 +6295,7 @@ const _super = (function (geti, seti) { write(getGeneratedNameForNode(node)); emitEnd(node.name); write(") "); - // node.body must exist, as this is a non-ambient module + Debug.assert(node.body !== undefined); // node.body must exist, as this is a non-ambient module if (node.body.kind === SyntaxKind.ModuleBlock) { const saveConvertedLoopState = convertedLoopState; const saveTempFlags = tempFlags; diff --git a/tests/baselines/reference/ambientShorthand.js b/tests/baselines/reference/ambientShorthand.js index 76a3b482994..624b0b84771 100644 --- a/tests/baselines/reference/ambientShorthand.js +++ b/tests/baselines/reference/ambientShorthand.js @@ -18,7 +18,3 @@ foo(bar, baz); var jquery_1 = require("jquery"); var baz = require("fs"); jquery_1["default"](jquery_1.bar, baz); - - -//// [user.d.ts] -/// From ed6bfcdb08ccb0dbb1e72abb83a1332d39663cac Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 3 Jun 2016 06:45:00 -0700 Subject: [PATCH 3/6] Add merging tests --- src/compiler/checker.ts | 1 - .../reference/ambientShorthand_duplicate.js | 16 ++++++++++++++++ .../ambientShorthand_duplicate.symbols | 10 ++++++++++ .../reference/ambientShorthand_duplicate.types | 10 ++++++++++ .../reference/ambientShorthand_merging.js | 18 ++++++++++++++++++ .../reference/ambientShorthand_merging.symbols | 11 +++++++++++ .../reference/ambientShorthand_merging.types | 11 +++++++++++ .../ambient/ambientShorthand_duplicate.ts | 10 ++++++++++ .../ambient/ambientShorthand_merging.ts | 12 ++++++++++++ 9 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/ambientShorthand_duplicate.js create mode 100644 tests/baselines/reference/ambientShorthand_duplicate.symbols create mode 100644 tests/baselines/reference/ambientShorthand_duplicate.types create mode 100644 tests/baselines/reference/ambientShorthand_merging.js create mode 100644 tests/baselines/reference/ambientShorthand_merging.symbols create mode 100644 tests/baselines/reference/ambientShorthand_merging.types create mode 100644 tests/cases/conformance/ambient/ambientShorthand_duplicate.ts create mode 100644 tests/cases/conformance/ambient/ambientShorthand_merging.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 50f1ce0d208..c28502907d7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -380,7 +380,6 @@ namespace ts { } function mergeSymbol(target: Symbol, source: Symbol) { - //TODO: how to merge w/ shorthand ambient module? if (!(target.flags & getExcludedSymbolFlags(source.flags))) { if (source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule && target.constEnumOnlyModule && !source.constEnumOnlyModule) { // reset flag when merging instantiated module into value module that has only const enums diff --git a/tests/baselines/reference/ambientShorthand_duplicate.js b/tests/baselines/reference/ambientShorthand_duplicate.js new file mode 100644 index 00000000000..d99eb3d27dc --- /dev/null +++ b/tests/baselines/reference/ambientShorthand_duplicate.js @@ -0,0 +1,16 @@ +//// [tests/cases/conformance/ambient/ambientShorthand_duplicate.ts] //// + +//// [declarations1.d.ts] +declare module "foo"; + +//// [declarations2.d.ts] +declare module "foo"; + +//// [user.ts] +/// +/// +import foo from "foo"; + + +//// [user.js] +"use strict"; diff --git a/tests/baselines/reference/ambientShorthand_duplicate.symbols b/tests/baselines/reference/ambientShorthand_duplicate.symbols new file mode 100644 index 00000000000..05856b47b92 --- /dev/null +++ b/tests/baselines/reference/ambientShorthand_duplicate.symbols @@ -0,0 +1,10 @@ +=== tests/cases/conformance/ambient/user.ts === +/// +/// +import foo from "foo"; +>foo : Symbol(foo, Decl(user.ts, 2, 6)) + +=== tests/cases/conformance/ambient/declarations1.d.ts === +declare module "foo"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/ambientShorthand_duplicate.types b/tests/baselines/reference/ambientShorthand_duplicate.types new file mode 100644 index 00000000000..1520c5447ec --- /dev/null +++ b/tests/baselines/reference/ambientShorthand_duplicate.types @@ -0,0 +1,10 @@ +=== tests/cases/conformance/ambient/user.ts === +/// +/// +import foo from "foo"; +>foo : any + +=== tests/cases/conformance/ambient/declarations1.d.ts === +declare module "foo"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/ambientShorthand_merging.js b/tests/baselines/reference/ambientShorthand_merging.js new file mode 100644 index 00000000000..f0aaefc6366 --- /dev/null +++ b/tests/baselines/reference/ambientShorthand_merging.js @@ -0,0 +1,18 @@ +//// [tests/cases/conformance/ambient/ambientShorthand_merging.ts] //// + +//// [declarations1.d.ts] +declare module "foo"; + +//// [declarations2.d.ts] +declare module "foo" { + export const bar: number; +} + +//// [user.ts] +/// +/// +import foo, {bar} from "foo"; + + +//// [user.js] +"use strict"; diff --git a/tests/baselines/reference/ambientShorthand_merging.symbols b/tests/baselines/reference/ambientShorthand_merging.symbols new file mode 100644 index 00000000000..8a0ca5acb74 --- /dev/null +++ b/tests/baselines/reference/ambientShorthand_merging.symbols @@ -0,0 +1,11 @@ +=== tests/cases/conformance/ambient/user.ts === +/// +/// +import foo, {bar} from "foo"; +>foo : Symbol(foo, Decl(user.ts, 2, 6)) +>bar : Symbol(bar, Decl(user.ts, 2, 13)) + +=== tests/cases/conformance/ambient/declarations1.d.ts === +declare module "foo"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/ambientShorthand_merging.types b/tests/baselines/reference/ambientShorthand_merging.types new file mode 100644 index 00000000000..78390a35dd8 --- /dev/null +++ b/tests/baselines/reference/ambientShorthand_merging.types @@ -0,0 +1,11 @@ +=== tests/cases/conformance/ambient/user.ts === +/// +/// +import foo, {bar} from "foo"; +>foo : any +>bar : any + +=== tests/cases/conformance/ambient/declarations1.d.ts === +declare module "foo"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/cases/conformance/ambient/ambientShorthand_duplicate.ts b/tests/cases/conformance/ambient/ambientShorthand_duplicate.ts new file mode 100644 index 00000000000..03a0dd72249 --- /dev/null +++ b/tests/cases/conformance/ambient/ambientShorthand_duplicate.ts @@ -0,0 +1,10 @@ +// @Filename: declarations1.d.ts +declare module "foo"; + +// @Filename: declarations2.d.ts +declare module "foo"; + +// @Filename: user.ts +/// +/// +import foo from "foo"; diff --git a/tests/cases/conformance/ambient/ambientShorthand_merging.ts b/tests/cases/conformance/ambient/ambientShorthand_merging.ts new file mode 100644 index 00000000000..a7bd7784d43 --- /dev/null +++ b/tests/cases/conformance/ambient/ambientShorthand_merging.ts @@ -0,0 +1,12 @@ +// @Filename: declarations1.d.ts +declare module "foo"; + +// @Filename: declarations2.d.ts +declare module "foo" { + export const bar: number; +} + +// @Filename: user.ts +/// +/// +import foo, {bar} from "foo"; From f83248880140e0a6fe620082e7f04f39a80ea1d9 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Mon, 6 Jun 2016 08:14:49 -0700 Subject: [PATCH 4/6] Add "implicit any" warning for shorthand ambient modules --- src/compiler/checker.ts | 6 ++++++ .../reference/ambientShorthand_isImplicitAny.errors.txt | 8 ++++++++ .../baselines/reference/ambientShorthand_isImplicitAny.js | 5 +++++ .../conformance/ambient/ambientShorthand_isImplicitAny.ts | 2 ++ 4 files changed, 21 insertions(+) create mode 100644 tests/baselines/reference/ambientShorthand_isImplicitAny.errors.txt create mode 100644 tests/baselines/reference/ambientShorthand_isImplicitAny.js create mode 100644 tests/cases/conformance/ambient/ambientShorthand_isImplicitAny.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c28502907d7..10cdd6126b2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16048,6 +16048,12 @@ namespace ts { } } } + + if (compilerOptions.noImplicitAny && !node.body) { + // Ambient shorthand module is an implicit any + reportImplicitAnyError(node, anyType); + } + if (node.body) { checkSourceElement(node.body); } diff --git a/tests/baselines/reference/ambientShorthand_isImplicitAny.errors.txt b/tests/baselines/reference/ambientShorthand_isImplicitAny.errors.txt new file mode 100644 index 00000000000..875a656202d --- /dev/null +++ b/tests/baselines/reference/ambientShorthand_isImplicitAny.errors.txt @@ -0,0 +1,8 @@ +tests/cases/conformance/ambient/ambientShorthand_isImplicitAny.ts(1,16): error TS7005: Variable '"jquery"' implicitly has an 'any' type. + + +==== tests/cases/conformance/ambient/ambientShorthand_isImplicitAny.ts (1 errors) ==== + declare module "jquery"; + ~~~~~~~~ +!!! error TS7005: Variable '"jquery"' implicitly has an 'any' type. + \ No newline at end of file diff --git a/tests/baselines/reference/ambientShorthand_isImplicitAny.js b/tests/baselines/reference/ambientShorthand_isImplicitAny.js new file mode 100644 index 00000000000..ab05d2a9979 --- /dev/null +++ b/tests/baselines/reference/ambientShorthand_isImplicitAny.js @@ -0,0 +1,5 @@ +//// [ambientShorthand_isImplicitAny.ts] +declare module "jquery"; + + +//// [ambientShorthand_isImplicitAny.js] diff --git a/tests/cases/conformance/ambient/ambientShorthand_isImplicitAny.ts b/tests/cases/conformance/ambient/ambientShorthand_isImplicitAny.ts new file mode 100644 index 00000000000..bf7de709ef2 --- /dev/null +++ b/tests/cases/conformance/ambient/ambientShorthand_isImplicitAny.ts @@ -0,0 +1,2 @@ +// @noImplicitAny: true +declare module "jquery"; From 9fa971091ca8b078e556ae7f9e1eb31a5633e4cf Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Thu, 9 Jun 2016 12:46:52 -0700 Subject: [PATCH 5/6] Add tests for more kinds of import/export --- tests/baselines/reference/ambientShorthand.js | 6 ++-- .../reference/ambientShorthand.symbols | 6 +++- .../reference/ambientShorthand.types | 8 +++-- .../reference/ambientShorthand_reExport.js | 30 +++++++++++++++++++ .../ambientShorthand_reExport.symbols | 22 ++++++++++++++ .../reference/ambientShorthand_reExport.types | 23 ++++++++++++++ .../conformance/ambient/ambientShorthand.ts | 3 +- .../ambient/ambientShorthand_reExport.ts | 14 +++++++++ 8 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 tests/baselines/reference/ambientShorthand_reExport.js create mode 100644 tests/baselines/reference/ambientShorthand_reExport.symbols create mode 100644 tests/baselines/reference/ambientShorthand_reExport.types create mode 100644 tests/cases/conformance/ambient/ambientShorthand_reExport.ts diff --git a/tests/baselines/reference/ambientShorthand.js b/tests/baselines/reference/ambientShorthand.js index 624b0b84771..109264fc91b 100644 --- a/tests/baselines/reference/ambientShorthand.js +++ b/tests/baselines/reference/ambientShorthand.js @@ -9,7 +9,8 @@ declare module "fs"; /// import foo, {bar} from "jquery"; import * as baz from "fs"; -foo(bar, baz); +import boom = require("jquery"); +foo(bar, baz, boom); //// [user.js] @@ -17,4 +18,5 @@ foo(bar, baz); /// var jquery_1 = require("jquery"); var baz = require("fs"); -jquery_1["default"](jquery_1.bar, baz); +var boom = require("jquery"); +jquery_1["default"](jquery_1.bar, baz, boom); diff --git a/tests/baselines/reference/ambientShorthand.symbols b/tests/baselines/reference/ambientShorthand.symbols index 91cefe8d4c4..6747fd65173 100644 --- a/tests/baselines/reference/ambientShorthand.symbols +++ b/tests/baselines/reference/ambientShorthand.symbols @@ -7,10 +7,14 @@ import foo, {bar} from "jquery"; import * as baz from "fs"; >baz : Symbol(baz, Decl(user.ts, 2, 6)) -foo(bar, baz); +import boom = require("jquery"); +>boom : Symbol(boom, Decl(user.ts, 2, 26)) + +foo(bar, baz, boom); >foo : Symbol(foo, Decl(user.ts, 1, 6)) >bar : Symbol(bar, Decl(user.ts, 1, 13)) >baz : Symbol(baz, Decl(user.ts, 2, 6)) +>boom : Symbol(boom, Decl(user.ts, 2, 26)) === tests/cases/conformance/ambient/declarations.d.ts === declare module "jquery" diff --git a/tests/baselines/reference/ambientShorthand.types b/tests/baselines/reference/ambientShorthand.types index 12b18953e88..054349b1a6a 100644 --- a/tests/baselines/reference/ambientShorthand.types +++ b/tests/baselines/reference/ambientShorthand.types @@ -7,11 +7,15 @@ import foo, {bar} from "jquery"; import * as baz from "fs"; >baz : any -foo(bar, baz); ->foo(bar, baz) : any +import boom = require("jquery"); +>boom : any + +foo(bar, baz, boom); +>foo(bar, baz, boom) : any >foo : any >bar : any >baz : any +>boom : any === tests/cases/conformance/ambient/declarations.d.ts === declare module "jquery" diff --git a/tests/baselines/reference/ambientShorthand_reExport.js b/tests/baselines/reference/ambientShorthand_reExport.js new file mode 100644 index 00000000000..d0433e5d478 --- /dev/null +++ b/tests/baselines/reference/ambientShorthand_reExport.js @@ -0,0 +1,30 @@ +//// [tests/cases/conformance/ambient/ambientShorthand_reExport.ts] //// + +//// [declarations.d.ts] +declare module "jquery"; + +//// [reExportX.ts] +export {x} from "jquery"; + +//// [reExportAll.ts] +export * from "jquery"; + +//// [reExportUser.ts] +import {x} from "./reExportX"; +import * as $ from "./reExportAll"; +// '$' is not callable, it is an object. +x($); + + +//// [reExportX.js] +"use strict"; +var jquery_1 = require("jquery"); +exports.x = jquery_1.x; +//// [reExportAll.js] +"use strict"; +//// [reExportUser.js] +"use strict"; +var reExportX_1 = require("./reExportX"); +var $ = require("./reExportAll"); +// '$' is not callable, it is an object. +reExportX_1.x($); diff --git a/tests/baselines/reference/ambientShorthand_reExport.symbols b/tests/baselines/reference/ambientShorthand_reExport.symbols new file mode 100644 index 00000000000..1e8d5318011 --- /dev/null +++ b/tests/baselines/reference/ambientShorthand_reExport.symbols @@ -0,0 +1,22 @@ +=== tests/cases/conformance/ambient/declarations.d.ts === +declare module "jquery"; +No type information for this code. +No type information for this code.=== tests/cases/conformance/ambient/reExportX.ts === +export {x} from "jquery"; +>x : Symbol(x, Decl(reExportX.ts, 0, 8)) + +=== tests/cases/conformance/ambient/reExportAll.ts === +export * from "jquery"; +No type information for this code. +No type information for this code.=== tests/cases/conformance/ambient/reExportUser.ts === +import {x} from "./reExportX"; +>x : Symbol(x, Decl(reExportUser.ts, 0, 8)) + +import * as $ from "./reExportAll"; +>$ : Symbol($, Decl(reExportUser.ts, 1, 6)) + +// '$' is not callable, it is an object. +x($); +>x : Symbol(x, Decl(reExportUser.ts, 0, 8)) +>$ : Symbol($, Decl(reExportUser.ts, 1, 6)) + diff --git a/tests/baselines/reference/ambientShorthand_reExport.types b/tests/baselines/reference/ambientShorthand_reExport.types new file mode 100644 index 00000000000..5765c7e0331 --- /dev/null +++ b/tests/baselines/reference/ambientShorthand_reExport.types @@ -0,0 +1,23 @@ +=== tests/cases/conformance/ambient/declarations.d.ts === +declare module "jquery"; +No type information for this code. +No type information for this code.=== tests/cases/conformance/ambient/reExportX.ts === +export {x} from "jquery"; +>x : any + +=== tests/cases/conformance/ambient/reExportAll.ts === +export * from "jquery"; +No type information for this code. +No type information for this code.=== tests/cases/conformance/ambient/reExportUser.ts === +import {x} from "./reExportX"; +>x : any + +import * as $ from "./reExportAll"; +>$ : typeof $ + +// '$' is not callable, it is an object. +x($); +>x($) : any +>x : any +>$ : typeof $ + diff --git a/tests/cases/conformance/ambient/ambientShorthand.ts b/tests/cases/conformance/ambient/ambientShorthand.ts index 3070abff595..35bb53a92cf 100644 --- a/tests/cases/conformance/ambient/ambientShorthand.ts +++ b/tests/cases/conformance/ambient/ambientShorthand.ts @@ -7,4 +7,5 @@ declare module "fs"; /// import foo, {bar} from "jquery"; import * as baz from "fs"; -foo(bar, baz); +import boom = require("jquery"); +foo(bar, baz, boom); diff --git a/tests/cases/conformance/ambient/ambientShorthand_reExport.ts b/tests/cases/conformance/ambient/ambientShorthand_reExport.ts new file mode 100644 index 00000000000..b78afe42675 --- /dev/null +++ b/tests/cases/conformance/ambient/ambientShorthand_reExport.ts @@ -0,0 +1,14 @@ +// @Filename: declarations.d.ts +declare module "jquery"; + +// @Filename: reExportX.ts +export {x} from "jquery"; + +// @Filename: reExportAll.ts +export * from "jquery"; + +// @Filename: reExportUser.ts +import {x} from "./reExportX"; +import * as $ from "./reExportAll"; +// '$' is not callable, it is an object. +x($); From 077dfff93bc9419d25e3b0b06a43071991c8e2de Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 10 Jun 2016 08:03:41 -0700 Subject: [PATCH 6/6] Add tests --- .../fourslash/ambientShorthandFindAllRefs.ts | 21 ++++++++++ .../ambientShorthandGotoDefinition.ts | 39 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 tests/cases/fourslash/ambientShorthandFindAllRefs.ts create mode 100644 tests/cases/fourslash/ambientShorthandGotoDefinition.ts diff --git a/tests/cases/fourslash/ambientShorthandFindAllRefs.ts b/tests/cases/fourslash/ambientShorthandFindAllRefs.ts new file mode 100644 index 00000000000..16fddd1869d --- /dev/null +++ b/tests/cases/fourslash/ambientShorthandFindAllRefs.ts @@ -0,0 +1,21 @@ +/// + +// @Filename: declarations.d.ts +////declare module "jquery"; + +// @Filename: user.ts +////import {[|x|]} from "jquery"; + +// @Filename: user2.ts +////import {[|x|]} from "jquery"; + +let ranges = test.ranges(); +for (let range of ranges) { + goTo.file(range.fileName); + goTo.position(range.start); + + verify.referencesCountIs(ranges.length); + for (let expectedRange of ranges) { + verify.referencesAtPositionContains(expectedRange); + } +} diff --git a/tests/cases/fourslash/ambientShorthandGotoDefinition.ts b/tests/cases/fourslash/ambientShorthandGotoDefinition.ts new file mode 100644 index 00000000000..970b87f8ec2 --- /dev/null +++ b/tests/cases/fourslash/ambientShorthandGotoDefinition.ts @@ -0,0 +1,39 @@ +/// + +// @Filename: declarations.d.ts +/////*module*/declare module "jquery" + +// @Filename: user.ts +/////// +////import /*importFoo*/foo, {bar} from "jquery"; +////import /*importBaz*/* as /*idBaz*/baz from "jquery"; +/////*importBang*/import /*idBang*/bang = require("jquery"); +////foo/*useFoo*/(bar/*useBar*/, baz/*useBaz*/, bang/*useBang*/); + +goTo.marker("useFoo"); +verify.quickInfoIs("import foo"); +goTo.definition(); +verify.caretAtMarker("importFoo"); +goTo.definition(); +verify.caretAtMarker("module"); + +goTo.marker("useBar"); +verify.quickInfoIs("import bar"); +goTo.definition(); +verify.caretAtMarker("module"); + +goTo.marker("useBaz"); +verify.quickInfoIs("import baz"); +goTo.definition(); +verify.caretAtMarker("importBaz"); +goTo.marker("idBaz"); +goTo.definition(); +verify.caretAtMarker("module"); + +goTo.marker("useBang"); +verify.quickInfoIs("import bang = require(\"jquery\")"); +goTo.definition(); +verify.caretAtMarker("importBang"); +goTo.marker("idBang"); +goTo.definition(); +verify.caretAtMarker("module");