mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-28 12:58:49 -05:00
Merge pull request #3818 from Microsoft/exportSpecifierCompletions
Support completions in exports with module specifiers.
This commit is contained in:
@@ -5135,7 +5135,12 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
node.exportClause = parseNamedImportsOrExports(SyntaxKind.NamedExports);
|
||||
if (parseOptional(SyntaxKind.FromKeyword)) {
|
||||
|
||||
// It is not uncommon to accidentally omit the 'from' keyword. Additionally, in editing scenarios,
|
||||
// the 'from' keyword can be parsed as a named export when the export clause is unterminated (i.e. `export { from "moduleName";`)
|
||||
// If we don't have a 'from' keyword, see if we have a string literal such that ASI won't take effect.
|
||||
if (token === SyntaxKind.FromKeyword || (token === SyntaxKind.StringLiteral && !scanner.hasPrecedingLineBreak())) {
|
||||
parseExpected(SyntaxKind.FromKeyword)
|
||||
node.moduleSpecifier = parseModuleSpecifier();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3028,17 +3028,17 @@ namespace ts {
|
||||
|
||||
function tryGetGlobalSymbols(): boolean {
|
||||
let objectLikeContainer: ObjectLiteralExpression | BindingPattern;
|
||||
let importClause: ImportClause;
|
||||
let namedImportsOrExports: NamedImportsOrExports;
|
||||
let jsxContainer: JsxOpeningLikeElement;
|
||||
|
||||
if (objectLikeContainer = tryGetObjectLikeCompletionContainer(contextToken)) {
|
||||
return tryGetObjectLikeCompletionSymbols(objectLikeContainer);
|
||||
}
|
||||
|
||||
if (importClause = <ImportClause>getAncestor(contextToken, SyntaxKind.ImportClause)) {
|
||||
if (namedImportsOrExports = tryGetNamedImportsOrExportsForCompletion(contextToken)) {
|
||||
// cursor is in an import clause
|
||||
// try to show exported member for imported module
|
||||
return tryGetImportClauseCompletionSymbols(importClause);
|
||||
return tryGetImportOrExportClauseCompletionSymbols(namedImportsOrExports);
|
||||
}
|
||||
|
||||
if (jsxContainer = tryGetContainingJsxElement(contextToken)) {
|
||||
@@ -3048,7 +3048,7 @@ namespace ts {
|
||||
attrsType = typeChecker.getJsxElementAttributesType(<JsxOpeningLikeElement>jsxContainer);
|
||||
|
||||
if (attrsType) {
|
||||
symbols = filterJsxAttributes((<JsxOpeningLikeElement>jsxContainer).attributes, typeChecker.getPropertiesOfType(attrsType));
|
||||
symbols = filterJsxAttributes(typeChecker.getPropertiesOfType(attrsType), (<JsxOpeningLikeElement>jsxContainer).attributes);
|
||||
isMemberCompletion = true;
|
||||
isNewIdentifierLocation = false;
|
||||
return true;
|
||||
@@ -3117,24 +3117,12 @@ namespace ts {
|
||||
function isCompletionListBlocker(contextToken: Node): boolean {
|
||||
let start = new Date().getTime();
|
||||
let result = isInStringOrRegularExpressionOrTemplateLiteral(contextToken) ||
|
||||
isIdentifierDefinitionLocation(contextToken) ||
|
||||
isSolelyIdentifierDefinitionLocation(contextToken) ||
|
||||
isDotOfNumericLiteral(contextToken);
|
||||
log("getCompletionsAtPosition: isCompletionListBlocker: " + (new Date().getTime() - start));
|
||||
return result;
|
||||
}
|
||||
|
||||
function shouldShowCompletionsInImportsClause(node: Node): boolean {
|
||||
if (node) {
|
||||
// import {|
|
||||
// import {a,|
|
||||
if (node.kind === SyntaxKind.OpenBraceToken || node.kind === SyntaxKind.CommaToken) {
|
||||
return node.parent.kind === SyntaxKind.NamedImports;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function isNewIdentifierDefinitionLocation(previousToken: Node): boolean {
|
||||
if (previousToken) {
|
||||
let containingNodeKind = previousToken.parent.kind;
|
||||
@@ -3266,38 +3254,42 @@ namespace ts {
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregates relevant symbols for completion in import clauses; for instance,
|
||||
* Aggregates relevant symbols for completion in import clauses and export clauses
|
||||
* whose declarations have a module specifier; for instance, symbols will be aggregated for
|
||||
*
|
||||
* import { $ } from "moduleName";
|
||||
* import { | } from "moduleName";
|
||||
* export { a as foo, | } from "moduleName";
|
||||
*
|
||||
* but not for
|
||||
*
|
||||
* export { | };
|
||||
*
|
||||
* Relevant symbols are stored in the captured 'symbols' variable.
|
||||
*
|
||||
* @returns true if 'symbols' was successfully populated; false otherwise.
|
||||
*/
|
||||
function tryGetImportClauseCompletionSymbols(importClause: ImportClause): boolean {
|
||||
// cursor is in import clause
|
||||
// try to show exported member for imported module
|
||||
if (shouldShowCompletionsInImportsClause(contextToken)) {
|
||||
isMemberCompletion = true;
|
||||
isNewIdentifierLocation = false;
|
||||
function tryGetImportOrExportClauseCompletionSymbols(namedImportsOrExports: NamedImportsOrExports): boolean {
|
||||
let declarationKind = namedImportsOrExports.kind === SyntaxKind.NamedImports ?
|
||||
SyntaxKind.ImportDeclaration :
|
||||
SyntaxKind.ExportDeclaration;
|
||||
let importOrExportDeclaration = <ImportDeclaration | ExportDeclaration>getAncestor(namedImportsOrExports, declarationKind);
|
||||
let moduleSpecifier = importOrExportDeclaration.moduleSpecifier;
|
||||
|
||||
let importDeclaration = <ImportDeclaration>importClause.parent;
|
||||
Debug.assert(importDeclaration !== undefined && importDeclaration.kind === SyntaxKind.ImportDeclaration);
|
||||
|
||||
let exports: Symbol[];
|
||||
let moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(importDeclaration.moduleSpecifier);
|
||||
if (moduleSpecifierSymbol) {
|
||||
exports = typeChecker.getExportsOfModule(moduleSpecifierSymbol);
|
||||
}
|
||||
|
||||
//let exports = typeInfoResolver.getExportsOfImportDeclaration(importDeclaration);
|
||||
symbols = exports ? filterModuleExports(exports, importDeclaration) : emptyArray;
|
||||
if (!moduleSpecifier) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
isMemberCompletion = false;
|
||||
isNewIdentifierLocation = true;
|
||||
|
||||
isMemberCompletion = true;
|
||||
isNewIdentifierLocation = false;
|
||||
|
||||
let exports: Symbol[];
|
||||
let moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(importOrExportDeclaration.moduleSpecifier);
|
||||
if (moduleSpecifierSymbol) {
|
||||
exports = typeChecker.getExportsOfModule(moduleSpecifierSymbol);
|
||||
}
|
||||
|
||||
symbols = exports ? filterNamedImportOrExportCompletionItems(exports, namedImportsOrExports.elements) : emptyArray;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3321,6 +3313,26 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the containing list of named imports or exports of a context token,
|
||||
* on the condition that one exists and that the context implies completion should be given.
|
||||
*/
|
||||
function tryGetNamedImportsOrExportsForCompletion(contextToken: Node): NamedImportsOrExports {
|
||||
if (contextToken) {
|
||||
switch (contextToken.kind) {
|
||||
case SyntaxKind.OpenBraceToken: // import { |
|
||||
case SyntaxKind.CommaToken: // import { a as 0, |
|
||||
switch (contextToken.parent.kind) {
|
||||
case SyntaxKind.NamedImports:
|
||||
case SyntaxKind.NamedExports:
|
||||
return <NamedImportsOrExports>contextToken.parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function tryGetContainingJsxElement(contextToken: Node): JsxOpeningLikeElement {
|
||||
if (contextToken) {
|
||||
let parent = contextToken.parent;
|
||||
@@ -3368,7 +3380,10 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isIdentifierDefinitionLocation(contextToken: Node): boolean {
|
||||
/**
|
||||
* @returns true if we are certain that the currently edited location must define a new location; false otherwise.
|
||||
*/
|
||||
function isSolelyIdentifierDefinitionLocation(contextToken: Node): boolean {
|
||||
let containingNodeKind = contextToken.parent.kind;
|
||||
switch (contextToken.kind) {
|
||||
case SyntaxKind.CommaToken:
|
||||
@@ -3425,6 +3440,11 @@ namespace ts {
|
||||
case SyntaxKind.ProtectedKeyword:
|
||||
return containingNodeKind === SyntaxKind.Parameter;
|
||||
|
||||
case SyntaxKind.AsKeyword:
|
||||
containingNodeKind === SyntaxKind.ImportSpecifier ||
|
||||
containingNodeKind === SyntaxKind.ExportSpecifier ||
|
||||
containingNodeKind === SyntaxKind.NamespaceImport;
|
||||
|
||||
case SyntaxKind.ClassKeyword:
|
||||
case SyntaxKind.EnumKeyword:
|
||||
case SyntaxKind.InterfaceKeyword:
|
||||
@@ -3466,33 +3486,41 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function filterModuleExports(exports: Symbol[], importDeclaration: ImportDeclaration): Symbol[] {
|
||||
let exisingImports: Map<boolean> = {};
|
||||
/**
|
||||
* Filters out completion suggestions for named imports or exports.
|
||||
*
|
||||
* @param exportsOfModule The list of symbols which a module exposes.
|
||||
* @param namedImportsOrExports The list of existing import/export specifiers in the import/export clause.
|
||||
*
|
||||
* @returns Symbols to be suggested at an import/export clause, barring those whose named imports/exports
|
||||
* do not occur at the current position and have not otherwise been typed.
|
||||
*/
|
||||
function filterNamedImportOrExportCompletionItems(exportsOfModule: Symbol[], namedImportsOrExports: ImportOrExportSpecifier[]): Symbol[] {
|
||||
let exisingImportsOrExports: Map<boolean> = {};
|
||||
|
||||
if (!importDeclaration.importClause) {
|
||||
return exports;
|
||||
for (let element of namedImportsOrExports) {
|
||||
// If this is the current item we are editing right now, do not filter it out
|
||||
if (element.getStart() <= position && position <= element.getEnd()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = element.propertyName || element.name;
|
||||
exisingImportsOrExports[name.text] = true;
|
||||
}
|
||||
|
||||
if (importDeclaration.importClause.namedBindings &&
|
||||
importDeclaration.importClause.namedBindings.kind === SyntaxKind.NamedImports) {
|
||||
|
||||
forEach((<NamedImports>importDeclaration.importClause.namedBindings).elements, el => {
|
||||
// If this is the current item we are editing right now, do not filter it out
|
||||
if (el.getStart() <= position && position <= el.getEnd()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let name = el.propertyName || el.name;
|
||||
exisingImports[name.text] = true;
|
||||
});
|
||||
if (isEmpty(exisingImportsOrExports)) {
|
||||
return exportsOfModule;
|
||||
}
|
||||
|
||||
if (isEmpty(exisingImports)) {
|
||||
return exports;
|
||||
}
|
||||
return filter(exports, e => !lookUp(exisingImports, e.name));
|
||||
return filter(exportsOfModule, e => !lookUp(exisingImportsOrExports, e.name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters out completion suggestions for named imports or exports.
|
||||
*
|
||||
* @returns Symbols to be suggested in an object binding pattern or object literal expression, barring those whose declarations
|
||||
* do not occur at the current position and have not otherwise been typed.
|
||||
*/
|
||||
function filterObjectMembersList(contextualMemberSymbols: Symbol[], existingMembers: Declaration[]): Symbol[] {
|
||||
if (!existingMembers || existingMembers.length === 0) {
|
||||
return contextualMemberSymbols;
|
||||
@@ -3527,17 +3555,16 @@ namespace ts {
|
||||
existingMemberNames[existingName] = true;
|
||||
}
|
||||
|
||||
let filteredMembers: Symbol[] = [];
|
||||
forEach(contextualMemberSymbols, s => {
|
||||
if (!existingMemberNames[s.name]) {
|
||||
filteredMembers.push(s);
|
||||
}
|
||||
});
|
||||
|
||||
return filteredMembers;
|
||||
return filter(contextualMemberSymbols, m => !lookUp(existingMemberNames, m.name));
|
||||
}
|
||||
|
||||
function filterJsxAttributes(attributes: NodeArray<JsxAttribute | JsxSpreadAttribute>, symbols: Symbol[]): Symbol[] {
|
||||
/**
|
||||
* Filters out completion suggestions from 'symbols' according to existing JSX attributes.
|
||||
*
|
||||
* @returns Symbols to be suggested in a JSX element, barring those whose attributes
|
||||
* do not occur at the current position and have not otherwise been typed.
|
||||
*/
|
||||
function filterJsxAttributes(symbols: Symbol[], attributes: NodeArray<JsxAttribute | JsxSpreadAttribute>): Symbol[] {
|
||||
let seenNames: Map<boolean> = {};
|
||||
for (let attr of attributes) {
|
||||
// If this is the current item we are editing right now, do not filter it out
|
||||
@@ -3549,13 +3576,8 @@ namespace ts {
|
||||
seenNames[(<JsxAttribute>attr).name.text] = true;
|
||||
}
|
||||
}
|
||||
let result: Symbol[] = [];
|
||||
for (let sym of symbols) {
|
||||
if (!seenNames[sym.name]) {
|
||||
result.push(sym);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
return filter(symbols, a => !lookUp(seenNames, a.name));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
//// [tests/cases/compiler/exportDeclarationWithModuleSpecifierNameOnNextLine1.ts] ////
|
||||
|
||||
//// [t1.ts]
|
||||
|
||||
export var x = "x";
|
||||
|
||||
//// [t2.ts]
|
||||
export { x } from
|
||||
"./t1";
|
||||
|
||||
//// [t3.ts]
|
||||
export { } from
|
||||
"./t1";
|
||||
|
||||
//// [t4.ts]
|
||||
export { x as a } from
|
||||
"./t1";
|
||||
|
||||
//// [t5.ts]
|
||||
export { x as a, } from
|
||||
"./t1";
|
||||
|
||||
//// [t1.js]
|
||||
exports.x = "x";
|
||||
//// [t2.js]
|
||||
var t1_1 = require("./t1");
|
||||
exports.x = t1_1.x;
|
||||
//// [t3.js]
|
||||
//// [t4.js]
|
||||
var t1_1 = require("./t1");
|
||||
exports.a = t1_1.x;
|
||||
//// [t5.js]
|
||||
var t1_1 = require("./t1");
|
||||
exports.a = t1_1.x;
|
||||
@@ -0,0 +1,28 @@
|
||||
=== tests/cases/compiler/t1.ts ===
|
||||
|
||||
export var x = "x";
|
||||
>x : Symbol(x, Decl(t1.ts, 1, 10))
|
||||
|
||||
=== tests/cases/compiler/t2.ts ===
|
||||
export { x } from
|
||||
>x : Symbol(x, Decl(t2.ts, 0, 8))
|
||||
|
||||
"./t1";
|
||||
|
||||
=== tests/cases/compiler/t3.ts ===
|
||||
export { } from
|
||||
No type information for this code. "./t1";
|
||||
No type information for this code.
|
||||
No type information for this code.=== tests/cases/compiler/t4.ts ===
|
||||
export { x as a } from
|
||||
>x : Symbol(a, Decl(t4.ts, 0, 8))
|
||||
>a : Symbol(a, Decl(t4.ts, 0, 8))
|
||||
|
||||
"./t1";
|
||||
|
||||
=== tests/cases/compiler/t5.ts ===
|
||||
export { x as a, } from
|
||||
>x : Symbol(a, Decl(t5.ts, 0, 8))
|
||||
>a : Symbol(a, Decl(t5.ts, 0, 8))
|
||||
|
||||
"./t1";
|
||||
@@ -0,0 +1,29 @@
|
||||
=== tests/cases/compiler/t1.ts ===
|
||||
|
||||
export var x = "x";
|
||||
>x : string
|
||||
>"x" : string
|
||||
|
||||
=== tests/cases/compiler/t2.ts ===
|
||||
export { x } from
|
||||
>x : string
|
||||
|
||||
"./t1";
|
||||
|
||||
=== tests/cases/compiler/t3.ts ===
|
||||
export { } from
|
||||
No type information for this code. "./t1";
|
||||
No type information for this code.
|
||||
No type information for this code.=== tests/cases/compiler/t4.ts ===
|
||||
export { x as a } from
|
||||
>x : string
|
||||
>a : string
|
||||
|
||||
"./t1";
|
||||
|
||||
=== tests/cases/compiler/t5.ts ===
|
||||
export { x as a, } from
|
||||
>x : string
|
||||
>a : string
|
||||
|
||||
"./t1";
|
||||
44
tests/baselines/reference/unclosedExportClause01.errors.txt
Normal file
44
tests/baselines/reference/unclosedExportClause01.errors.txt
Normal file
@@ -0,0 +1,44 @@
|
||||
tests/cases/compiler/t2.ts(1,13): error TS2305: Module '"tests/cases/compiler/t1"' has no exported member 'from'.
|
||||
tests/cases/compiler/t2.ts(1,18): error TS1005: ',' expected.
|
||||
tests/cases/compiler/t3.ts(1,10): error TS2305: Module '"tests/cases/compiler/t1"' has no exported member 'from'.
|
||||
tests/cases/compiler/t3.ts(1,15): error TS1005: ',' expected.
|
||||
tests/cases/compiler/t4.ts(1,17): error TS1005: ',' expected.
|
||||
tests/cases/compiler/t4.ts(1,17): error TS2305: Module '"tests/cases/compiler/t1"' has no exported member 'from'.
|
||||
tests/cases/compiler/t4.ts(1,22): error TS1005: ',' expected.
|
||||
tests/cases/compiler/t5.ts(1,18): error TS2305: Module '"tests/cases/compiler/t1"' has no exported member 'from'.
|
||||
tests/cases/compiler/t5.ts(1,23): error TS1005: ',' expected.
|
||||
|
||||
|
||||
==== tests/cases/compiler/t1.ts (0 errors) ====
|
||||
|
||||
export var x = "x";
|
||||
|
||||
==== tests/cases/compiler/t2.ts (2 errors) ====
|
||||
export { x, from "./t1"
|
||||
~~~~
|
||||
!!! error TS2305: Module '"tests/cases/compiler/t1"' has no exported member 'from'.
|
||||
~~~~~~
|
||||
!!! error TS1005: ',' expected.
|
||||
|
||||
==== tests/cases/compiler/t3.ts (2 errors) ====
|
||||
export { from "./t1"
|
||||
~~~~
|
||||
!!! error TS2305: Module '"tests/cases/compiler/t1"' has no exported member 'from'.
|
||||
~~~~~~
|
||||
!!! error TS1005: ',' expected.
|
||||
|
||||
==== tests/cases/compiler/t4.ts (3 errors) ====
|
||||
export { x as a from "./t1"
|
||||
~~~~
|
||||
!!! error TS1005: ',' expected.
|
||||
~~~~
|
||||
!!! error TS2305: Module '"tests/cases/compiler/t1"' has no exported member 'from'.
|
||||
~~~~~~
|
||||
!!! error TS1005: ',' expected.
|
||||
|
||||
==== tests/cases/compiler/t5.ts (2 errors) ====
|
||||
export { x as a, from "./t1"
|
||||
~~~~
|
||||
!!! error TS2305: Module '"tests/cases/compiler/t1"' has no exported member 'from'.
|
||||
~~~~~~
|
||||
!!! error TS1005: ',' expected.
|
||||
30
tests/baselines/reference/unclosedExportClause01.js
Normal file
30
tests/baselines/reference/unclosedExportClause01.js
Normal file
@@ -0,0 +1,30 @@
|
||||
//// [tests/cases/compiler/unclosedExportClause01.ts] ////
|
||||
|
||||
//// [t1.ts]
|
||||
|
||||
export var x = "x";
|
||||
|
||||
//// [t2.ts]
|
||||
export { x, from "./t1"
|
||||
|
||||
//// [t3.ts]
|
||||
export { from "./t1"
|
||||
|
||||
//// [t4.ts]
|
||||
export { x as a from "./t1"
|
||||
|
||||
//// [t5.ts]
|
||||
export { x as a, from "./t1"
|
||||
|
||||
//// [t1.js]
|
||||
exports.x = "x";
|
||||
//// [t2.js]
|
||||
var t1_1 = require("./t1");
|
||||
exports.x = t1_1.x;
|
||||
//// [t3.js]
|
||||
//// [t4.js]
|
||||
var t1_1 = require("./t1");
|
||||
exports.a = t1_1.x;
|
||||
//// [t5.js]
|
||||
var t1_1 = require("./t1");
|
||||
exports.a = t1_1.x;
|
||||
57
tests/baselines/reference/unclosedExportClause02.errors.txt
Normal file
57
tests/baselines/reference/unclosedExportClause02.errors.txt
Normal file
@@ -0,0 +1,57 @@
|
||||
tests/cases/compiler/t2.ts(1,10): error TS2304: Cannot find name 'x'.
|
||||
tests/cases/compiler/t2.ts(1,13): error TS2304: Cannot find name 'from'.
|
||||
tests/cases/compiler/t2.ts(2,5): error TS1005: ',' expected.
|
||||
tests/cases/compiler/t3.ts(1,10): error TS2304: Cannot find name 'from'.
|
||||
tests/cases/compiler/t3.ts(2,5): error TS1005: ',' expected.
|
||||
tests/cases/compiler/t4.ts(1,10): error TS2304: Cannot find name 'x'.
|
||||
tests/cases/compiler/t4.ts(1,17): error TS1005: ',' expected.
|
||||
tests/cases/compiler/t4.ts(1,17): error TS2304: Cannot find name 'from'.
|
||||
tests/cases/compiler/t4.ts(2,5): error TS1005: ',' expected.
|
||||
tests/cases/compiler/t5.ts(1,10): error TS2304: Cannot find name 'x'.
|
||||
tests/cases/compiler/t5.ts(1,18): error TS2304: Cannot find name 'from'.
|
||||
tests/cases/compiler/t5.ts(2,5): error TS1005: ',' expected.
|
||||
|
||||
|
||||
==== tests/cases/compiler/t1.ts (0 errors) ====
|
||||
|
||||
export var x = "x";
|
||||
|
||||
==== tests/cases/compiler/t2.ts (3 errors) ====
|
||||
export { x, from
|
||||
~
|
||||
!!! error TS2304: Cannot find name 'x'.
|
||||
~~~~
|
||||
!!! error TS2304: Cannot find name 'from'.
|
||||
"./t1";
|
||||
~~~~~~
|
||||
!!! error TS1005: ',' expected.
|
||||
|
||||
==== tests/cases/compiler/t3.ts (2 errors) ====
|
||||
export { from
|
||||
~~~~
|
||||
!!! error TS2304: Cannot find name 'from'.
|
||||
"./t1";
|
||||
~~~~~~
|
||||
!!! error TS1005: ',' expected.
|
||||
|
||||
==== tests/cases/compiler/t4.ts (4 errors) ====
|
||||
export { x as a from
|
||||
~
|
||||
!!! error TS2304: Cannot find name 'x'.
|
||||
~~~~
|
||||
!!! error TS1005: ',' expected.
|
||||
~~~~
|
||||
!!! error TS2304: Cannot find name 'from'.
|
||||
"./t1";
|
||||
~~~~~~
|
||||
!!! error TS1005: ',' expected.
|
||||
|
||||
==== tests/cases/compiler/t5.ts (3 errors) ====
|
||||
export { x as a, from
|
||||
~
|
||||
!!! error TS2304: Cannot find name 'x'.
|
||||
~~~~
|
||||
!!! error TS2304: Cannot find name 'from'.
|
||||
"./t1";
|
||||
~~~~~~
|
||||
!!! error TS1005: ',' expected.
|
||||
32
tests/baselines/reference/unclosedExportClause02.js
Normal file
32
tests/baselines/reference/unclosedExportClause02.js
Normal file
@@ -0,0 +1,32 @@
|
||||
//// [tests/cases/compiler/unclosedExportClause02.ts] ////
|
||||
|
||||
//// [t1.ts]
|
||||
|
||||
export var x = "x";
|
||||
|
||||
//// [t2.ts]
|
||||
export { x, from
|
||||
"./t1";
|
||||
|
||||
//// [t3.ts]
|
||||
export { from
|
||||
"./t1";
|
||||
|
||||
//// [t4.ts]
|
||||
export { x as a from
|
||||
"./t1";
|
||||
|
||||
//// [t5.ts]
|
||||
export { x as a, from
|
||||
"./t1";
|
||||
|
||||
//// [t1.js]
|
||||
exports.x = "x";
|
||||
//// [t2.js]
|
||||
"./t1";
|
||||
//// [t3.js]
|
||||
"./t1";
|
||||
//// [t4.js]
|
||||
"./t1";
|
||||
//// [t5.js]
|
||||
"./t1";
|
||||
@@ -0,0 +1,20 @@
|
||||
// @module: commonjs
|
||||
|
||||
// @filename: t1.ts
|
||||
export var x = "x";
|
||||
|
||||
// @filename: t2.ts
|
||||
export { x } from
|
||||
"./t1";
|
||||
|
||||
// @filename: t3.ts
|
||||
export { } from
|
||||
"./t1";
|
||||
|
||||
// @filename: t4.ts
|
||||
export { x as a } from
|
||||
"./t1";
|
||||
|
||||
// @filename: t5.ts
|
||||
export { x as a, } from
|
||||
"./t1";
|
||||
16
tests/cases/compiler/unclosedExportClause01.ts
Normal file
16
tests/cases/compiler/unclosedExportClause01.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
// @module: commonjs
|
||||
|
||||
// @filename: t1.ts
|
||||
export var x = "x";
|
||||
|
||||
// @filename: t2.ts
|
||||
export { x, from "./t1"
|
||||
|
||||
// @filename: t3.ts
|
||||
export { from "./t1"
|
||||
|
||||
// @filename: t4.ts
|
||||
export { x as a from "./t1"
|
||||
|
||||
// @filename: t5.ts
|
||||
export { x as a, from "./t1"
|
||||
20
tests/cases/compiler/unclosedExportClause02.ts
Normal file
20
tests/cases/compiler/unclosedExportClause02.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
// @module: commonjs
|
||||
|
||||
// @filename: t1.ts
|
||||
export var x = "x";
|
||||
|
||||
// @filename: t2.ts
|
||||
export { x, from
|
||||
"./t1";
|
||||
|
||||
// @filename: t3.ts
|
||||
export { from
|
||||
"./t1";
|
||||
|
||||
// @filename: t4.ts
|
||||
export { x as a from
|
||||
"./t1";
|
||||
|
||||
// @filename: t5.ts
|
||||
export { x as a, from
|
||||
"./t1";
|
||||
40
tests/cases/fourslash/completionListInExportClause01.ts
Normal file
40
tests/cases/fourslash/completionListInExportClause01.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @Filename: m1.ts
|
||||
////export var foo: number = 1;
|
||||
////export function bar() { return 10; }
|
||||
////export function baz() { return 10; }
|
||||
|
||||
// @Filename: m2.ts
|
||||
////export {/*1*/, /*2*/ from "m1"
|
||||
////export {/*3*/} from "m1"
|
||||
////export {foo,/*4*/ from "m1"
|
||||
////export {bar as /*5*/, /*6*/ from "m1"
|
||||
////export {foo, bar, baz as b,/*7*/} from "m1"
|
||||
|
||||
function verifyCompletionAtMarker(marker: string, showBuilder: boolean, ...completions: string[]) {
|
||||
goTo.marker(marker);
|
||||
if (completions.length) {
|
||||
for (let completion of completions) {
|
||||
verify.completionListContains(completion);
|
||||
}
|
||||
}
|
||||
else {
|
||||
verify.completionListIsEmpty();
|
||||
}
|
||||
|
||||
if (showBuilder) {
|
||||
verify.completionListAllowsNewIdentifier();
|
||||
}
|
||||
else {
|
||||
verify.not.completionListAllowsNewIdentifier();
|
||||
}
|
||||
}
|
||||
|
||||
verifyCompletionAtMarker("1", /*showBuilder*/ false, "foo", "bar", "baz");
|
||||
verifyCompletionAtMarker("2", /*showBuilder*/ false, "foo", "bar", "baz");
|
||||
verifyCompletionAtMarker("3", /*showBuilder*/ false, "foo", "bar", "baz");
|
||||
verifyCompletionAtMarker("4", /*showBuilder*/ false, "bar", "baz");
|
||||
verifyCompletionAtMarker("5", /*showBuilder*/ true);
|
||||
verifyCompletionAtMarker("6", /*showBuilder*/ false, "foo", "baz");
|
||||
verifyCompletionAtMarker("7", /*showBuilder*/ false);
|
||||
14
tests/cases/fourslash/completionListInExportClause02.ts
Normal file
14
tests/cases/fourslash/completionListInExportClause02.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
////declare module "M1" {
|
||||
//// export var V;
|
||||
////}
|
||||
////var W;
|
||||
////declare module "M2" {
|
||||
//// export { /**/ } from "M1"
|
||||
////}
|
||||
|
||||
goTo.marker();
|
||||
verify.completionListContains("V");
|
||||
verify.not.completionListContains("W");
|
||||
verify.not.completionListAllowsNewIdentifier();
|
||||
16
tests/cases/fourslash/completionListInExportClause03.ts
Normal file
16
tests/cases/fourslash/completionListInExportClause03.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////declare module "M1" {
|
||||
//// export var abc: number;
|
||||
//// export var def: string;
|
||||
////}
|
||||
////
|
||||
////declare module "M2" {
|
||||
//// export { abc/**/ } from "M1";
|
||||
////}
|
||||
|
||||
// Ensure we don't filter out the current item.
|
||||
goTo.marker();
|
||||
verify.completionListContains("abc");
|
||||
verify.completionListContains("def");
|
||||
verify.not.completionListAllowsNewIdentifier();
|
||||
@@ -11,6 +11,7 @@
|
||||
////import {foo,/*4*/ from "m1"
|
||||
////import {bar as /*5*/, /*6*/ from "m1"
|
||||
////import {foo, bar, baz as b,/*7*/} from "m1"
|
||||
|
||||
function verifyCompletionAtMarker(marker: string, showBuilder: boolean, ...completions: string[]) {
|
||||
goTo.marker(marker);
|
||||
if (completions.length) {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @Filename: m1.ts
|
||||
////export var foo: number = 1;
|
||||
|
||||
// @Filename: m2.ts
|
||||
////import * as /**/ from "m1"
|
||||
|
||||
goTo.marker();
|
||||
verify.completionListIsEmpty();
|
||||
verify.completionListAllowsNewIdentifier();
|
||||
Reference in New Issue
Block a user