Skip to content

Commit 9f6f871

Browse files
committed
Merge pull request microsoft#7507 from Microsoft/preprocessFindAugmentations
find module augmentations in preprocessor
2 parents 94ada07 + 2b2092b commit 9f6f871

2 files changed

Lines changed: 282 additions & 67 deletions

File tree

src/services/services.ts

Lines changed: 100 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2147,8 +2147,23 @@ namespace ts {
21472147
export function preProcessFile(sourceText: string, readImportFiles = true, detectJavaScriptImports = false): PreProcessedFileInfo {
21482148
const referencedFiles: FileReference[] = [];
21492149
const importedFiles: FileReference[] = [];
2150-
let ambientExternalModules: string[];
2150+
let ambientExternalModules: { ref: FileReference, depth: number }[];
21512151
let isNoDefaultLib = false;
2152+
let braceNesting = 0;
2153+
// assume that text represent an external module if it contains at least one top level import/export
2154+
// ambient modules that are found inside external modules are interpreted as module augmentations
2155+
let externalModule = false;
2156+
2157+
function nextToken() {
2158+
const token = scanner.scan();
2159+
if (token === SyntaxKind.OpenBraceToken) {
2160+
braceNesting++;
2161+
}
2162+
else if (token === SyntaxKind.CloseBraceToken) {
2163+
braceNesting--;
2164+
}
2165+
return token;
2166+
}
21522167

21532168
function processTripleSlashDirectives(): void {
21542169
const commentRanges = getLeadingCommentRanges(sourceText, 0);
@@ -2165,21 +2180,33 @@ namespace ts {
21652180
});
21662181
}
21672182

2183+
function getFileReference() {
2184+
const file = scanner.getTokenValue();
2185+
const pos = scanner.getTokenPos();
2186+
return {
2187+
fileName: file,
2188+
pos: pos,
2189+
end: pos + file.length
2190+
};
2191+
}
2192+
21682193
function recordAmbientExternalModule(): void {
21692194
if (!ambientExternalModules) {
21702195
ambientExternalModules = [];
21712196
}
2172-
ambientExternalModules.push(scanner.getTokenValue());
2197+
ambientExternalModules.push({ ref: getFileReference(), depth: braceNesting });
21732198
}
21742199

21752200
function recordModuleName() {
2176-
const importPath = scanner.getTokenValue();
2177-
const pos = scanner.getTokenPos();
2178-
importedFiles.push({
2179-
fileName: importPath,
2180-
pos: pos,
2181-
end: pos + importPath.length
2182-
});
2201+
importedFiles.push(getFileReference());
2202+
2203+
markAsExternalModuleIfTopLevel();
2204+
}
2205+
2206+
function markAsExternalModuleIfTopLevel() {
2207+
if (braceNesting === 0) {
2208+
externalModule = true;
2209+
}
21832210
}
21842211

21852212
/**
@@ -2189,9 +2216,9 @@ namespace ts {
21892216
let token = scanner.getToken();
21902217
if (token === SyntaxKind.DeclareKeyword) {
21912218
// declare module "mod"
2192-
token = scanner.scan();
2219+
token = nextToken();
21932220
if (token === SyntaxKind.ModuleKeyword) {
2194-
token = scanner.scan();
2221+
token = nextToken();
21952222
if (token === SyntaxKind.StringLiteral) {
21962223
recordAmbientExternalModule();
21972224
}
@@ -2208,17 +2235,18 @@ namespace ts {
22082235
function tryConsumeImport(): boolean {
22092236
let token = scanner.getToken();
22102237
if (token === SyntaxKind.ImportKeyword) {
2211-
token = scanner.scan();
2238+
2239+
token = nextToken();
22122240
if (token === SyntaxKind.StringLiteral) {
22132241
// import "mod";
22142242
recordModuleName();
22152243
return true;
22162244
}
22172245
else {
22182246
if (token === SyntaxKind.Identifier || isKeyword(token)) {
2219-
token = scanner.scan();
2247+
token = nextToken();
22202248
if (token === SyntaxKind.FromKeyword) {
2221-
token = scanner.scan();
2249+
token = nextToken();
22222250
if (token === SyntaxKind.StringLiteral) {
22232251
// import d from "mod";
22242252
recordModuleName();
@@ -2232,7 +2260,7 @@ namespace ts {
22322260
}
22332261
else if (token === SyntaxKind.CommaToken) {
22342262
// consume comma and keep going
2235-
token = scanner.scan();
2263+
token = nextToken();
22362264
}
22372265
else {
22382266
// unknown syntax
@@ -2241,17 +2269,17 @@ namespace ts {
22412269
}
22422270

22432271
if (token === SyntaxKind.OpenBraceToken) {
2244-
token = scanner.scan();
2272+
token = nextToken();
22452273
// consume "{ a as B, c, d as D}" clauses
22462274
// make sure that it stops on EOF
22472275
while (token !== SyntaxKind.CloseBraceToken && token !== SyntaxKind.EndOfFileToken) {
2248-
token = scanner.scan();
2276+
token = nextToken();
22492277
}
22502278

22512279
if (token === SyntaxKind.CloseBraceToken) {
2252-
token = scanner.scan();
2280+
token = nextToken();
22532281
if (token === SyntaxKind.FromKeyword) {
2254-
token = scanner.scan();
2282+
token = nextToken();
22552283
if (token === SyntaxKind.StringLiteral) {
22562284
// import {a as A} from "mod";
22572285
// import d, {a, b as B} from "mod"
@@ -2261,13 +2289,13 @@ namespace ts {
22612289
}
22622290
}
22632291
else if (token === SyntaxKind.AsteriskToken) {
2264-
token = scanner.scan();
2292+
token = nextToken();
22652293
if (token === SyntaxKind.AsKeyword) {
2266-
token = scanner.scan();
2294+
token = nextToken();
22672295
if (token === SyntaxKind.Identifier || isKeyword(token)) {
2268-
token = scanner.scan();
2296+
token = nextToken();
22692297
if (token === SyntaxKind.FromKeyword) {
2270-
token = scanner.scan();
2298+
token = nextToken();
22712299
if (token === SyntaxKind.StringLiteral) {
22722300
// import * as NS from "mod"
22732301
// import d, * as NS from "mod"
@@ -2288,19 +2316,20 @@ namespace ts {
22882316
function tryConsumeExport(): boolean {
22892317
let token = scanner.getToken();
22902318
if (token === SyntaxKind.ExportKeyword) {
2291-
token = scanner.scan();
2319+
markAsExternalModuleIfTopLevel();
2320+
token = nextToken();
22922321
if (token === SyntaxKind.OpenBraceToken) {
2293-
token = scanner.scan();
2322+
token = nextToken();
22942323
// consume "{ a as B, c, d as D}" clauses
22952324
// make sure it stops on EOF
22962325
while (token !== SyntaxKind.CloseBraceToken && token !== SyntaxKind.EndOfFileToken) {
2297-
token = scanner.scan();
2326+
token = nextToken();
22982327
}
22992328

23002329
if (token === SyntaxKind.CloseBraceToken) {
2301-
token = scanner.scan();
2330+
token = nextToken();
23022331
if (token === SyntaxKind.FromKeyword) {
2303-
token = scanner.scan();
2332+
token = nextToken();
23042333
if (token === SyntaxKind.StringLiteral) {
23052334
// export {a as A} from "mod";
23062335
// export {a, b as B} from "mod"
@@ -2310,19 +2339,19 @@ namespace ts {
23102339
}
23112340
}
23122341
else if (token === SyntaxKind.AsteriskToken) {
2313-
token = scanner.scan();
2342+
token = nextToken();
23142343
if (token === SyntaxKind.FromKeyword) {
2315-
token = scanner.scan();
2344+
token = nextToken();
23162345
if (token === SyntaxKind.StringLiteral) {
23172346
// export * from "mod"
23182347
recordModuleName();
23192348
}
23202349
}
23212350
}
23222351
else if (token === SyntaxKind.ImportKeyword) {
2323-
token = scanner.scan();
2352+
token = nextToken();
23242353
if (token === SyntaxKind.Identifier || isKeyword(token)) {
2325-
token = scanner.scan();
2354+
token = nextToken();
23262355
if (token === SyntaxKind.EqualsToken) {
23272356
if (tryConsumeRequireCall(/*skipCurrentToken*/ true)) {
23282357
return true;
@@ -2338,11 +2367,11 @@ namespace ts {
23382367
}
23392368

23402369
function tryConsumeRequireCall(skipCurrentToken: boolean): boolean {
2341-
let token = skipCurrentToken ? scanner.scan() : scanner.getToken();
2370+
let token = skipCurrentToken ? nextToken() : scanner.getToken();
23422371
if (token === SyntaxKind.RequireKeyword) {
2343-
token = scanner.scan();
2372+
token = nextToken();
23442373
if (token === SyntaxKind.OpenParenToken) {
2345-
token = scanner.scan();
2374+
token = nextToken();
23462375
if (token === SyntaxKind.StringLiteral) {
23472376
// require("mod");
23482377
recordModuleName();
@@ -2356,17 +2385,17 @@ namespace ts {
23562385
function tryConsumeDefine(): boolean {
23572386
let token = scanner.getToken();
23582387
if (token === SyntaxKind.Identifier && scanner.getTokenValue() === "define") {
2359-
token = scanner.scan();
2388+
token = nextToken();
23602389
if (token !== SyntaxKind.OpenParenToken) {
23612390
return true;
23622391
}
23632392

2364-
token = scanner.scan();
2393+
token = nextToken();
23652394
if (token === SyntaxKind.StringLiteral) {
23662395
// looks like define ("modname", ... - skip string literal and comma
2367-
token = scanner.scan();
2396+
token = nextToken();
23682397
if (token === SyntaxKind.CommaToken) {
2369-
token = scanner.scan();
2398+
token = nextToken();
23702399
}
23712400
else {
23722401
// unexpected token
@@ -2380,7 +2409,7 @@ namespace ts {
23802409
}
23812410

23822411
// skip open bracket
2383-
token = scanner.scan();
2412+
token = nextToken();
23842413
let i = 0;
23852414
// scan until ']' or EOF
23862415
while (token !== SyntaxKind.CloseBracketToken && token !== SyntaxKind.EndOfFileToken) {
@@ -2390,7 +2419,7 @@ namespace ts {
23902419
i++;
23912420
}
23922421

2393-
token = scanner.scan();
2422+
token = nextToken();
23942423
}
23952424
return true;
23962425

@@ -2400,7 +2429,7 @@ namespace ts {
24002429

24012430
function processImports(): void {
24022431
scanner.setText(sourceText);
2403-
scanner.scan();
2432+
nextToken();
24042433
// Look for:
24052434
// import "mod";
24062435
// import d from "mod"
@@ -2427,7 +2456,7 @@ namespace ts {
24272456
continue;
24282457
}
24292458
else {
2430-
scanner.scan();
2459+
nextToken();
24312460
}
24322461
}
24332462

@@ -2438,7 +2467,34 @@ namespace ts {
24382467
processImports();
24392468
}
24402469
processTripleSlashDirectives();
2441-
return { referencedFiles, importedFiles, isLibFile: isNoDefaultLib, ambientExternalModules };
2470+
if (externalModule) {
2471+
// for external modules module all nested ambient modules are augmentations
2472+
if (ambientExternalModules) {
2473+
// move all detected ambient modules to imported files since they need to be resolved
2474+
for (const decl of ambientExternalModules) {
2475+
importedFiles.push(decl.ref);
2476+
}
2477+
}
2478+
return { referencedFiles, importedFiles, isLibFile: isNoDefaultLib, ambientExternalModules: undefined };
2479+
}
2480+
else {
2481+
// for global scripts ambient modules still can have augmentations - look for ambient modules with depth > 0
2482+
let ambientModuleNames: string[];
2483+
if (ambientExternalModules) {
2484+
for (const decl of ambientExternalModules) {
2485+
if (decl.depth === 0) {
2486+
if (!ambientModuleNames) {
2487+
ambientModuleNames = [];
2488+
}
2489+
ambientModuleNames.push(decl.ref.fileName);
2490+
}
2491+
else {
2492+
importedFiles.push(decl.ref);
2493+
}
2494+
}
2495+
}
2496+
return { referencedFiles, importedFiles, isLibFile: isNoDefaultLib, ambientExternalModules: ambientModuleNames };
2497+
}
24422498
}
24432499

24442500
/// Helpers

0 commit comments

Comments
 (0)