-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support reference library directives #7549
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,12 @@ namespace ts { | |
|
||
const emptyArray: any[] = []; | ||
|
||
const defaultLibrarySearchPaths = <Path[]>[ | ||
"typings/", | ||
"node_modules/", | ||
"node_modules/@types/", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i thought we are going to make it |
||
]; | ||
|
||
export const version = "1.9.0"; | ||
|
||
export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean): string { | ||
|
@@ -371,7 +377,7 @@ namespace ts { | |
const traceEnabled = isTraceEnabled(compilerOptions, host); | ||
|
||
const failedLookupLocations: string[] = []; | ||
const state = {compilerOptions, host, traceEnabled, skipTsx: false}; | ||
const state = { compilerOptions, host, traceEnabled, skipTsx: false }; | ||
let resolvedFileName = tryLoadModuleUsingOptionalResolutionSettings(moduleName, containingDirectory, nodeLoadModuleByRelativeName, | ||
failedLookupLocations, supportedExtensions, state); | ||
|
||
|
@@ -407,7 +413,7 @@ namespace ts { | |
} | ||
|
||
/* @internal */ | ||
export function directoryProbablyExists(directoryName: string, host: { directoryExists?: (directoryName: string) => boolean } ): boolean { | ||
export function directoryProbablyExists(directoryName: string, host: { directoryExists?: (directoryName: string) => boolean }): boolean { | ||
// if host does not support 'directoryExists' assume that directory will exist | ||
return !host.directoryExists || host.directoryExists(directoryName); | ||
} | ||
|
@@ -554,7 +560,7 @@ namespace ts { | |
|
||
|
||
return referencedSourceFile | ||
? { resolvedModule: { resolvedFileName: referencedSourceFile }, failedLookupLocations } | ||
? { resolvedModule: { resolvedFileName: referencedSourceFile }, failedLookupLocations } | ||
: { resolvedModule: undefined, failedLookupLocations }; | ||
} | ||
|
||
|
@@ -649,9 +655,9 @@ namespace ts { | |
|
||
export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[] { | ||
let diagnostics = program.getOptionsDiagnostics(cancellationToken).concat( | ||
program.getSyntacticDiagnostics(sourceFile, cancellationToken), | ||
program.getGlobalDiagnostics(cancellationToken), | ||
program.getSemanticDiagnostics(sourceFile, cancellationToken)); | ||
program.getSyntacticDiagnostics(sourceFile, cancellationToken), | ||
program.getGlobalDiagnostics(cancellationToken), | ||
program.getSemanticDiagnostics(sourceFile, cancellationToken)); | ||
|
||
if (program.getCompilerOptions().declaration) { | ||
diagnostics = diagnostics.concat(program.getDeclarationDiagnostics(sourceFile, cancellationToken)); | ||
|
@@ -690,6 +696,14 @@ namespace ts { | |
let program: Program; | ||
let files: SourceFile[] = []; | ||
let fileProcessingDiagnostics = createDiagnosticCollection(); | ||
const currentDirectory = host.getCurrentDirectory(); | ||
const resolvedLibraries: Map<ResolvedLibrary> = {}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so are they case sensitive? is this intentional? if not use fileMap. |
||
let libraryRoot = | ||
(options.rootDir && ts.toPath(options.rootDir, currentDirectory, host.getCanonicalFileName)) || | ||
(options.configFilePath && getDirectoryPath(getNormalizedAbsolutePath(options.configFilePath, currentDirectory))); | ||
if (libraryRoot === undefined) { | ||
libraryRoot = computeCommonSourceDirectoryOfFilenames(rootNames); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is kinda unexpected. so |
||
} | ||
const programDiagnostics = createDiagnosticCollection(); | ||
|
||
let commonSourceDirectory: string; | ||
|
@@ -706,7 +720,6 @@ namespace ts { | |
// Map storing if there is emit blocking diagnostics for given input | ||
const hasEmitBlockingDiagnostics = createFileMap<boolean>(getCanonicalFileName); | ||
|
||
const currentDirectory = host.getCurrentDirectory(); | ||
const resolveModuleNamesWorker = host.resolveModuleNames | ||
? ((moduleNames: string[], containingFile: string) => host.resolveModuleNames(moduleNames, containingFile)) | ||
: ((moduleNames: string[], containingFile: string) => { | ||
|
@@ -883,8 +896,8 @@ namespace ts { | |
const oldResolution = getResolvedModule(oldSourceFile, moduleNames[i]); | ||
const resolutionChanged = oldResolution | ||
? !newResolution || | ||
oldResolution.resolvedFileName !== newResolution.resolvedFileName || | ||
!!oldResolution.isExternalLibraryImport !== !!newResolution.isExternalLibraryImport | ||
oldResolution.resolvedFileName !== newResolution.resolvedFileName || | ||
!!oldResolution.isExternalLibraryImport !== !!newResolution.isExternalLibraryImport | ||
: newResolution; | ||
|
||
if (resolutionChanged) { | ||
|
@@ -1007,9 +1020,9 @@ namespace ts { | |
} | ||
|
||
function getDiagnosticsHelper( | ||
sourceFile: SourceFile, | ||
getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => Diagnostic[], | ||
cancellationToken: CancellationToken): Diagnostic[] { | ||
sourceFile: SourceFile, | ||
getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => Diagnostic[], | ||
cancellationToken: CancellationToken): Diagnostic[] { | ||
if (sourceFile) { | ||
return getDiagnostics(sourceFile, cancellationToken); | ||
} | ||
|
@@ -1484,6 +1497,7 @@ namespace ts { | |
const basePath = getDirectoryPath(fileName); | ||
if (!options.noResolve) { | ||
processReferencedFiles(file, basePath); | ||
processReferencedLibraries(file, libraryRoot); | ||
} | ||
|
||
// always process imported modules to record module name resolutions | ||
|
@@ -1507,6 +1521,97 @@ namespace ts { | |
}); | ||
} | ||
|
||
function findLibraryDefinition(searchPath: string) { | ||
let typingFilename = "index.d.ts"; | ||
const packageJsonPath = combinePaths(searchPath, "package.json"); | ||
if (host.fileExists(packageJsonPath)) { | ||
let package: { typings?: string } = {}; | ||
try { | ||
package = JSON.parse(host.readFile(packageJsonPath)); | ||
} | ||
catch (e) { } | ||
|
||
if (package.typings) { | ||
typingFilename = package.typings; | ||
} | ||
} | ||
|
||
const combinedPath = normalizePath(combinePaths(searchPath, typingFilename)); | ||
return host.fileExists(combinedPath) ? combinedPath : undefined; | ||
} | ||
|
||
function processReferencedLibraries(file: SourceFile, compilationRoot: string) { | ||
const primarySearchPaths = map(getEffectiveLibraryPrimarySearchPaths(), path => combinePaths(compilationRoot, path)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not see |
||
|
||
const failedSearchPaths: string[] = []; | ||
const moduleResolutionState: ModuleResolutionState = { | ||
compilerOptions: options, | ||
host: host, | ||
skipTsx: true, | ||
traceEnabled: false | ||
}; | ||
|
||
for (const ref of file.referencedLibraries) { | ||
// If we already found this library as a primary reference, or failed to find it, nothing to do | ||
const previousResolution = resolvedLibraries[ref.fileName]; | ||
if (previousResolution && (previousResolution.primary || (previousResolution.resolvedFileName === undefined))) { | ||
continue; | ||
} | ||
|
||
let foundIt = false; | ||
|
||
// Check primary library paths | ||
for (const primaryPath of primarySearchPaths) { | ||
const searchPath = combinePaths(primaryPath, ref.fileName); | ||
const resolvedFile = findLibraryDefinition(searchPath); | ||
if (resolvedFile) { | ||
resolvedLibraries[ref.fileName] = { primary: true, resolvedFileName: resolvedFile }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't you add it to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't crash due to the checks in processSourceFile (added a test), but good catch. Rearranged. |
||
processSourceFile(resolvedFile, /*isDefaultLib*/ false, /*isReference*/ true, file, ref.pos, ref.end); | ||
foundIt = true; | ||
break; | ||
} | ||
} | ||
|
||
// Check secondary library paths | ||
if (!foundIt) { | ||
const secondaryResult = loadModuleFromNodeModules(ref.fileName, file.fileName, failedSearchPaths, moduleResolutionState); | ||
if (secondaryResult) { | ||
foundIt = true; | ||
// If we already resolved to this file, it must have been a secondary reference. Check file contents | ||
// for sameness and possibly issue an error | ||
if (previousResolution) { | ||
const otherFileText = host.readFile(secondaryResult); | ||
if (otherFileText !== getSourceFile(previousResolution.resolvedFileName).text) { | ||
fileProcessingDiagnostics.add(createFileDiagnostic(file, ref.pos, ref.end - ref.pos, | ||
Diagnostics.Conflicting_library_definitions_for_0_found_at_1_and_2_Copy_the_correct_file_to_a_local_typings_folder_to_resolve_this_conflict, | ||
ref.fileName, | ||
secondaryResult, | ||
previousResolution.resolvedFileName)); | ||
} | ||
} | ||
else { | ||
// First resolution of this library | ||
resolvedLibraries[ref.fileName] = { primary: false, resolvedFileName: secondaryResult }; | ||
processSourceFile(secondaryResult, /*isDefaultLib*/ false, /*isReference*/ true, file, ref.pos, ref.end); | ||
} | ||
} | ||
} | ||
|
||
if (!foundIt) { | ||
fileProcessingDiagnostics.add(createFileDiagnostic(file, ref.pos, ref.end - ref.pos, Diagnostics.Cannot_find_name_0, ref.fileName)); | ||
// Create an entry as a primary lookup result so we don't keep doing this | ||
resolvedLibraries[ref.fileName] = { primary: true, resolvedFileName: undefined }; | ||
} | ||
} | ||
} | ||
|
||
function getEffectiveLibraryPrimarySearchPaths(): Path[] { | ||
return <Path[]>(options.librarySearchPaths || | ||
(options.configFilePath ? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting... so if the user provides Also, why is the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct. I removed "" from the list of default search paths. |
||
[options.configFilePath].concat(defaultLibrarySearchPaths) : | ||
defaultLibrarySearchPaths)); | ||
} | ||
|
||
function getCanonicalFileName(fileName: string): string { | ||
return host.getCanonicalFileName(fileName); | ||
} | ||
|
@@ -1553,15 +1658,11 @@ namespace ts { | |
return; | ||
} | ||
|
||
function computeCommonSourceDirectory(sourceFiles: SourceFile[]): string { | ||
function computeCommonSourceDirectoryOfFilenames(fileNames: string[]): string { | ||
let commonPathComponents: string[]; | ||
const failed = forEach(files, sourceFile => { | ||
const failed = forEach(fileNames, sourceFile => { | ||
// Each file contributes into common source file path | ||
if (isDeclarationFile(sourceFile)) { | ||
return; | ||
} | ||
|
||
const sourcePathComponents = getNormalizedPathComponents(sourceFile.fileName, currentDirectory); | ||
const sourcePathComponents = getNormalizedPathComponents(sourceFile, currentDirectory); | ||
sourcePathComponents.pop(); // The base file name is not part of the common directory path | ||
|
||
if (!commonPathComponents) { | ||
|
@@ -1601,6 +1702,16 @@ namespace ts { | |
return getNormalizedPathFromPathComponents(commonPathComponents); | ||
} | ||
|
||
function computeCommonSourceDirectory(sourceFiles: SourceFile[]): string { | ||
const fileNames: string[] = []; | ||
for (const file of sourceFiles) { | ||
if (!file.isDeclarationFile) { | ||
fileNames.push(file.fileName); | ||
} | ||
} | ||
return computeCommonSourceDirectoryOfFilenames(fileNames); | ||
} | ||
|
||
function checkSourceFilesBelongToPath(sourceFiles: SourceFile[], rootDirectory: string): boolean { | ||
let allFilesBelongToPath = true; | ||
if (sourceFiles) { | ||
|
@@ -1742,7 +1853,7 @@ namespace ts { | |
|
||
// If we failed to find a good common directory, but outDir is specified and at least one of our files is on a windows drive/URL/other resource, add a failure | ||
if (options.outDir && dir === "" && forEach(files, file => getRootLength(file.fileName) > 1)) { | ||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files)); | ||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files)); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -390,6 +390,7 @@ namespace ts { | |
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"), /* compilerHost */ undefined); | ||
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); | ||
} | ||
configParseResult.options.configFilePath = configFileName as Path; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should not this be set in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry meant, parseJsonConfigFileContent |
||
return configParseResult; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1536,6 +1536,7 @@ namespace ts { | |
amdDependencies: AmdDependency[]; | ||
moduleName: string; | ||
referencedFiles: FileReference[]; | ||
referencedLibraries: FileReference[]; | ||
languageVariant: LanguageVariant; | ||
isDeclarationFile: boolean; | ||
|
||
|
@@ -2415,6 +2416,7 @@ namespace ts { | |
jsx?: JsxEmit; | ||
reactNamespace?: string; | ||
listFiles?: boolean; | ||
librarySearchPaths?: string[]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i do not see parsing to this anywhere. has the changes to commandlineparser been missed intentionally? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated |
||
locale?: string; | ||
mapRoot?: string; | ||
module?: ModuleKind; | ||
|
@@ -2466,8 +2468,11 @@ namespace ts { | |
// Do not perform validation of output file name in transpile scenarios | ||
/* @internal */ suppressOutputPathCheck?: boolean; | ||
|
||
list?: string[]; | ||
/* @internal */ | ||
// When options come from a config file, its path is recorded here | ||
configFilePath?: string; | ||
|
||
list?: string[]; | ||
[option: string]: CompilerOptionsValue; | ||
} | ||
|
||
|
@@ -2743,6 +2748,13 @@ namespace ts { | |
isExternalLibraryImport?: boolean; | ||
} | ||
|
||
export interface ResolvedLibrary { | ||
// True if the library was found in a primary lookup location | ||
primary: boolean; | ||
// The location of the .d.ts file we located, or undefined if resolution failed | ||
resolvedFileName?: string; | ||
} | ||
|
||
export interface ResolvedModuleWithFailedLookupLocations { | ||
resolvedModule: ResolvedModule; | ||
failedLookupLocations: string[]; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, missing quotes:
.. local 'typings' folder ..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
possibly:
Copy the correct file to the local 'typings' folder
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to suggested text