Skip to content

Commit 8491f70

Browse files
committed
Merge branch 'master' into esau-squash
# Conflicts: # tests/baselines/reference/api/typescript.d.ts
2 parents 2428220 + a56b272 commit 8491f70

33 files changed

+1399
-191
lines changed

src/compiler/binder.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2305,18 +2305,22 @@ namespace ts {
23052305
}
23062306

23072307
function setCommonJsModuleIndicator(node: Node) {
2308+
if (file.externalModuleIndicator) {
2309+
return false;
2310+
}
23082311
if (!file.commonJsModuleIndicator) {
23092312
file.commonJsModuleIndicator = node;
2310-
if (!file.externalModuleIndicator) {
2311-
bindSourceFileAsExternalModule();
2312-
}
2313+
bindSourceFileAsExternalModule();
23132314
}
2315+
return true;
23142316
}
23152317

23162318
function bindExportsPropertyAssignment(node: BinaryExpression) {
23172319
// When we create a property via 'exports.foo = bar', the 'exports.foo' property access
23182320
// expression is the declaration
2319-
setCommonJsModuleIndicator(node);
2321+
if (!setCommonJsModuleIndicator(node)) {
2322+
return;
2323+
}
23202324
const lhs = node.left as PropertyAccessEntityNameExpression;
23212325
const symbol = forEachIdentifierInEntityName(lhs.expression, /*parent*/ undefined, (id, symbol) => {
23222326
if (symbol) {
@@ -2337,15 +2341,15 @@ namespace ts {
23372341
// is still pointing to 'module.exports'.
23382342
// We do not want to consider this as 'export=' since a module can have only one of these.
23392343
// Similarly we do not want to treat 'module.exports = exports' as an 'export='.
2344+
if (!setCommonJsModuleIndicator(node)) {
2345+
return;
2346+
}
23402347
const assignedExpression = getRightMostAssignedExpression(node.right);
23412348
if (isEmptyObjectLiteral(assignedExpression) || container === file && isExportsOrModuleExportsOrAlias(file, assignedExpression)) {
2342-
// Mark it as a module in case there are no other exports in the file
2343-
setCommonJsModuleIndicator(node);
23442349
return;
23452350
}
23462351

23472352
// 'module.exports = expr' assignment
2348-
setCommonJsModuleIndicator(node);
23492353
const flags = exportAssignmentIsAlias(node)
23502354
? SymbolFlags.Alias // An export= with an EntityNameExpression or a ClassExpression exports all meanings of that identifier or class
23512355
: SymbolFlags.Property | SymbolFlags.ExportValue | SymbolFlags.ValueModule;

src/compiler/factory.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2587,18 +2587,41 @@ namespace ts {
25872587
return node;
25882588
}
25892589

2590-
export function createUnparsedSourceFile(text: string, map?: string): UnparsedSource {
2590+
export function createUnparsedSourceFile(text: string): UnparsedSource;
2591+
export function createUnparsedSourceFile(text: string, mapPath: string | undefined, map: string | undefined): UnparsedSource;
2592+
export function createUnparsedSourceFile(text: string, mapPath?: string, map?: string): UnparsedSource {
25912593
const node = <UnparsedSource>createNode(SyntaxKind.UnparsedSource);
25922594
node.text = text;
2595+
node.sourceMapPath = mapPath;
25932596
node.sourceMapText = map;
25942597
return node;
25952598
}
2596-
2597-
export function createInputFiles(javascript: string, declaration: string, javascriptMapText?: string, declarationMapText?: string): InputFiles {
2599+
export function createInputFiles(
2600+
javascript: string,
2601+
declaration: string
2602+
): InputFiles;
2603+
export function createInputFiles(
2604+
javascript: string,
2605+
declaration: string,
2606+
javascriptMapPath: string | undefined,
2607+
javascriptMapText: string | undefined,
2608+
declarationMapPath: string | undefined,
2609+
declarationMapText: string | undefined
2610+
): InputFiles;
2611+
export function createInputFiles(
2612+
javascript: string,
2613+
declaration: string,
2614+
javascriptMapPath?: string,
2615+
javascriptMapText?: string,
2616+
declarationMapPath?: string,
2617+
declarationMapText?: string
2618+
): InputFiles {
25982619
const node = <InputFiles>createNode(SyntaxKind.InputFiles);
25992620
node.javascriptText = javascript;
2621+
node.javascriptMapPath = javascriptMapPath;
26002622
node.javascriptMapText = javascriptMapText;
26012623
node.declarationText = declaration;
2624+
node.declarationMapPath = declarationMapPath;
26022625
node.declarationMapText = declarationMapText;
26032626
return node;
26042627
}

src/compiler/moduleSpecifiers.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,16 @@ namespace ts.moduleSpecifiers {
133133
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? fileExtensionIs(text, Extension.Js) : undefined) || false;
134134
}
135135

136-
function discoverProbableSymlinks(files: ReadonlyArray<SourceFile>) {
136+
function discoverProbableSymlinks(files: ReadonlyArray<SourceFile>, getCanonicalFileName: (file: string) => string, host: ModuleSpecifierResolutionHost) {
137137
const symlinks = mapDefined(files, sf =>
138138
sf.resolvedModules && firstDefinedIterator(sf.resolvedModules.values(), res =>
139139
res && res.originalPath && res.resolvedFileName !== res.originalPath ? [res.resolvedFileName, res.originalPath] : undefined));
140140
const result = createMap<string>();
141141
if (symlinks) {
142+
const currentDirectory = host.getCurrentDirectory ? host.getCurrentDirectory() : "";
142143
for (const [resolvedPath, originalPath] of symlinks) {
143-
const resolvedParts = getPathComponents(resolvedPath);
144-
const originalParts = getPathComponents(originalPath);
144+
const resolvedParts = getPathComponents(toPath(resolvedPath, currentDirectory, getCanonicalFileName));
145+
const originalParts = getPathComponents(toPath(originalPath, currentDirectory, getCanonicalFileName));
145146
while (resolvedParts[resolvedParts.length - 1] === originalParts[originalParts.length - 1]) {
146147
resolvedParts.pop();
147148
originalParts.pop();
@@ -153,12 +154,13 @@ namespace ts.moduleSpecifiers {
153154
}
154155

155156
function getAllModulePathsUsingIndirectSymlinks(files: ReadonlyArray<SourceFile>, target: string, getCanonicalFileName: (file: string) => string, host: ModuleSpecifierResolutionHost) {
156-
const links = discoverProbableSymlinks(files);
157+
const links = discoverProbableSymlinks(files, getCanonicalFileName, host);
157158
const paths = arrayFrom(links.keys());
158159
let options: string[] | undefined;
160+
const compareStrings = (!host.useCaseSensitiveFileNames || host.useCaseSensitiveFileNames()) ? compareStringsCaseSensitive : compareStringsCaseInsensitive;
159161
for (const path of paths) {
160162
const resolved = links.get(path)!;
161-
if (startsWith(target, resolved + "/")) {
163+
if (compareStrings(target.slice(0, resolved.length + 1), resolved + "/") === Comparison.EqualTo) {
162164
const relative = getRelativePathFromDirectory(resolved, target, getCanonicalFileName);
163165
const option = resolvePath(path, relative);
164166
if (!host.fileExists || host.fileExists(option)) {
@@ -167,12 +169,11 @@ namespace ts.moduleSpecifiers {
167169
}
168170
}
169171
}
170-
const resolvedtarget = host.getCurrentDirectory ? resolvePath(host.getCurrentDirectory(), target) : target;
171172
if (options) {
172-
options.push(resolvedtarget); // Since these are speculative, we also include the original resolved name as a possibility
173+
options.push(target); // Since these are speculative, we also include the original resolved name as a possibility
173174
return options;
174175
}
175-
return [resolvedtarget];
176+
return [target];
176177
}
177178

178179
/**
@@ -183,7 +184,7 @@ namespace ts.moduleSpecifiers {
183184
const symlinks = mapDefined(files, sf =>
184185
sf.resolvedModules && firstDefinedIterator(sf.resolvedModules.values(), res =>
185186
res && res.resolvedFileName === fileName ? res.originalPath : undefined));
186-
return symlinks.length === 0 ? getAllModulePathsUsingIndirectSymlinks(files, fileName, getCanonicalFileName, host) : symlinks;
187+
return symlinks.length === 0 ? getAllModulePathsUsingIndirectSymlinks(files, getNormalizedAbsolutePath(fileName, host.getCurrentDirectory ? host.getCurrentDirectory() : ""), getCanonicalFileName, host) : symlinks;
187188
}
188189

189190
function getRelativePathNParents(relativePath: string): number {

src/compiler/program.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,10 +1240,12 @@ namespace ts {
12401240

12411241
const dtsFilename = changeExtension(resolvedRefOpts.options.outFile, ".d.ts");
12421242
const js = host.readFile(resolvedRefOpts.options.outFile) || `/* Input file ${resolvedRefOpts.options.outFile} was missing */\r\n`;
1243-
const jsMap = host.readFile(resolvedRefOpts.options.outFile + ".map"); // TODO: try to read sourceMappingUrl comment from the js file
1243+
const jsMapPath = resolvedRefOpts.options.outFile + ".map"; // TODO: try to read sourceMappingUrl comment from the file
1244+
const jsMap = host.readFile(jsMapPath);
12441245
const dts = host.readFile(dtsFilename) || `/* Input file ${dtsFilename} was missing */\r\n`;
1245-
const dtsMap = host.readFile(dtsFilename + ".map");
1246-
const node = createInputFiles(js, dts, jsMap, dtsMap);
1246+
const dtsMapPath = dtsFilename + ".map";
1247+
const dtsMap = host.readFile(dtsMapPath);
1248+
const node = createInputFiles(js, dts, jsMap && jsMapPath, jsMap, dtsMap && dtsMapPath, dtsMap);
12471249
nodes.push(node);
12481250
}
12491251
}

src/compiler/sourcemap.ts

Lines changed: 48 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,6 @@ namespace ts {
9999
let sourceMapDataList: SourceMapData[] | undefined;
100100
let disabled: boolean = !(compilerOptions.sourceMap || compilerOptions.inlineSourceMap);
101101

102-
let completedSections: SourceMapSectionDefinition[];
103-
let sectionStartLine: number;
104-
let sectionStartColumn: number;
105-
106102
return {
107103
initialize,
108104
reset,
@@ -150,9 +146,6 @@ namespace ts {
150146
lastEncodedNameIndex = 0;
151147

152148
// Initialize source map data
153-
completedSections = [];
154-
sectionStartLine = 1;
155-
sectionStartColumn = 1;
156149
sourceMapData = {
157150
sourceMapFilePath,
158151
jsSourceMappingURL: !compilerOptions.inlineSourceMap ? getBaseFileName(normalizeSlashes(sourceMapFilePath)) : undefined!, // TODO: GH#18217
@@ -221,9 +214,6 @@ namespace ts {
221214
lastEncodedNameIndex = undefined;
222215
sourceMapData = undefined!;
223216
sourceMapDataList = undefined!;
224-
completedSections = undefined!;
225-
sectionStartLine = undefined!;
226-
sectionStartColumn = undefined!;
227217
}
228218

229219
interface SourceMapSection {
@@ -233,7 +223,7 @@ namespace ts {
233223
sources: string[];
234224
names?: string[];
235225
mappings: string;
236-
sourcesContent?: string[];
226+
sourcesContent?: (string | null)[];
237227
sections?: undefined;
238228
}
239229

@@ -261,26 +251,6 @@ namespace ts {
261251
};
262252
}
263253

264-
function resetSectionalData(): void {
265-
sourceMapData.sourceMapSources = [];
266-
sourceMapData.sourceMapNames = [];
267-
sourceMapData.sourceMapMappings = "";
268-
sourceMapData.sourceMapSourcesContent = compilerOptions.inlineSources ? [] : undefined;
269-
}
270-
271-
function generateMap(): SourceMap {
272-
if (completedSections.length) {
273-
captureSectionalSpanIfNeeded(/*reset*/ false);
274-
return {
275-
version: 3,
276-
file: sourceMapData.sourceMapFile,
277-
sections: completedSections
278-
};
279-
}
280-
else {
281-
return captureSection();
282-
}
283-
}
284254

285255
// Encoding for sourcemap span
286256
function encodeLastRecordedSourceMapSpan() {
@@ -350,8 +320,8 @@ namespace ts {
350320
sourceLinePos.line++;
351321
sourceLinePos.character++;
352322

353-
const emittedLine = writer.getLine() - sectionStartLine + 1;
354-
const emittedColumn = emittedLine === 0 ? (writer.getColumn() - sectionStartColumn + 1) : writer.getColumn();
323+
const emittedLine = writer.getLine();
324+
const emittedColumn = writer.getColumn();
355325

356326
// If this location wasn't recorded or the location in source is going backwards, record the span
357327
if (!lastRecordedSourceMapSpan ||
@@ -386,13 +356,8 @@ namespace ts {
386356
}
387357
}
388358

389-
function captureSectionalSpanIfNeeded(reset: boolean) {
390-
if (lastRecordedSourceMapSpan && lastRecordedSourceMapSpan === lastEncodedSourceMapSpan) { // If we've recorded some spans, save them
391-
completedSections.push({ offset: { line: sectionStartLine - 1, column: sectionStartColumn - 1 }, map: captureSection() });
392-
if (reset) {
393-
resetSectionalData();
394-
}
395-
}
359+
function isPossiblySourceMap(x: {}): x is SourceMapSection {
360+
return typeof x === "object" && !!(x as any).mappings && typeof (x as any).mappings === "string" && !!(x as any).sources;
396361
}
397362

398363
/**
@@ -409,7 +374,6 @@ namespace ts {
409374

410375
if (node) {
411376
if (isUnparsedSource(node) && node.sourceMapText !== undefined) {
412-
captureSectionalSpanIfNeeded(/*reset*/ true);
413377
const text = node.sourceMapText;
414378
let parsed: {} | undefined;
415379
try {
@@ -418,24 +382,41 @@ namespace ts {
418382
catch {
419383
// empty
420384
}
421-
const offset = { line: writer.getLine() - 1, column: writer.getColumn() - 1 };
422-
completedSections.push(parsed
423-
? {
424-
offset,
425-
map: parsed as SourceMap
426-
}
427-
: {
428-
offset,
429-
// This is just passes the buck on sourcemaps we don't really understand, instead of issuing an error (which would be difficult this late)
430-
url: `data:application/json;charset=utf-8;base64,${base64encode(sys, text)}`
431-
}
432-
);
433-
const emitResult = emitCallback(hint, node);
434-
sectionStartLine = writer.getLine();
435-
sectionStartColumn = writer.getColumn();
436-
lastRecordedSourceMapSpan = undefined!;
437-
lastEncodedSourceMapSpan = defaultLastEncodedSourceMapSpan;
438-
return emitResult;
385+
if (!parsed || !isPossiblySourceMap(parsed)) {
386+
return emitCallback(hint, node);
387+
}
388+
const offsetLine = writer.getLine();
389+
const firstLineColumnOffset = writer.getColumn();
390+
// First, decode the old component sourcemap
391+
const originalMap = parsed;
392+
sourcemaps.calculateDecodedMappings(originalMap, (raw): void => {
393+
// Apply offsets to each position and fixup source entries
394+
const rawPath = originalMap.sources[raw.sourceIndex];
395+
const relativePath = originalMap.sourceRoot ? combinePaths(originalMap.sourceRoot, rawPath) : rawPath;
396+
const combinedPath = combinePaths(getDirectoryPath(node.sourceMapPath!), relativePath);
397+
const sourcesDirectoryPath = compilerOptions.sourceRoot ? host.getCommonSourceDirectory() : sourceMapDir;
398+
const resolvedPath = getRelativePathToDirectoryOrUrl(
399+
sourcesDirectoryPath,
400+
combinedPath,
401+
host.getCurrentDirectory(),
402+
host.getCanonicalFileName,
403+
/*isAbsolutePathAnUrl*/ true
404+
);
405+
const absolutePath = toPath(resolvedPath, sourcesDirectoryPath, host.getCanonicalFileName);
406+
// tslint:disable-next-line:no-null-keyword
407+
setupSourceEntry(absolutePath, originalMap.sourcesContent ? originalMap.sourcesContent[raw.sourceIndex] : null); // TODO: Lookup content for inlining?
408+
const newIndex = sourceMapData.sourceMapSources.indexOf(resolvedPath);
409+
// Then reencode all the updated spans into the overall map
410+
encodeLastRecordedSourceMapSpan();
411+
lastRecordedSourceMapSpan = {
412+
...raw,
413+
emittedLine: raw.emittedLine + offsetLine - 1,
414+
emittedColumn: raw.emittedLine === 0 ? (raw.emittedColumn + firstLineColumnOffset - 1) : raw.emittedColumn,
415+
sourceIndex: newIndex,
416+
};
417+
});
418+
// And actually emit the text these sourcemaps are for
419+
return emitCallback(hint, node);
439420
}
440421
const emitNode = node.emitNode;
441422
const emitFlags = emitNode && emitNode.flags || EmitFlags.None;
@@ -529,13 +510,17 @@ namespace ts {
529510
return;
530511
}
531512

513+
setupSourceEntry(sourceFile.fileName, sourceFile.text);
514+
}
515+
516+
function setupSourceEntry(fileName: string, content: string | null) {
532517
// Add the file to tsFilePaths
533518
// If sourceroot option: Use the relative path corresponding to the common directory path
534519
// otherwise source locations relative to map file location
535520
const sourcesDirectoryPath = compilerOptions.sourceRoot ? host.getCommonSourceDirectory() : sourceMapDir;
536521

537522
const source = getRelativePathToDirectoryOrUrl(sourcesDirectoryPath,
538-
currentSource.fileName,
523+
fileName,
539524
host.getCurrentDirectory(),
540525
host.getCanonicalFileName,
541526
/*isAbsolutePathAnUrl*/ true);
@@ -546,10 +531,10 @@ namespace ts {
546531
sourceMapData.sourceMapSources.push(source);
547532

548533
// The one that can be used from program to get the actual source file
549-
sourceMapData.inputSourceFileNames.push(currentSource.fileName);
534+
sourceMapData.inputSourceFileNames.push(fileName);
550535

551536
if (compilerOptions.inlineSources) {
552-
sourceMapData.sourceMapSourcesContent!.push(currentSource.text);
537+
sourceMapData.sourceMapSourcesContent!.push(content);
553538
}
554539
}
555540
}
@@ -564,7 +549,7 @@ namespace ts {
564549

565550
encodeLastRecordedSourceMapSpan();
566551

567-
return JSON.stringify(generateMap());
552+
return JSON.stringify(captureSection());
568553
}
569554

570555
/**

0 commit comments

Comments
 (0)