Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 18a7c3f

Browse files
author
Andy
authored
For import fix, prefer symlink over a real path (microsoft#20395)
* For import fix, prefer symlink over a real path * fixes * Use best result from all symlinks * Make originalPath optional more * Only include real path if a symlink isn't available
1 parent c2fc5ea commit 18a7c3f

20 files changed

+282
-162
lines changed

src/compiler/builder.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,9 @@ namespace ts {
468468
}
469469

470470
function getReferencedByPaths(referencedFilePath: Path) {
471-
return mapDefinedIter(references.entries(), ([filePath, referencesInFile]) =>
471+
return arrayFrom(mapDefinedIterator(references.entries(), ([filePath, referencesInFile]) =>
472472
referencesInFile.has(referencedFilePath) ? filePath as Path : undefined
473-
);
473+
));
474474
}
475475

476476
function getFilesAffectedByUpdatedShape(program: Program, sourceFile: SourceFile): ReadonlyArray<SourceFile> {
@@ -504,7 +504,7 @@ namespace ts {
504504
}
505505

506506
// Return array of values that needs emit
507-
return flatMapIter(seenFileNamesMap.values(), value => value);
507+
return arrayFrom(mapDefinedIterator(seenFileNamesMap.values(), value => value));
508508
}
509509
}
510510
}

src/compiler/core.ts

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,19 @@ namespace ts {
191191
return undefined;
192192
}
193193

