diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index d3363285af..753e02c7a0 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1181,9 +1181,9 @@ namespace ts { lastContainer = next; } - function declareSymbolAndAddToSymbolTable(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): void { + function declareSymbolAndAddToSymbolTable(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol { // Just call this directly so that the return type of this function stays "void". - declareSymbolAndAddToSymbolTableWorker(node, symbolFlags, symbolExcludes); + return declareSymbolAndAddToSymbolTableWorker(node, symbolFlags, symbolExcludes); } function declareSymbolAndAddToSymbolTableWorker(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol { @@ -1298,14 +1298,10 @@ namespace ts { } } + const symbol = declareSymbolAndAddToSymbolTable(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes); + if (pattern) { - // TODO: don't really need such a symbol in container.locals... - const symbol = declareSymbol(container.locals, undefined, node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes); - file.patternAmbientModules = file.patternAmbientModules || []; - file.patternAmbientModules.push({ pattern, symbol }); - } - else { - declareSymbolAndAddToSymbolTable(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes); + (file.patternAmbientModules || (file.patternAmbientModules = [])).push({ pattern, symbol }); } } } @@ -2084,10 +2080,10 @@ namespace ts { checkStrictModeFunctionName(node); if (inStrictMode) { checkStrictModeFunctionDeclaration(node); - return bindBlockScopedDeclaration(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes); + bindBlockScopedDeclaration(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes); } else { - return declareSymbolAndAddToSymbolTable(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes); + declareSymbolAndAddToSymbolTable(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes); } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3e66cf1661..149f21734a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1292,9 +1292,11 @@ namespace ts { return undefined; } - const patternModuleSymbol = getPatternAmbientModule(moduleName); - if (patternModuleSymbol) { - return getMergedSymbol(patternModuleSymbol); + if (patternAmbientModules) { + const pattern = findBestPatternMatch(patternAmbientModules, _ => _.pattern, moduleName); + if (pattern) { + return getMergedSymbol(pattern.symbol); + } } if (moduleNotFoundError) { @@ -1304,16 +1306,6 @@ namespace ts { return undefined; } - /** Get an ambient module with a wildcard ("*") in it. */ - function getPatternAmbientModule(name: string): Symbol | undefined { - if (patternAmbientModules) { - const pattern = findBestPatternMatch(patternAmbientModules, _ => _.pattern, name); - if (pattern) { - return pattern.symbol; - } - } - } - // An external module with an 'export =' declaration resolves to the target of the 'export =' declaration, // and an external module with no 'export =' declaration resolves to the module itself. function resolveExternalModuleSymbol(moduleSymbol: Symbol): Symbol { diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 1677f61c15..3267737a3e 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -95,6 +95,7 @@ namespace ts { return compilerOptions.traceResolution && host.trace !== undefined; } + /* @internal */ export function hasZeroOrOneAsteriskCharacter(str: string): boolean { let seenAsterisk = false; for (let i = 0; i < str.length; i++) { @@ -502,7 +503,7 @@ namespace ts { if (state.traceEnabled) { trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName); } - matchedPattern = matchPatternOrExact(Object.keys(state.compilerOptions.paths), moduleName); + matchedPattern = matchPatternOrExact(getKeys(state.compilerOptions.paths), moduleName); } if (matchedPattern) { @@ -570,6 +571,7 @@ namespace ts { } /** Return the object corresponding to the best pattern to match `candidate`. */ + /* @internal */ export function findBestPatternMatch(values: T[], getPattern: (value: T) => Pattern, candidate: string): T | undefined { let matchedValue: T | undefined = undefined; // use length of prefix as betterness criteria @@ -592,6 +594,7 @@ namespace ts { endsWith(candidate, suffix); } + /* @internal */ export function tryParsePattern(pattern: string): Pattern | undefined { // This should be verified outside of here and a proper error thrown. Debug.assert(hasZeroOrOneAsteriskCharacter(pattern)); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a6f19f121c..bcc4bbcf69 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2137,12 +2137,14 @@ namespace ts { } /** Represents a "prefix*suffix" pattern. */ + /* @internal */ export interface Pattern { prefix: string; suffix: string; } - + /** Used to track a `declare module "foo*"`-like declaration. */ + /* @internal */ export interface PatternAmbientModule { pattern: Pattern; symbol: Symbol;