194+
export function firstDefinedIterator<T, U>(iter: Iterator<T>, callback: (element: T) => U | undefined): U | undefined {
195+
while (true) {
196+
const { value, done } = iter.next();
197+
if (done) {
198+
return undefined;
199+
}
200+
const result = callback(value);
201+
if (result !== undefined) {
202+
return result;
203+
}
204+
}
205+
}
206+
194207
/**
195208
* Iterates through the parent chain of a node and performs the callback on each parent until the callback
196209
* returns a truthy value, then returns that value.
@@ -474,22 +487,32 @@ namespace ts {
474487
return result;
475488
}
476489

477-
export function flatMapIter<T, U>(iter: Iterator<T>, mapfn: (x: T) => U | U[] | undefined): U[] {
478-
const result: U[] = [];
479-
while (true) {
480-
const { value, done } = iter.next();
481-
if (done) break;
482-
const res = mapfn(value);
483-
if (res) {
484-
if (isArray(res)) {
485-
result.push(...res);
486-
}
487-
else {
488-
result.push(res);
490+
export function flatMapIterator<T, U>(iter: Iterator<T>, mapfn: (x: T) => U[] | Iterator<U> | undefined): Iterator<U> {
491+
const first = iter.next();
492+
if (first.done) {
493+
return emptyIterator;
494+
}
495+
let currentIter = getIterator(first.value);
496+
return {
497+
next() {
498+
while (true) {
499+
const currentRes = currentIter.next();
500+
if (!currentRes.done) {
501+
return currentRes;
502+
}
503+
const iterRes = iter.next();
504+
if (iterRes.done) {
505+
return iterRes;
506+
}
507+
currentIter = getIterator(iterRes.value);
489508
}
490-
}
509+
},
510+
};
511+
512+
function getIterator(x: T): Iterator<U> {
513+
const res = mapfn(x);
514+
return res === undefined ? emptyIterator : isArray(res) ? arrayIterator(res) : res;
491515
}
492-
return result;
493516
}
494517

495518
/**
@@ -537,17 +560,34 @@ namespace ts {
537560
return result;
538561
}
539562

540-
export function mapDefinedIter<T, U>(iter: Iterator<T>, mapFn: (x: T) => U | undefined): U[] {
541-
const result: U[] = [];
542-
while (true) {
543-
const { value, done } = iter.next();
544-
if (done) break;
545-
const res = mapFn(value);
546-
if (res !== undefined) {
547-
result.push(res);
563+
export function mapDefinedIterator<T, U>(iter: Iterator<T>, mapFn: (x: T) => U | undefined): Iterator<U> {
564+
return {
565+
next() {
566+
while (true) {
567+
const res = iter.next();
568+
if (res.done) {
569+
return res;
570+
}
571+
const value = mapFn(res.value);
572+
if (value !== undefined) {
573+
return { value, done: false };
574+
}
575+
}
548576
}
549-
}
550-
return result;
577+
};
578+
}
579+
580+
export const emptyIterator: Iterator<never> = { next: () => ({ value: undefined as never, done: true }) };
581+
582+
export function singleIterator<T>(value: T): Iterator<T> {
583+
let done = false;
584+
return {
585+
next() {
586+
const wasDone = done;
587+
done = true;
588+
return wasDone ? { value: undefined as never, done: true } : { value, done: false };
589+
}
590+
};
551591
}
552592

553593
/**
@@ -1360,7 +1400,7 @@ namespace ts {
13601400
/**
13611401
* Tests whether a value is an array.
13621402
*/
1363-
export function isArray(value: any): value is ReadonlyArray<any> {
1403+
export function isArray(value: any): value is ReadonlyArray<{}> {
13641404
return Array.isArray ? Array.isArray(value) : value instanceof Array;
13651405
}
13661406

src/compiler/moduleNameResolver.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ namespace ts {
6464
return { fileName: resolved.path, packageId: resolved.packageId };
6565
}
6666

67-
function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, isExternalLibraryImport: boolean, failedLookupLocations: string[]): ResolvedModuleWithFailedLookupLocations {
67+
function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, originalPath: string | undefined, isExternalLibraryImport: boolean, failedLookupLocations: string[]): ResolvedModuleWithFailedLookupLocations {
6868
return {
69-
resolvedModule: resolved && { resolvedFileName: resolved.path, extension: resolved.extension, isExternalLibraryImport, packageId: resolved.packageId },
69+
resolvedModule: resolved && { resolvedFileName: resolved.path, originalPath, extension: resolved.extension, isExternalLibraryImport, packageId: resolved.packageId },
7070
failedLookupLocations
7171
};
7272
}
@@ -732,12 +732,12 @@ namespace ts {
732732

733733
const result = jsOnly ? tryResolve(Extensions.JavaScript) : (tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript));
734734
if (result && result.value) {
735-
const { resolved, isExternalLibraryImport } = result.value;
736-
return createResolvedModuleWithFailedLookupLocations(resolved, isExternalLibraryImport, failedLookupLocations);
735+
const { resolved, originalPath, isExternalLibraryImport } = result.value;
736+
return createResolvedModuleWithFailedLookupLocations(resolved, originalPath, isExternalLibraryImport, failedLookupLocations);
737737
}
738738
return { resolvedModule: undefined, failedLookupLocations };
739739

740-
function tryResolve(extensions: Extensions): SearchResult<{ resolved: Resolved, isExternalLibraryImport: boolean }> {
740+
function tryResolve(extensions: Extensions): SearchResult<{ resolved: Resolved, originalPath?: string, isExternalLibraryImport: boolean }> {
741741
const loader: ResolutionKindSpecificLoader = (extensions, candidate, failedLookupLocations, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ true);
742742
const resolved = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loader, failedLookupLocations, state);
743743
if (resolved) {
@@ -752,11 +752,17 @@ namespace ts {
752752
if (!resolved) return undefined;
753753

754754
let resolvedValue = resolved.value;
755-
if (!compilerOptions.preserveSymlinks) {
756-
resolvedValue = resolvedValue && { ...resolved.value, path: realPath(resolved.value.path, host, traceEnabled), extension: resolved.value.extension };
755+
let originalPath: string | undefined;
756+
if (!compilerOptions.preserveSymlinks && resolvedValue) {
757+
originalPath = resolvedValue.path;
758+
const path = realPath(resolved.value.path, host, traceEnabled);
759+
if (path === originalPath) {
760+
originalPath = undefined;
761+
}
762+
resolvedValue = { ...resolvedValue, path };
757763
}
758764
// For node_modules lookups, get the real path so that multiple accesses to an `npm link`-ed module do not create duplicate files.
759-
return { value: resolvedValue && { resolved: resolvedValue, isExternalLibraryImport: true } };
765+
return { value: resolvedValue && { resolved: resolvedValue, originalPath, isExternalLibraryImport: true } };
760766
}
761767
else {
762768
const { path: candidate, parts } = normalizePathAndParts(combinePaths(containingDirectory, moduleName));
@@ -1115,7 +1121,8 @@ namespace ts {
11151121
const containingDirectory = getDirectoryPath(containingFile);
11161122

11171123
const resolved = tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript);
1118-
return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*isExternalLibraryImport*/ false, failedLookupLocations);
1124+
// No originalPath because classic resolution doesn't resolve realPath
1125+
return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*originalPath*/ undefined, /*isExternalLibraryImport*/ false, failedLookupLocations);
11191126

11201127
function tryResolve(extensions: Extensions): SearchResult<Resolved> {
11211128
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, failedLookupLocations, state);
@@ -1162,7 +1169,7 @@ namespace ts {
11621169
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled };
11631170
const failedLookupLocations: string[] = [];
11641171
const resolved = loadModuleFromNodeModulesOneLevel(Extensions.DtsOnly, moduleName, globalCache, failedLookupLocations, state);
1165-
return createResolvedModuleWithFailedLookupLocations(resolved, /*isExternalLibraryImport*/ true, failedLookupLocations);
1172+
return createResolvedModuleWithFailedLookupLocations(resolved, /*originalPath*/ undefined, /*isExternalLibraryImport*/ true, failedLookupLocations);
11661173
}
11671174

11681175
/**

src/compiler/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2478,7 +2478,7 @@ namespace ts {
24782478
// Stores a mapping 'external module reference text' -> 'resolved file name' | undefined
24792479
// It is used to resolve module names in the checker.
24802480
// Content of this field should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead
2481-
/* @internal */ resolvedModules: Map<ResolvedModuleFull>;
2481+
/* @internal */ resolvedModules: Map<ResolvedModuleFull | undefined>;
24822482
/* @internal */ resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
24832483
/* @internal */ imports: ReadonlyArray<StringLiteral>;
24842484
// Identifier only if `declare global`
@@ -4243,6 +4243,8 @@ namespace ts {
42434243
* If changing this, remember to change `moduleResolutionIsEqualTo`.
42444244
*/
42454245
export interface ResolvedModuleFull extends ResolvedModule {
4246+
/* @internal */
4247+
readonly originalPath?: string;
42464248
/**
42474249
* Extension of resolvedFileName. This must match what's at the end of resolvedFileName.
42484250
* This is optional for backwards-compatibility, but will be added if not provided.

src/compiler/utilities.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ namespace ts {
101101
return oldResolution.isExternalLibraryImport === newResolution.isExternalLibraryImport &&
102102
oldResolution.extension === newResolution.extension &&
103103
oldResolution.resolvedFileName === newResolution.resolvedFileName &&
104+
oldResolution.originalPath === newResolution.originalPath &&
104105
packageIdIsEqual(oldResolution.packageId, newResolution.packageId);
105106
}
106107

@@ -3696,6 +3697,10 @@ namespace ts {
36963697
export function typeHasCallOrConstructSignatures(type: Type, checker: TypeChecker) {
36973698
return checker.getSignaturesOfType(type, SignatureKind.Call).length !== 0 || checker.getSignaturesOfType(type, SignatureKind.Construct).length !== 0;
36983699
}
3700+
3701+
export function forSomeAncestorDirectory(directory: string, callback: (directory: string) => boolean): boolean {
3702+
return !!forEachAncestorDirectory(directory, d => callback(d) ? true : undefined);
3703+
}
36993704
}
37003705

37013706
namespace ts {

0 commit comments

Comments
 (0)