mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Keep track of why files are in the program (#40011)
* --explainFiles currently hardcoded * Move configFileSpecs to configFile so it can be used in program later * Explain root file inclusion reason and explain include files in the log * Baseline explainFiles * Fix incorrectly reporting of file list two times in --b mode * Fix unnecessary new lines in output represented incorretly in the baseline * More tests * More cleaning up * Keep listing files in same order as list files, just add explaination * Fix double listing of file names when the program has errors * Make diagnostic chains for file include reason * Add explaination for the file include to diagnostics for program * Harness ls incorrectly adding tsconfig as the root file * Fix incorrect use of path for calculating absolute path * Fix the root file in fourslash * Test project service options merge * Add config file name to matched by include explaination * Add test for when the file changes and program is reused completely but related file information is reattached to correct location * Handle file preprocessing diagnostics updates when program is reused and related information location changes * Moved types to types.ts * Refactoring and cleanup * More cleanup * More refatoring * Handle synthetic imports * Baselines after merge
This commit is contained in:
+109
-127
@@ -196,6 +196,11 @@ namespace ts {
|
||||
description: Diagnostics.Print_names_of_files_part_of_the_compilation
|
||||
},
|
||||
{
|
||||
name: "explainFiles",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Print_names_of_files_and_the_reason_they_are_part_of_the_compilation
|
||||
}, {
|
||||
name: "listEmittedFiles",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
@@ -268,6 +273,31 @@ namespace ts {
|
||||
},
|
||||
];
|
||||
|
||||
/* @internal */
|
||||
export const targetOptionDeclaration: CommandLineOptionOfCustomType = {
|
||||
name: "target",
|
||||
shortName: "t",
|
||||
type: new Map(getEntries({
|
||||
es3: ScriptTarget.ES3,
|
||||
es5: ScriptTarget.ES5,
|
||||
es6: ScriptTarget.ES2015,
|
||||
es2015: ScriptTarget.ES2015,
|
||||
es2016: ScriptTarget.ES2016,
|
||||
es2017: ScriptTarget.ES2017,
|
||||
es2018: ScriptTarget.ES2018,
|
||||
es2019: ScriptTarget.ES2019,
|
||||
es2020: ScriptTarget.ES2020,
|
||||
esnext: ScriptTarget.ESNext,
|
||||
})),
|
||||
affectsSourceFile: true,
|
||||
affectsModuleResolution: true,
|
||||
affectsEmit: true,
|
||||
paramType: Diagnostics.VERSION,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Basic_Options,
|
||||
description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_ES2015_ES2016_ES2017_ES2018_ES2019_ES2020_or_ESNEXT,
|
||||
};
|
||||
|
||||
/* @internal */
|
||||
export const optionDeclarations: CommandLineOption[] = [
|
||||
// CommandLine only options
|
||||
@@ -330,29 +360,7 @@ namespace ts {
|
||||
},
|
||||
|
||||
// Basic
|
||||
{
|
||||
name: "target",
|
||||
shortName: "t",
|
||||
type: new Map(getEntries({
|
||||
es3: ScriptTarget.ES3,
|
||||
es5: ScriptTarget.ES5,
|
||||
es6: ScriptTarget.ES2015,
|
||||
es2015: ScriptTarget.ES2015,
|
||||
es2016: ScriptTarget.ES2016,
|
||||
es2017: ScriptTarget.ES2017,
|
||||
es2018: ScriptTarget.ES2018,
|
||||
es2019: ScriptTarget.ES2019,
|
||||
es2020: ScriptTarget.ES2020,
|
||||
esnext: ScriptTarget.ESNext,
|
||||
})),
|
||||
affectsSourceFile: true,
|
||||
affectsModuleResolution: true,
|
||||
affectsEmit: true,
|
||||
paramType: Diagnostics.VERSION,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Basic_Options,
|
||||
description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_ES2015_ES2016_ES2017_ES2018_ES2019_ES2020_or_ESNEXT,
|
||||
},
|
||||
targetOptionDeclaration,
|
||||
{
|
||||
name: "module",
|
||||
shortName: "m",
|
||||
@@ -2030,10 +2038,10 @@ namespace ts {
|
||||
const files = map(
|
||||
filter(
|
||||
configParseResult.fileNames,
|
||||
(!configParseResult.configFileSpecs || !configParseResult.configFileSpecs.validatedIncludeSpecs) ? _ => true : matchesSpecs(
|
||||
!configParseResult.options.configFile?.configFileSpecs?.validatedIncludeSpecs ? returnTrue : matchesSpecs(
|
||||
configFileName,
|
||||
configParseResult.configFileSpecs.validatedIncludeSpecs,
|
||||
configParseResult.configFileSpecs.validatedExcludeSpecs,
|
||||
configParseResult.options.configFile.configFileSpecs.validatedIncludeSpecs,
|
||||
configParseResult.options.configFile.configFileSpecs.validatedExcludeSpecs,
|
||||
host,
|
||||
)
|
||||
),
|
||||
@@ -2058,9 +2066,9 @@ namespace ts {
|
||||
watchOptions: watchOptionMap && optionMapToObject(watchOptionMap),
|
||||
references: map(configParseResult.projectReferences, r => ({ ...r, path: r.originalPath ? r.originalPath : "", originalPath: undefined })),
|
||||
files: length(files) ? files : undefined,
|
||||
...(configParseResult.configFileSpecs ? {
|
||||
include: filterSameAsDefaultInclude(configParseResult.configFileSpecs.validatedIncludeSpecs),
|
||||
exclude: configParseResult.configFileSpecs.validatedExcludeSpecs
|
||||
...(configParseResult.options.configFile?.configFileSpecs ? {
|
||||
include: filterSameAsDefaultInclude(configParseResult.options.configFile.configFileSpecs.validatedIncludeSpecs),
|
||||
exclude: configParseResult.options.configFile.configFileSpecs.validatedExcludeSpecs
|
||||
} : {}),
|
||||
compileOnSave: !!configParseResult.compileOnSave ? true : undefined
|
||||
};
|
||||
@@ -2081,7 +2089,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function matchesSpecs(path: string, includeSpecs: readonly string[] | undefined, excludeSpecs: readonly string[] | undefined, host: ConvertToTSConfigHost): (path: string) => boolean {
|
||||
if (!includeSpecs) return _ => true;
|
||||
if (!includeSpecs) return returnTrue;
|
||||
const patterns = getFileMatcherPatterns(path, excludeSpecs, includeSpecs, host.useCaseSensitiveFileNames, host.getCurrentDirectory());
|
||||
const excludeRe = patterns.excludePattern && getRegexFromPattern(patterns.excludePattern, host.useCaseSensitiveFileNames);
|
||||
const includeRe = patterns.includeFilePattern && getRegexFromPattern(patterns.includeFilePattern, host.useCaseSensitiveFileNames);
|
||||
@@ -2094,7 +2102,7 @@ namespace ts {
|
||||
if (excludeRe) {
|
||||
return path => excludeRe.test(path);
|
||||
}
|
||||
return _ => true;
|
||||
return returnTrue;
|
||||
}
|
||||
|
||||
function getCustomTypeMapOfCommandLineOption(optionDefinition: CommandLineOption): ESMap<string, string | number> | undefined {
|
||||
@@ -2387,40 +2395,29 @@ namespace ts {
|
||||
parsedConfig.watchOptions || existingWatchOptions;
|
||||
|
||||
options.configFilePath = configFileName && normalizeSlashes(configFileName);
|
||||
const configFileSpecs = getConfigFileSpecs();
|
||||
if (sourceFile) sourceFile.configFileSpecs = configFileSpecs;
|
||||
setConfigFileInOptions(options, sourceFile);
|
||||
let projectReferences: ProjectReference[] | undefined;
|
||||
const { fileNames, wildcardDirectories, spec } = getFileNames();
|
||||
|
||||
const basePathForFileNames = normalizePath(configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath);
|
||||
return {
|
||||
options,
|
||||
watchOptions,
|
||||
fileNames,
|
||||
projectReferences,
|
||||
fileNames: getFileNames(basePathForFileNames),
|
||||
projectReferences: getProjectReferences(basePathForFileNames),
|
||||
typeAcquisition: parsedConfig.typeAcquisition || getDefaultTypeAcquisition(),
|
||||
raw,
|
||||
errors,
|
||||
wildcardDirectories,
|
||||
// Wildcard directories (provided as part of a wildcard path) are stored in a
|
||||
// file map that marks whether it was a regular wildcard match (with a `*` or `?` token),
|
||||
// or a recursive directory. This information is used by filesystem watchers to monitor for
|
||||
// new entries in these paths.
|
||||
wildcardDirectories: getWildcardDirectories(configFileSpecs, basePathForFileNames, host.useCaseSensitiveFileNames),
|
||||
compileOnSave: !!raw.compileOnSave,
|
||||
configFileSpecs: spec
|
||||
};
|
||||
|
||||
function getFileNames(): ExpandResult {
|
||||
function getConfigFileSpecs(): ConfigFileSpecs {
|
||||
const referencesOfRaw = getPropFromRaw<ProjectReference>("references", element => typeof element === "object", "object");
|
||||
if (isArray(referencesOfRaw)) {
|
||||
for (const ref of referencesOfRaw) {
|
||||
if (typeof ref.path !== "string") {
|
||||
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "reference.path", "string");
|
||||
}
|
||||
else {
|
||||
(projectReferences || (projectReferences = [])).push({
|
||||
path: getNormalizedAbsolutePath(ref.path, basePath),
|
||||
originalPath: ref.path,
|
||||
prepend: ref.prepend,
|
||||
circular: ref.circular
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const filesSpecs = toPropValue(getSpecsFromRaw("files"));
|
||||
if (filesSpecs) {
|
||||
const hasZeroOrNoReferences = referencesOfRaw === "no-prop" || isArray(referencesOfRaw) && referencesOfRaw.length === 0;
|
||||
@@ -2457,13 +2454,57 @@ namespace ts {
|
||||
if (filesSpecs === undefined && includeSpecs === undefined) {
|
||||
includeSpecs = ["**/*"];
|
||||
}
|
||||
let validatedIncludeSpecs: readonly string[] | undefined, validatedExcludeSpecs: readonly string[] | undefined;
|
||||
|
||||
const result = matchFileNames(filesSpecs, includeSpecs, excludeSpecs, configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath, options, host, errors, extraFileExtensions, sourceFile);
|
||||
if (shouldReportNoInputFiles(result, canJsonReportNoInputFiles(raw), resolutionStack)) {
|
||||
errors.push(getErrorForNoInputFiles(result.spec, configFileName));
|
||||
// The exclude spec list is converted into a regular expression, which allows us to quickly
|
||||
// test whether a file or directory should be excluded before recursively traversing the
|
||||
// file system.
|
||||
|
||||
if (includeSpecs) {
|
||||
validatedIncludeSpecs = validateSpecs(includeSpecs, errors, /*disallowTrailingRecursion*/ true, sourceFile, "include");
|
||||
}
|
||||
|
||||
return result;
|
||||
if (excludeSpecs) {
|
||||
validatedExcludeSpecs = validateSpecs(excludeSpecs, errors, /*disallowTrailingRecursion*/ false, sourceFile, "exclude");
|
||||
}
|
||||
|
||||
return {
|
||||
filesSpecs,
|
||||
includeSpecs,
|
||||
excludeSpecs,
|
||||
validatedFilesSpec: filter(filesSpecs, isString),
|
||||
validatedIncludeSpecs,
|
||||
validatedExcludeSpecs,
|
||||
};
|
||||
}
|
||||
|
||||
function getFileNames(basePath: string): string[] {
|
||||
const fileNames = getFileNamesFromConfigSpecs(configFileSpecs, basePath, options, host, extraFileExtensions);
|
||||
if (shouldReportNoInputFiles(fileNames, canJsonReportNoInputFiles(raw), resolutionStack)) {
|
||||
errors.push(getErrorForNoInputFiles(configFileSpecs, configFileName));
|
||||
}
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
function getProjectReferences(basePath: string): readonly ProjectReference[] | undefined {
|
||||
let projectReferences: ProjectReference[] | undefined;
|
||||
const referencesOfRaw = getPropFromRaw<ProjectReference>("references", element => typeof element === "object", "object");
|
||||
if (isArray(referencesOfRaw)) {
|
||||
for (const ref of referencesOfRaw) {
|
||||
if (typeof ref.path !== "string") {
|
||||
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "reference.path", "string");
|
||||
}
|
||||
else {
|
||||
(projectReferences || (projectReferences = [])).push({
|
||||
path: getNormalizedAbsolutePath(ref.path, basePath),
|
||||
originalPath: ref.path,
|
||||
prepend: ref.prepend,
|
||||
circular: ref.circular
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return projectReferences;
|
||||
}
|
||||
|
||||
type PropOfRaw<T> = readonly T[] | "not-array" | "no-prop";
|
||||
@@ -2511,8 +2552,8 @@ namespace ts {
|
||||
JSON.stringify(excludeSpecs || []));
|
||||
}
|
||||
|
||||
function shouldReportNoInputFiles(result: ExpandResult, canJsonReportNoInutFiles: boolean, resolutionStack?: Path[]) {
|
||||
return result.fileNames.length === 0 && canJsonReportNoInutFiles && (!resolutionStack || resolutionStack.length === 0);
|
||||
function shouldReportNoInputFiles(fileNames: string[], canJsonReportNoInutFiles: boolean, resolutionStack?: Path[]) {
|
||||
return fileNames.length === 0 && canJsonReportNoInutFiles && (!resolutionStack || resolutionStack.length === 0);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
@@ -2521,9 +2562,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function updateErrorForNoInputFiles(result: ExpandResult, configFileName: string, configFileSpecs: ConfigFileSpecs, configParseDiagnostics: Diagnostic[], canJsonReportNoInutFiles: boolean) {
|
||||
export function updateErrorForNoInputFiles(fileNames: string[], configFileName: string, configFileSpecs: ConfigFileSpecs, configParseDiagnostics: Diagnostic[], canJsonReportNoInutFiles: boolean) {
|
||||
const existingErrors = configParseDiagnostics.length;
|
||||
if (shouldReportNoInputFiles(result, canJsonReportNoInutFiles)) {
|
||||
if (shouldReportNoInputFiles(fileNames, canJsonReportNoInutFiles)) {
|
||||
configParseDiagnostics.push(getErrorForNoInputFiles(configFileSpecs, configFileName));
|
||||
}
|
||||
else {
|
||||
@@ -3011,65 +3052,10 @@ namespace ts {
|
||||
*/
|
||||
const wildcardDirectoryPattern = /^[^*?]*(?=\/[^/]*[*?])/;
|
||||
|
||||
/**
|
||||
* Expands an array of file specifications.
|
||||
*
|
||||
* @param filesSpecs The literal file names to include.
|
||||
* @param includeSpecs The wildcard file specifications to include.
|
||||
* @param excludeSpecs The wildcard file specifications to exclude.
|
||||
* @param basePath The base path for any relative file specifications.
|
||||
* @param options Compiler options.
|
||||
* @param host The host used to resolve files and directories.
|
||||
* @param errors An array for diagnostic reporting.
|
||||
*/
|
||||
function matchFileNames(
|
||||
filesSpecs: readonly string[] | undefined,
|
||||
includeSpecs: readonly string[] | undefined,
|
||||
excludeSpecs: readonly string[] | undefined,
|
||||
basePath: string,
|
||||
options: CompilerOptions,
|
||||
host: ParseConfigHost,
|
||||
errors: Push<Diagnostic>,
|
||||
extraFileExtensions: readonly FileExtensionInfo[],
|
||||
jsonSourceFile: TsConfigSourceFile | undefined
|
||||
): ExpandResult {
|
||||
basePath = normalizePath(basePath);
|
||||
let validatedIncludeSpecs: readonly string[] | undefined, validatedExcludeSpecs: readonly string[] | undefined;
|
||||
|
||||
// The exclude spec list is converted into a regular expression, which allows us to quickly
|
||||
// test whether a file or directory should be excluded before recursively traversing the
|
||||
// file system.
|
||||
|
||||
if (includeSpecs) {
|
||||
validatedIncludeSpecs = validateSpecs(includeSpecs, errors, /*disallowTrailingRecursion*/ true, jsonSourceFile, "include");
|
||||
}
|
||||
|
||||
if (excludeSpecs) {
|
||||
validatedExcludeSpecs = validateSpecs(excludeSpecs, errors, /*disallowTrailingRecursion*/ false, jsonSourceFile, "exclude");
|
||||
}
|
||||
|
||||
// Wildcard directories (provided as part of a wildcard path) are stored in a
|
||||
// file map that marks whether it was a regular wildcard match (with a `*` or `?` token),
|
||||
// or a recursive directory. This information is used by filesystem watchers to monitor for
|
||||
// new entries in these paths.
|
||||
const wildcardDirectories = getWildcardDirectories(validatedIncludeSpecs, validatedExcludeSpecs, basePath, host.useCaseSensitiveFileNames);
|
||||
|
||||
const spec: ConfigFileSpecs = {
|
||||
filesSpecs,
|
||||
includeSpecs,
|
||||
excludeSpecs,
|
||||
validatedFilesSpec: filter(filesSpecs, isString),
|
||||
validatedIncludeSpecs,
|
||||
validatedExcludeSpecs,
|
||||
wildcardDirectories
|
||||
};
|
||||
return getFileNamesFromConfigSpecs(spec, basePath, options, host, extraFileExtensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file names from the provided config file specs that contain, files, include, exclude and
|
||||
* other properties needed to resolve the file names
|
||||
* @param spec The config file specs extracted with file names to include, wildcards to include/exclude and other details
|
||||
* @param configFileSpecs The config file specs extracted with file names to include, wildcards to include/exclude and other details
|
||||
* @param basePath The base path for any relative file specifications.
|
||||
* @param options Compiler options.
|
||||
* @param host The host used to resolve files and directories.
|
||||
@@ -3077,12 +3063,12 @@ namespace ts {
|
||||
*/
|
||||
/* @internal */
|
||||
export function getFileNamesFromConfigSpecs(
|
||||
spec: ConfigFileSpecs,
|
||||
configFileSpecs: ConfigFileSpecs,
|
||||
basePath: string,
|
||||
options: CompilerOptions,
|
||||
host: ParseConfigHost,
|
||||
extraFileExtensions: readonly FileExtensionInfo[] = emptyArray
|
||||
): ExpandResult {
|
||||
): string[] {
|
||||
basePath = normalizePath(basePath);
|
||||
|
||||
const keyMapper = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
|
||||
@@ -3101,7 +3087,7 @@ namespace ts {
|
||||
// file map with a possibly case insensitive key. We use this map to store paths matched
|
||||
// via wildcard of *.json kind
|
||||
const wildCardJsonFileMap = new Map<string, string>();
|
||||
const { validatedFilesSpec, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories } = spec;
|
||||
const { validatedFilesSpec, validatedIncludeSpecs, validatedExcludeSpecs } = configFileSpecs;
|
||||
|
||||
// Rather than requery this for each file and filespec, we query the supported extensions
|
||||
// once and store it on the expansion context.
|
||||
@@ -3162,11 +3148,7 @@ namespace ts {
|
||||
const literalFiles = arrayFrom(literalFileMap.values());
|
||||
const wildcardFiles = arrayFrom(wildcardFileMap.values());
|
||||
|
||||
return {
|
||||
fileNames: literalFiles.concat(wildcardFiles, arrayFrom(wildCardJsonFileMap.values())),
|
||||
wildcardDirectories,
|
||||
spec
|
||||
};
|
||||
return literalFiles.concat(wildcardFiles, arrayFrom(wildCardJsonFileMap.values()));
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -3251,7 +3233,7 @@ namespace ts {
|
||||
/**
|
||||
* Gets directories in a set of include patterns that should be watched for changes.
|
||||
*/
|
||||
function getWildcardDirectories(include: readonly string[] | undefined, exclude: readonly string[] | undefined, path: string, useCaseSensitiveFileNames: boolean): MapLike<WatchDirectoryFlags> {
|
||||
function getWildcardDirectories({ validatedIncludeSpecs: include, validatedExcludeSpecs: exclude }: ConfigFileSpecs, path: string, useCaseSensitiveFileNames: boolean): MapLike<WatchDirectoryFlags> {
|
||||
// We watch a directory recursively if it contains a wildcard anywhere in a directory segment
|
||||
// of the pattern:
|
||||
//
|
||||
|
||||
@@ -1196,6 +1196,158 @@
|
||||
"category": "Error",
|
||||
"code": 1392
|
||||
},
|
||||
"Imported via {0} from file '{1}'": {
|
||||
"category": "Message",
|
||||
"code": 1393
|
||||
},
|
||||
"Imported via {0} from file '{1}' with packageId '{2}'": {
|
||||
"category": "Message",
|
||||
"code": 1394
|
||||
},
|
||||
"Imported via {0} from file '{1}' to import 'importHelpers' as specified in compilerOptions": {
|
||||
"category": "Message",
|
||||
"code": 1395
|
||||
},
|
||||
"Imported via {0} from file '{1}' with packageId '{2}' to import 'importHelpers' as specified in compilerOptions": {
|
||||
"category": "Message",
|
||||
"code": 1396
|
||||
},
|
||||
"Imported via {0} from file '{1}' to import 'jsx' and 'jsxs' factory functions": {
|
||||
"category": "Message",
|
||||
"code": 1397
|
||||
},
|
||||
"Imported via {0} from file '{1}' with packageId '{2}' to import 'jsx' and 'jsxs' factory functions": {
|
||||
"category": "Message",
|
||||
"code": 1398
|
||||
},
|
||||
"File is included via import here.": {
|
||||
"category": "Message",
|
||||
"code": 1399
|
||||
},
|
||||
"Referenced via '{0}' from file '{1}'": {
|
||||
"category": "Message",
|
||||
"code": 1400
|
||||
},
|
||||
"File is included via reference here.": {
|
||||
"category": "Message",
|
||||
"code": 1401
|
||||
},
|
||||
"Type library referenced via '{0}' from file '{1}'": {
|
||||
"category": "Message",
|
||||
"code": 1402
|
||||
},
|
||||
"Type library referenced via '{0}' from file '{1}' with packageId '{2}'": {
|
||||
"category": "Message",
|
||||
"code": 1403
|
||||
},
|
||||
"File is included via type library reference here.": {
|
||||
"category": "Message",
|
||||
"code": 1404
|
||||
},
|
||||
"Library referenced via '{0}' from file '{1}'": {
|
||||
"category": "Message",
|
||||
"code": 1405
|
||||
},
|
||||
"File is included via library reference here.": {
|
||||
"category": "Message",
|
||||
"code": 1406
|
||||
},
|
||||
"Matched by include pattern '{0}' in '{1}'": {
|
||||
"category": "Message",
|
||||
"code": 1407
|
||||
},
|
||||
"File is matched by include pattern specified here.": {
|
||||
"category": "Message",
|
||||
"code": 1408
|
||||
},
|
||||
"Part of 'files' list in tsconfig.json": {
|
||||
"category": "Message",
|
||||
"code": 1409
|
||||
},
|
||||
"File is matched by 'files' list specified here.": {
|
||||
"category": "Message",
|
||||
"code": 1410
|
||||
},
|
||||
"Output from referenced project '{0}' included because '{1}' specified": {
|
||||
"category": "Message",
|
||||
"code": 1411
|
||||
},
|
||||
"Output from referenced project '{0}' included because '--module' is specified as 'none'": {
|
||||
"category": "Message",
|
||||
"code": 1412
|
||||
},
|
||||
"File is output from referenced project specified here.": {
|
||||
"category": "Message",
|
||||
"code": 1413
|
||||
},
|
||||
"Source from referenced project '{0}' included because '{1}' specified": {
|
||||
"category": "Message",
|
||||
"code": 1414
|
||||
},
|
||||
"Source from referenced project '{0}' included because '--module' is specified as 'none'": {
|
||||
"category": "Message",
|
||||
"code": 1415
|
||||
},
|
||||
"File is source from referenced project specified here.": {
|
||||
"category": "Message",
|
||||
"code": 1416
|
||||
},
|
||||
"Entry point of type library '{0}' specified in compilerOptions": {
|
||||
"category": "Message",
|
||||
"code": 1417
|
||||
},
|
||||
"Entry point of type library '{0}' specified in compilerOptions with packageId '{1}'": {
|
||||
"category": "Message",
|
||||
"code": 1418
|
||||
},
|
||||
"File is entry point of type library specified here.": {
|
||||
"category": "Message",
|
||||
"code": 1419
|
||||
},
|
||||
"Entry point for implicit type library '{0}'": {
|
||||
"category": "Message",
|
||||
"code": 1420
|
||||
},
|
||||
"Entry point for implicit type library '{0}' with packageId '{1}'": {
|
||||
"category": "Message",
|
||||
"code": 1421
|
||||
},
|
||||
"Library '{0}' specified in compilerOptions": {
|
||||
"category": "Message",
|
||||
"code": 1422
|
||||
},
|
||||
"File is library specified here.": {
|
||||
"category": "Message",
|
||||
"code": 1423
|
||||
},
|
||||
"Default library": {
|
||||
"category": "Message",
|
||||
"code": 1424
|
||||
},
|
||||
"Default library for target '{0}'": {
|
||||
"category": "Message",
|
||||
"code": 1425
|
||||
},
|
||||
"File is default library for target specified here.": {
|
||||
"category": "Message",
|
||||
"code": 1426
|
||||
},
|
||||
"Root file specified for compilation": {
|
||||
"category": "Message",
|
||||
"code": 1427
|
||||
},
|
||||
"File is output of project reference source '{0}'": {
|
||||
"category": "Message",
|
||||
"code": 1428
|
||||
},
|
||||
"File redirects to file '{0}'": {
|
||||
"category": "Message",
|
||||
"code": 1429
|
||||
},
|
||||
"The file is in the program because:": {
|
||||
"category": "Message",
|
||||
"code": 1430
|
||||
},
|
||||
"The types of '{0}' are incompatible between these types.": {
|
||||
"category": "Error",
|
||||
"code": 2200
|
||||
@@ -4748,6 +4900,10 @@
|
||||
"category": "Error",
|
||||
"code": 6504
|
||||
},
|
||||
"Print names of files and the reason they are part of the compilation.": {
|
||||
"category": "Message",
|
||||
"code": 6505
|
||||
},
|
||||
"Require undeclared properties from index signatures to use element accesses.": {
|
||||
"category": "Error",
|
||||
"code": 6803
|
||||
|
||||
+337
-245
@@ -466,20 +466,19 @@ namespace ts {
|
||||
if (diagnostic.file) {
|
||||
output += host.getNewLine();
|
||||
output += formatCodeSpan(diagnostic.file, diagnostic.start!, diagnostic.length!, "", getCategoryFormat(diagnostic.category), host); // TODO: GH#18217
|
||||
if (diagnostic.relatedInformation) {
|
||||
output += host.getNewLine();
|
||||
for (const { file, start, length, messageText } of diagnostic.relatedInformation) {
|
||||
if (file) {
|
||||
output += host.getNewLine();
|
||||
output += halfIndent + formatLocation(file, start!, host); // TODO: GH#18217
|
||||
output += formatCodeSpan(file, start!, length!, indent, ForegroundColorEscapeSequences.Cyan, host); // TODO: GH#18217
|
||||
}
|
||||
}
|
||||
if (diagnostic.relatedInformation) {
|
||||
output += host.getNewLine();
|
||||
for (const { file, start, length, messageText } of diagnostic.relatedInformation) {
|
||||
if (file) {
|
||||
output += host.getNewLine();
|
||||
output += indent + flattenDiagnosticMessageText(messageText, host.getNewLine());
|
||||
output += halfIndent + formatLocation(file, start!, host); // TODO: GH#18217
|
||||
output += formatCodeSpan(file, start!, length!, indent, ForegroundColorEscapeSequences.Cyan, host); // TODO: GH#18217
|
||||
}
|
||||
output += host.getNewLine();
|
||||
output += indent + flattenDiagnosticMessageText(messageText, host.getNewLine());
|
||||
}
|
||||
}
|
||||
|
||||
output += host.getNewLine();
|
||||
}
|
||||
return output;
|
||||
@@ -583,10 +582,66 @@ namespace ts {
|
||||
allDiagnostics?: readonly T[];
|
||||
}
|
||||
|
||||
interface RefFile extends TextRange {
|
||||
kind: RefFileKind;
|
||||
index: number;
|
||||
/*@internal*/
|
||||
export function isReferencedFile(reason: FileIncludeReason | undefined): reason is ReferencedFile {
|
||||
switch (reason?.kind) {
|
||||
case FileIncludeKind.Import:
|
||||
case FileIncludeKind.ReferenceFile:
|
||||
case FileIncludeKind.TypeReferenceDirective:
|
||||
case FileIncludeKind.LibReferenceDirective:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface ReferenceFileLocation {
|
||||
file: SourceFile;
|
||||
pos: number;
|
||||
end: number;
|
||||
packageId: PackageId | undefined;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface SyntheticReferenceFileLocation {
|
||||
file: SourceFile;
|
||||
packageId: PackageId | undefined;
|
||||
text: string;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function isReferenceFileLocation(location: ReferenceFileLocation | SyntheticReferenceFileLocation): location is ReferenceFileLocation {
|
||||
return (location as ReferenceFileLocation).pos !== undefined;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function getReferencedFileLocation(getSourceFileByPath: (path: Path) => SourceFile | undefined, ref: ReferencedFile): ReferenceFileLocation | SyntheticReferenceFileLocation {
|
||||
const file = Debug.checkDefined(getSourceFileByPath(ref.file));
|
||||
const { kind, index } = ref;
|
||||
let pos: number | undefined, end: number | undefined, packageId: PackageId | undefined;
|
||||
switch (kind) {
|
||||
case FileIncludeKind.Import:
|
||||
const importLiteral = getModuleNameStringLiteralAt(file, index);
|
||||
packageId = file.resolvedModules?.get(importLiteral.text)?.packageId;
|
||||
if (importLiteral.pos === -1) return { file, packageId, text: importLiteral.text };
|
||||
pos = skipTrivia(file.text, importLiteral.pos);
|
||||
end = importLiteral.end;
|
||||
break;
|
||||
case FileIncludeKind.ReferenceFile:
|
||||
({ pos, end } = file.referencedFiles[index]);
|
||||
break;
|
||||
case FileIncludeKind.TypeReferenceDirective:
|
||||
({ pos, end } = file.typeReferenceDirectives[index]);
|
||||
packageId = file.resolvedTypeReferenceDirectiveNames?.get(toFileNameLowerCase(file.typeReferenceDirectives[index].fileName))?.packageId;
|
||||
break;
|
||||
case FileIncludeKind.LibReferenceDirective:
|
||||
({ pos, end } = file.libReferenceDirectives[index]);
|
||||
break;
|
||||
default:
|
||||
return Debug.assertNever(kind);
|
||||
}
|
||||
return { file, pos, end, packageId };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -754,14 +809,12 @@ namespace ts {
|
||||
let noDiagnosticsTypeChecker: TypeChecker;
|
||||
let classifiableNames: Set<__String>;
|
||||
const ambientModuleNameToUnmodifiedFileName = new Map<string, string>();
|
||||
// Todo:: Use this to report why file was included in --extendedDiagnostics
|
||||
let refFileMap: MultiMap<Path, ts.RefFile> | undefined;
|
||||
|
||||
let fileReasons = createMultiMap<Path, FileIncludeReason>();
|
||||
const cachedBindAndCheckDiagnosticsForFile: DiagnosticCache<Diagnostic> = {};
|
||||
const cachedDeclarationDiagnosticsForFile: DiagnosticCache<DiagnosticWithLocation> = {};
|
||||
|
||||
let resolvedTypeReferenceDirectives = new Map<string, ResolvedTypeReferenceDirective | undefined>();
|
||||
let fileProcessingDiagnostics = createDiagnosticCollection();
|
||||
let fileProcessingDiagnostics: FilePreprocessingDiagnostics[] | undefined;
|
||||
|
||||
// The below settings are to track if a .js file should be add to the program if loaded via searching under node_modules.
|
||||
// This works as imported modules are discovered recursively in a depth first manner, specifically:
|
||||
@@ -796,7 +849,7 @@ namespace ts {
|
||||
|
||||
// Map storing if there is emit blocking diagnostics for given input
|
||||
const hasEmitBlockingDiagnostics = new Map<string, boolean>();
|
||||
let _compilerOptionsObjectLiteralSyntax: ObjectLiteralExpression | null | undefined;
|
||||
let _compilerOptionsObjectLiteralSyntax: ObjectLiteralExpression | false | undefined;
|
||||
|
||||
let moduleResolutionCache: ModuleResolutionCache | undefined;
|
||||
let actualResolveModuleNamesWorker: (moduleNames: string[], containingFile: string, reusedNames?: string[], redirectedReference?: ResolvedProjectReference) => ResolvedModuleFull[];
|
||||
@@ -884,40 +937,35 @@ namespace ts {
|
||||
resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile);
|
||||
}
|
||||
if (rootNames.length) {
|
||||
for (const parsedRef of resolvedProjectReferences) {
|
||||
if (!parsedRef) continue;
|
||||
resolvedProjectReferences?.forEach((parsedRef, index) => {
|
||||
if (!parsedRef) return;
|
||||
const out = outFile(parsedRef.commandLine.options);
|
||||
if (useSourceOfProjectReferenceRedirect) {
|
||||
if (out || getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) {
|
||||
for (const fileName of parsedRef.commandLine.fileNames) {
|
||||
processSourceFile(fileName, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
|
||||
processProjectReferenceFile(fileName, { kind: FileIncludeKind.SourceFromProjectReference, index });
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (out) {
|
||||
processSourceFile(changeExtension(out, ".d.ts"), /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
|
||||
processProjectReferenceFile(changeExtension(out, ".d.ts"), { kind: FileIncludeKind.OutputFromProjectReference, index });
|
||||
}
|
||||
else if (getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) {
|
||||
const getCommonSourceDirectory = memoize(() => getCommonSourceDirectoryOfConfig(parsedRef.commandLine, !host.useCaseSensitiveFileNames()));
|
||||
for (const fileName of parsedRef.commandLine.fileNames) {
|
||||
if (!fileExtensionIs(fileName, Extension.Dts) && !fileExtensionIs(fileName, Extension.Json)) {
|
||||
processSourceFile(
|
||||
getOutputDeclarationFileName(fileName, parsedRef.commandLine, !host.useCaseSensitiveFileNames(), getCommonSourceDirectory),
|
||||
/*isDefaultLib*/ false,
|
||||
/*ignoreNoDefaultLib*/ false,
|
||||
/*packageId*/ undefined
|
||||
);
|
||||
processProjectReferenceFile(getOutputDeclarationFileName(fileName, parsedRef.commandLine, !host.useCaseSensitiveFileNames(), getCommonSourceDirectory), { kind: FileIncludeKind.OutputFromProjectReference, index });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
tracing.push(tracing.Phase.Program, "processRootFiles", { count: rootNames.length });
|
||||
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false));
|
||||
forEach(rootNames, (name, index) => processRootFile(name, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.RootFile, index }));
|
||||
tracing.pop();
|
||||
|
||||
// load type declarations specified via 'types' argument or implicitly from types/ and node_modules/@types folders
|
||||
@@ -930,7 +978,7 @@ namespace ts {
|
||||
const containingFilename = combinePaths(containingDirectory, inferredTypesContainingFile);
|
||||
const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeReferences, containingFilename);
|
||||
for (let i = 0; i < typeReferences.length; i++) {
|
||||
processTypeReferenceDirective(typeReferences[i], resolutions[i]);
|
||||
processTypeReferenceDirective(typeReferences[i], resolutions[i], { kind: FileIncludeKind.AutomaticTypeDirectiveFile, typeReference: typeReferences[i], packageId: resolutions[i]?.packageId });
|
||||
}
|
||||
tracing.pop();
|
||||
}
|
||||
@@ -944,11 +992,11 @@ namespace ts {
|
||||
// otherwise, using options specified in '--lib' instead of '--target' default library file
|
||||
const defaultLibraryFileName = getDefaultLibraryFileName();
|
||||
if (!options.lib && defaultLibraryFileName) {
|
||||
processRootFile(defaultLibraryFileName, /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false);
|
||||
processRootFile(defaultLibraryFileName, /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.LibFile });
|
||||
}
|
||||
else {
|
||||
forEach(options.lib, libFileName => {
|
||||
processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false);
|
||||
forEach(options.lib, (libFileName, index) => {
|
||||
processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.LibFile, index });
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -989,7 +1037,6 @@ namespace ts {
|
||||
getSourceFileByPath,
|
||||
getSourceFiles: () => files,
|
||||
getMissingFilePaths: () => missingFilePaths!, // TODO: GH#18217
|
||||
getRefFileMap: () => refFileMap,
|
||||
getFilesByNameMap: () => filesByName,
|
||||
getCompilerOptions: () => options,
|
||||
getSyntacticDiagnostics,
|
||||
@@ -1039,10 +1086,25 @@ namespace ts {
|
||||
getSymlinkCache,
|
||||
realpath: host.realpath?.bind(host),
|
||||
useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
|
||||
getFileIncludeReasons: () => fileReasons,
|
||||
structureIsReused,
|
||||
};
|
||||
|
||||
onProgramCreateComplete();
|
||||
|
||||
// Add file processingDiagnostics
|
||||
fileProcessingDiagnostics?.forEach(diagnostic => {
|
||||
switch (diagnostic.kind) {
|
||||
case FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic:
|
||||
return programDiagnostics.add(createDiagnosticExplainingFile(diagnostic.file && getSourceFileByPath(diagnostic.file), diagnostic.fileProcessingReason, diagnostic.diagnostic, diagnostic.args || emptyArray));
|
||||
case FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic:
|
||||
const { file, pos, end } = getReferencedFileLocation(getSourceFileByPath, diagnostic.reason) as ReferenceFileLocation;
|
||||
return programDiagnostics.add(createFileDiagnostic(file, Debug.checkDefined(pos), Debug.checkDefined(end) - pos, diagnostic.diagnostic, ...diagnostic.args || emptyArray));
|
||||
default:
|
||||
Debug.assertNever(diagnostic);
|
||||
}
|
||||
});
|
||||
|
||||
verifyCompilerOptions();
|
||||
performance.mark("afterProgram");
|
||||
performance.measure("Program", "beforeProgram", "afterProgram");
|
||||
@@ -1521,7 +1583,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
missingFilePaths = oldProgram.getMissingFilePaths();
|
||||
refFileMap = oldProgram.getRefFileMap();
|
||||
|
||||
// update fileName -> file mapping
|
||||
Debug.assert(newSourceFiles.length === oldProgram.getSourceFiles().length);
|
||||
@@ -1545,11 +1606,8 @@ namespace ts {
|
||||
});
|
||||
|
||||
files = newSourceFiles;
|
||||
fileReasons = oldProgram.getFileIncludeReasons();
|
||||
fileProcessingDiagnostics = oldProgram.getFileProcessingDiagnostics();
|
||||
|
||||
for (const modifiedFile of modifiedSourceFiles) {
|
||||
fileProcessingDiagnostics.reattachFileDiagnostics(modifiedFile.newFile);
|
||||
}
|
||||
resolvedTypeReferenceDirectives = oldProgram.getResolvedTypeReferenceDirectives();
|
||||
|
||||
sourceFileToPackageName = oldProgram.sourceFileToPackageName;
|
||||
@@ -1759,19 +1817,12 @@ namespace ts {
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
const fileProcessingDiagnosticsInFile = fileProcessingDiagnostics.getDiagnostics(sourceFile.fileName);
|
||||
const programDiagnosticsInFile = programDiagnostics.getDiagnostics(sourceFile.fileName);
|
||||
|
||||
return getMergedProgramDiagnostics(sourceFile, fileProcessingDiagnosticsInFile, programDiagnosticsInFile);
|
||||
}
|
||||
|
||||
function getMergedProgramDiagnostics(sourceFile: SourceFile, ...allDiagnostics: (readonly Diagnostic[] | undefined)[]) {
|
||||
const flatDiagnostics = flatten(allDiagnostics);
|
||||
if (!sourceFile.commentDirectives?.length) {
|
||||
return flatDiagnostics;
|
||||
return programDiagnosticsInFile;
|
||||
}
|
||||
|
||||
return getDiagnosticsWithPrecedingDirectives(sourceFile, sourceFile.commentDirectives, flatDiagnostics).diagnostics;
|
||||
return getDiagnosticsWithPrecedingDirectives(sourceFile, sourceFile.commentDirectives, programDiagnosticsInFile).diagnostics;
|
||||
}
|
||||
|
||||
function getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[] {
|
||||
@@ -2153,11 +2204,8 @@ namespace ts {
|
||||
|
||||
function getOptionsDiagnostics(): SortedReadonlyArray<Diagnostic> {
|
||||
return sortAndDeduplicateDiagnostics(concatenate(
|
||||
fileProcessingDiagnostics.getGlobalDiagnostics(),
|
||||
concatenate(
|
||||
programDiagnostics.getGlobalDiagnostics(),
|
||||
getOptionsDiagnosticsOfConfigFile()
|
||||
)
|
||||
programDiagnostics.getGlobalDiagnostics(),
|
||||
getOptionsDiagnosticsOfConfigFile()
|
||||
));
|
||||
}
|
||||
|
||||
@@ -2178,8 +2226,8 @@ namespace ts {
|
||||
return configFileParsingDiagnostics || emptyArray;
|
||||
}
|
||||
|
||||
function processRootFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean) {
|
||||
processSourceFile(normalizePath(fileName), isDefaultLib, ignoreNoDefaultLib, /*packageId*/ undefined);
|
||||
function processRootFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason) {
|
||||
processSourceFile(normalizePath(fileName), isDefaultLib, ignoreNoDefaultLib, /*packageId*/ undefined, reason);
|
||||
}
|
||||
|
||||
function fileReferenceIsEqualTo(a: FileReference, b: FileReference): boolean {
|
||||
@@ -2334,14 +2382,14 @@ namespace ts {
|
||||
|
||||
/** This should have similar behavior to 'processSourceFile' without diagnostics or mutation. */
|
||||
function getSourceFileFromReference(referencingFile: SourceFile | UnparsedSource, ref: FileReference): SourceFile | undefined {
|
||||
return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), fileName => filesByName.get(toPath(fileName)) || undefined);
|
||||
return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), getSourceFile);
|
||||
}
|
||||
|
||||
function getSourceFileFromReferenceWorker(
|
||||
fileName: string,
|
||||
getSourceFile: (fileName: string) => SourceFile | undefined,
|
||||
fail?: (diagnostic: DiagnosticMessage, ...argument: string[]) => void,
|
||||
refFile?: SourceFile): SourceFile | undefined {
|
||||
reason?: FileIncludeReason): SourceFile | undefined {
|
||||
|
||||
if (hasExtension(fileName)) {
|
||||
const canonicalFileName = host.getCanonicalFileName(fileName);
|
||||
@@ -2368,7 +2416,7 @@ namespace ts {
|
||||
fail(Diagnostics.File_0_not_found, fileName);
|
||||
}
|
||||
}
|
||||
else if (refFile && canonicalFileName === host.getCanonicalFileName(refFile.fileName)) {
|
||||
else if (isReferencedFile(reason) && canonicalFileName === host.getCanonicalFileName(getSourceFileByPath(reason.file)!.fileName)) {
|
||||
fail(Diagnostics.A_file_cannot_have_a_reference_to_itself);
|
||||
}
|
||||
}
|
||||
@@ -2390,34 +2438,27 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** This has side effects through `findSourceFile`. */
|
||||
function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, refFile?: RefFile): void {
|
||||
function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, reason: FileIncludeReason): void {
|
||||
getSourceFileFromReferenceWorker(
|
||||
fileName,
|
||||
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, ignoreNoDefaultLib, refFile, packageId), // TODO: GH#18217
|
||||
(diagnostic, ...args) => fileProcessingDiagnostics.add(
|
||||
createRefFileDiagnostic(refFile, diagnostic, ...args)
|
||||
),
|
||||
refFile && refFile.file
|
||||
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, ignoreNoDefaultLib, reason, packageId), // TODO: GH#18217
|
||||
(diagnostic, ...args) => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, diagnostic, args),
|
||||
reason
|
||||
);
|
||||
}
|
||||
|
||||
function reportFileNamesDifferOnlyInCasingError(fileName: string, existingFile: SourceFile, refFile: RefFile | undefined): void {
|
||||
const refs = !refFile ? refFileMap && refFileMap.get(existingFile.path) : undefined;
|
||||
const refToReportErrorOn = refs && find(refs, ref => ref.referencedFileName === existingFile.fileName);
|
||||
fileProcessingDiagnostics.add(refToReportErrorOn ?
|
||||
createFileDiagnosticAtReference(
|
||||
refToReportErrorOn,
|
||||
Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
existingFile.fileName,
|
||||
fileName,
|
||||
) :
|
||||
createRefFileDiagnostic(
|
||||
refFile,
|
||||
Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing,
|
||||
fileName,
|
||||
existingFile.fileName
|
||||
)
|
||||
);
|
||||
function processProjectReferenceFile(fileName: string, reason: ProjectReferenceFile) {
|
||||
return processSourceFile(fileName, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined, reason);
|
||||
}
|
||||
|
||||
function reportFileNamesDifferOnlyInCasingError(fileName: string, existingFile: SourceFile, reason: FileIncludeReason): void {
|
||||
const hasExistingReasonToReportErrorOn = !isReferencedFile(reason) && some(fileReasons.get(existingFile.path), isReferencedFile);
|
||||
if (hasExistingReasonToReportErrorOn) {
|
||||
addFilePreprocessingFileExplainingDiagnostic(existingFile, reason, Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing, [existingFile.fileName, fileName]);
|
||||
}
|
||||
else {
|
||||
addFilePreprocessingFileExplainingDiagnostic(existingFile, reason, Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, [fileName, existingFile.fileName]);
|
||||
}
|
||||
}
|
||||
|
||||
function createRedirectSourceFile(redirectTarget: SourceFile, unredirected: SourceFile, fileName: string, path: Path, resolvedPath: Path, originalFileName: string): SourceFile {
|
||||
@@ -2442,18 +2483,18 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Get source file from normalized fileName
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: RefFile | undefined, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
tracing.push(tracing.Phase.Program, "findSourceFile", {
|
||||
fileName,
|
||||
isDefaultLib: isDefaultLib || undefined,
|
||||
refKind: refFile ? (RefFileKind as any)[refFile.kind] : undefined,
|
||||
fileIncludeKind: (FileIncludeKind as any)[reason.kind],
|
||||
});
|
||||
const result = findSourceFileWorker(fileName, path, isDefaultLib, ignoreNoDefaultLib, refFile, packageId);
|
||||
const result = findSourceFileWorker(fileName, path, isDefaultLib, ignoreNoDefaultLib, reason, packageId);
|
||||
tracing.pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
function findSourceFileWorker(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: RefFile | undefined, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
function findSourceFileWorker(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
if (useSourceOfProjectReferenceRedirect) {
|
||||
let source = getSourceOfProjectReferenceRedirect(fileName);
|
||||
// If preserveSymlinks is true, module resolution wont jump the symlink
|
||||
@@ -2470,7 +2511,7 @@ namespace ts {
|
||||
}
|
||||
if (source) {
|
||||
const file = isString(source) ?
|
||||
findSourceFile(source, toPath(source), isDefaultLib, ignoreNoDefaultLib, refFile, packageId) :
|
||||
findSourceFile(source, toPath(source), isDefaultLib, ignoreNoDefaultLib, reason, packageId) :
|
||||
undefined;
|
||||
if (file) addFileToFilesByName(file, path, /*redirectedPath*/ undefined);
|
||||
return file;
|
||||
@@ -2479,7 +2520,7 @@ namespace ts {
|
||||
const originalFileName = fileName;
|
||||
if (filesByName.has(path)) {
|
||||
const file = filesByName.get(path);
|
||||
addFileToRefFileMap(fileName, file || undefined, refFile);
|
||||
addFileIncludeReason(file || undefined, reason);
|
||||
// try to check if we've already seen this file but with a different casing in path
|
||||
// NOTE: this only makes sense for case-insensitive file systems, and only on files which are not redirected
|
||||
if (file && options.forceConsistentCasingInFileNames) {
|
||||
@@ -2492,7 +2533,7 @@ namespace ts {
|
||||
const checkedAbsolutePath = getNormalizedAbsolutePathWithoutRoot(checkedName, currentDirectory);
|
||||
const inputAbsolutePath = getNormalizedAbsolutePathWithoutRoot(fileName, currentDirectory);
|
||||
if (checkedAbsolutePath !== inputAbsolutePath) {
|
||||
reportFileNamesDifferOnlyInCasingError(fileName, file, refFile);
|
||||
reportFileNamesDifferOnlyInCasingError(fileName, file, reason);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2523,7 +2564,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
let redirectedPath: Path | undefined;
|
||||
if (refFile && !useSourceOfProjectReferenceRedirect) {
|
||||
if (isReferencedFile(reason) && !useSourceOfProjectReferenceRedirect) {
|
||||
const redirectProject = getProjectReferenceRedirectProject(fileName);
|
||||
if (redirectProject) {
|
||||
if (outFile(redirectProject.commandLine.options)) {
|
||||
@@ -2545,12 +2586,7 @@ namespace ts {
|
||||
const file = host.getSourceFile(
|
||||
fileName,
|
||||
options.target!,
|
||||
hostErrorMessage => fileProcessingDiagnostics.add(createRefFileDiagnostic(
|
||||
refFile,
|
||||
Diagnostics.Cannot_read_file_0_Colon_1,
|
||||
fileName,
|
||||
hostErrorMessage
|
||||
)),
|
||||
hostErrorMessage => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, Diagnostics.Cannot_read_file_0_Colon_1, [fileName, hostErrorMessage]),
|
||||
shouldCreateNewSourceFile
|
||||
);
|
||||
|
||||
@@ -2563,6 +2599,7 @@ namespace ts {
|
||||
const dupFile = createRedirectSourceFile(fileFromPackageId, file!, fileName, path, toPath(fileName), originalFileName); // TODO: GH#18217
|
||||
redirectTargetsMap.add(fileFromPackageId.path, fileName);
|
||||
addFileToFilesByName(dupFile, path, redirectedPath);
|
||||
addFileIncludeReason(dupFile, reason);
|
||||
sourceFileToPackageName.set(path, packageId.name);
|
||||
processingOtherFiles!.push(dupFile);
|
||||
return dupFile;
|
||||
@@ -2581,14 +2618,14 @@ namespace ts {
|
||||
file.path = path;
|
||||
file.resolvedPath = toPath(fileName);
|
||||
file.originalFileName = originalFileName;
|
||||
addFileToRefFileMap(fileName, file, refFile);
|
||||
addFileIncludeReason(file, reason);
|
||||
|
||||
if (host.useCaseSensitiveFileNames()) {
|
||||
const pathLowerCase = toFileNameLowerCase(path);
|
||||
// for case-sensitive file systems check if we've already seen some file with similar filename ignoring case
|
||||
const existingFile = filesByNameIgnoreCase!.get(pathLowerCase);
|
||||
if (existingFile) {
|
||||
reportFileNamesDifferOnlyInCasingError(fileName, existingFile, refFile);
|
||||
reportFileNamesDifferOnlyInCasingError(fileName, existingFile, reason);
|
||||
}
|
||||
else {
|
||||
filesByNameIgnoreCase!.set(pathLowerCase, file);
|
||||
@@ -2619,15 +2656,8 @@ namespace ts {
|
||||
return file;
|
||||
}
|
||||
|
||||
function addFileToRefFileMap(referencedFileName: string, file: SourceFile | undefined, refFile: RefFile | undefined) {
|
||||
if (refFile && file) {
|
||||
(refFileMap || (refFileMap = createMultiMap())).add(file.path, {
|
||||
referencedFileName,
|
||||
kind: refFile.kind,
|
||||
index: refFile.index,
|
||||
file: refFile.file.path
|
||||
});
|
||||
}
|
||||
function addFileIncludeReason(file: SourceFile | undefined, reason: FileIncludeReason) {
|
||||
if (file) fileReasons.add(file.path, reason);
|
||||
}
|
||||
|
||||
function addFileToFilesByName(file: SourceFile | undefined, path: Path, redirectedPath: Path | undefined) {
|
||||
@@ -2728,19 +2758,12 @@ namespace ts {
|
||||
|
||||
function processReferencedFiles(file: SourceFile, isDefaultLib: boolean) {
|
||||
forEach(file.referencedFiles, (ref, index) => {
|
||||
const referencedFileName = resolveTripleslashReference(ref.fileName, file.fileName);
|
||||
processSourceFile(
|
||||
referencedFileName,
|
||||
resolveTripleslashReference(ref.fileName, file.fileName),
|
||||
isDefaultLib,
|
||||
/*ignoreNoDefaultLib*/ false,
|
||||
/*packageId*/ undefined,
|
||||
{
|
||||
kind: RefFileKind.ReferenceFile,
|
||||
index,
|
||||
file,
|
||||
pos: ref.pos,
|
||||
end: ref.end
|
||||
}
|
||||
{ kind: FileIncludeKind.ReferenceFile, file: file.path, index, }
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -2753,41 +2776,30 @@ namespace ts {
|
||||
}
|
||||
|
||||
const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeDirectives, file);
|
||||
|
||||
for (let i = 0; i < typeDirectives.length; i++) {
|
||||
const ref = file.typeReferenceDirectives[i];
|
||||
const resolvedTypeReferenceDirective = resolutions[i];
|
||||
for (let index = 0; index < typeDirectives.length; index++) {
|
||||
const ref = file.typeReferenceDirectives[index];
|
||||
const resolvedTypeReferenceDirective = resolutions[index];
|
||||
// store resolved type directive on the file
|
||||
const fileName = toFileNameLowerCase(ref.fileName);
|
||||
setResolvedTypeReferenceDirective(file, fileName, resolvedTypeReferenceDirective);
|
||||
processTypeReferenceDirective(
|
||||
fileName,
|
||||
resolvedTypeReferenceDirective,
|
||||
{
|
||||
kind: RefFileKind.TypeReferenceDirective,
|
||||
index: i,
|
||||
file,
|
||||
pos: ref.pos,
|
||||
end: ref.end
|
||||
}
|
||||
);
|
||||
processTypeReferenceDirective(fileName, resolvedTypeReferenceDirective, { kind: FileIncludeKind.TypeReferenceDirective, file: file.path, index, });
|
||||
}
|
||||
}
|
||||
|
||||
function processTypeReferenceDirective(
|
||||
typeReferenceDirective: string,
|
||||
resolvedTypeReferenceDirective?: ResolvedTypeReferenceDirective,
|
||||
refFile?: RefFile
|
||||
resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined,
|
||||
reason: FileIncludeReason
|
||||
): void {
|
||||
tracing.push(tracing.Phase.Program, "processTypeReferenceDirective", { directive: typeReferenceDirective, hasResolved: !!resolveModuleNamesReusingOldState, refKind: refFile?.kind, refPath: refFile?.file.path });
|
||||
processTypeReferenceDirectiveWorker(typeReferenceDirective, resolvedTypeReferenceDirective, refFile);
|
||||
tracing.push(tracing.Phase.Program, "processTypeReferenceDirective", { directive: typeReferenceDirective, hasResolved: !!resolveModuleNamesReusingOldState, refKind: reason.kind, refPath: isReferencedFile(reason) ? reason.file : undefined });
|
||||
processTypeReferenceDirectiveWorker(typeReferenceDirective, resolvedTypeReferenceDirective, reason);
|
||||
tracing.pop();
|
||||
}
|
||||
|
||||
function processTypeReferenceDirectiveWorker(
|
||||
typeReferenceDirective: string,
|
||||
resolvedTypeReferenceDirective?: ResolvedTypeReferenceDirective,
|
||||
refFile?: RefFile
|
||||
resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined,
|
||||
reason: FileIncludeReason
|
||||
): void {
|
||||
|
||||
// If we already found this library as a primary reference - nothing to do
|
||||
@@ -2801,7 +2813,7 @@ namespace ts {
|
||||
|
||||
if (resolvedTypeReferenceDirective.primary) {
|
||||
// resolved from the primary path
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile); // TODO: GH#18217
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, reason); // TODO: GH#18217
|
||||
}
|
||||
else {
|
||||
// If we already resolved to this file, it must have been a secondary reference. Check file contents
|
||||
@@ -2812,25 +2824,11 @@ namespace ts {
|
||||
const otherFileText = host.readFile(resolvedTypeReferenceDirective.resolvedFileName!);
|
||||
const existingFile = getSourceFile(previousResolution.resolvedFileName!)!;
|
||||
if (otherFileText !== existingFile.text) {
|
||||
// Try looking up ref for original file
|
||||
const refs = !refFile ? refFileMap && refFileMap.get(existingFile.path) : undefined;
|
||||
const refToReportErrorOn = refs && find(refs, ref => ref.referencedFileName === existingFile.fileName);
|
||||
fileProcessingDiagnostics.add(
|
||||
refToReportErrorOn ?
|
||||
createFileDiagnosticAtReference(
|
||||
refToReportErrorOn,
|
||||
Diagnostics.Conflicting_definitions_for_0_found_at_1_and_2_Consider_installing_a_specific_version_of_this_library_to_resolve_the_conflict,
|
||||
typeReferenceDirective,
|
||||
resolvedTypeReferenceDirective.resolvedFileName,
|
||||
previousResolution.resolvedFileName
|
||||
) :
|
||||
createRefFileDiagnostic(
|
||||
refFile,
|
||||
Diagnostics.Conflicting_definitions_for_0_found_at_1_and_2_Consider_installing_a_specific_version_of_this_library_to_resolve_the_conflict,
|
||||
typeReferenceDirective,
|
||||
resolvedTypeReferenceDirective.resolvedFileName,
|
||||
previousResolution.resolvedFileName
|
||||
)
|
||||
addFilePreprocessingFileExplainingDiagnostic(
|
||||
existingFile,
|
||||
reason,
|
||||
Diagnostics.Conflicting_definitions_for_0_found_at_1_and_2_Consider_installing_a_specific_version_of_this_library_to_resolve_the_conflict,
|
||||
[typeReferenceDirective, resolvedTypeReferenceDirective.resolvedFileName, previousResolution.resolvedFileName]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2839,18 +2837,14 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
// First resolution of this library
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile);
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, reason);
|
||||
}
|
||||
}
|
||||
|
||||
if (resolvedTypeReferenceDirective.isExternalLibraryImport) currentNodeModulesDepth--;
|
||||
}
|
||||
else {
|
||||
fileProcessingDiagnostics.add(createRefFileDiagnostic(
|
||||
refFile,
|
||||
Diagnostics.Cannot_find_type_definition_file_for_0,
|
||||
typeReferenceDirective
|
||||
));
|
||||
addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, Diagnostics.Cannot_find_type_definition_file_for_0, [typeReferenceDirective]);
|
||||
}
|
||||
|
||||
if (saveResolution) {
|
||||
@@ -2859,38 +2853,27 @@ namespace ts {
|
||||
}
|
||||
|
||||
function processLibReferenceDirectives(file: SourceFile) {
|
||||
forEach(file.libReferenceDirectives, libReference => {
|
||||
forEach(file.libReferenceDirectives, (libReference, index) => {
|
||||
const libName = toFileNameLowerCase(libReference.fileName);
|
||||
const libFileName = libMap.get(libName);
|
||||
if (libFileName) {
|
||||
// we ignore any 'no-default-lib' reference set on this file.
|
||||
processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ true);
|
||||
processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ true, { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index, });
|
||||
}
|
||||
else {
|
||||
const unqualifiedLibName = removeSuffix(removePrefix(libName, "lib."), ".d.ts");
|
||||
const suggestion = getSpellingSuggestion(unqualifiedLibName, libs, identity);
|
||||
const message = suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 : Diagnostics.Cannot_find_lib_definition_for_0;
|
||||
fileProcessingDiagnostics.add(createFileDiagnostic(
|
||||
file,
|
||||
libReference.pos,
|
||||
libReference.end - libReference.pos,
|
||||
message,
|
||||
libName,
|
||||
suggestion
|
||||
));
|
||||
const diagnostic = suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 : Diagnostics.Cannot_find_lib_definition_for_0;
|
||||
(fileProcessingDiagnostics ||= []).push({
|
||||
kind: FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic,
|
||||
reason: { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index, },
|
||||
diagnostic,
|
||||
args: [libName, suggestion]
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createRefFileDiagnostic(refFile: RefFile | undefined, message: DiagnosticMessage, ...args: any[]): Diagnostic {
|
||||
if (!refFile) {
|
||||
return createCompilerDiagnostic(message, ...args);
|
||||
}
|
||||
else {
|
||||
return createFileDiagnostic(refFile.file, refFile.pos, refFile.end - refFile.pos, message, ...args);
|
||||
}
|
||||
}
|
||||
|
||||
function getCanonicalFileName(fileName: string): string {
|
||||
return host.getCanonicalFileName(fileName);
|
||||
}
|
||||
@@ -2902,9 +2885,9 @@ namespace ts {
|
||||
const moduleNames = getModuleNames(file);
|
||||
const resolutions = resolveModuleNamesReusingOldState(moduleNames, file);
|
||||
Debug.assert(resolutions.length === moduleNames.length);
|
||||
for (let i = 0; i < moduleNames.length; i++) {
|
||||
const resolution = resolutions[i];
|
||||
setResolvedModule(file, moduleNames[i], resolution);
|
||||
for (let index = 0; index < moduleNames.length; index++) {
|
||||
const resolution = resolutions[index];
|
||||
setResolvedModule(file, moduleNames[index], resolution);
|
||||
|
||||
if (!resolution) {
|
||||
continue;
|
||||
@@ -2930,30 +2913,23 @@ namespace ts {
|
||||
const shouldAddFile = resolvedFileName
|
||||
&& !getResolutionDiagnostic(options, resolution)
|
||||
&& !options.noResolve
|
||||
&& i < file.imports.length
|
||||
&& index < file.imports.length
|
||||
&& !elideImport
|
||||
&& !(isJsFile && !getAllowJSCompilerOption(options))
|
||||
&& (isInJSFile(file.imports[i]) || !(file.imports[i].flags & NodeFlags.JSDoc));
|
||||
&& (isInJSFile(file.imports[index]) || !(file.imports[index].flags & NodeFlags.JSDoc));
|
||||
|
||||
if (elideImport) {
|
||||
modulesWithElidedImports.set(file.path, true);
|
||||
}
|
||||
else if (shouldAddFile) {
|
||||
const path = toPath(resolvedFileName);
|
||||
const pos = skipTrivia(file.text, file.imports[i].pos);
|
||||
findSourceFile(
|
||||
resolvedFileName,
|
||||
path,
|
||||
/*isDefaultLib*/ false,
|
||||
/*ignoreNoDefaultLib*/ false,
|
||||
{
|
||||
kind: RefFileKind.Import,
|
||||
index: i,
|
||||
file,
|
||||
pos,
|
||||
end: file.imports[i].end
|
||||
},
|
||||
resolution.packageId
|
||||
{ kind: FileIncludeKind.Import, file: file.path, index, },
|
||||
resolution.packageId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2971,19 +2947,14 @@ namespace ts {
|
||||
function checkSourceFilesBelongToPath(sourceFiles: readonly SourceFile[], rootDirectory: string): boolean {
|
||||
let allFilesBelongToPath = true;
|
||||
const absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory));
|
||||
let rootPaths: Set<Path> | undefined;
|
||||
|
||||
for (const sourceFile of sourceFiles) {
|
||||
if (!sourceFile.isDeclarationFile) {
|
||||
const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
|
||||
if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
|
||||
if (!rootPaths) rootPaths = new Set(rootNames.map(toPath));
|
||||
addProgramDiagnosticAtRefPath(
|
||||
addProgramDiagnosticExplainingFile(
|
||||
sourceFile,
|
||||
rootPaths,
|
||||
Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files,
|
||||
sourceFile.fileName,
|
||||
rootDirectory
|
||||
[sourceFile.fileName, rootDirectory]
|
||||
);
|
||||
allFilesBelongToPath = false;
|
||||
}
|
||||
@@ -3094,12 +3065,10 @@ namespace ts {
|
||||
for (const file of files) {
|
||||
// Ignore file that is not emitted
|
||||
if (sourceFileMayBeEmitted(file, program) && !rootPaths.has(file.path)) {
|
||||
addProgramDiagnosticAtRefPath(
|
||||
addProgramDiagnosticExplainingFile(
|
||||
file,
|
||||
rootPaths,
|
||||
Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern,
|
||||
file.fileName,
|
||||
options.configFilePath || ""
|
||||
[file.fileName, options.configFilePath || ""]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3343,35 +3312,138 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function createFileDiagnosticAtReference(refPathToReportErrorOn: ts.RefFile, message: DiagnosticMessage, ...args: (string | number | undefined)[]) {
|
||||
const refFile = Debug.checkDefined(getSourceFileByPath(refPathToReportErrorOn.file));
|
||||
const { kind, index } = refPathToReportErrorOn;
|
||||
let pos: number, end: number;
|
||||
switch (kind) {
|
||||
case RefFileKind.Import:
|
||||
pos = skipTrivia(refFile.text, refFile.imports[index].pos);
|
||||
end = refFile.imports[index].end;
|
||||
break;
|
||||
case RefFileKind.ReferenceFile:
|
||||
({ pos, end } = refFile.referencedFiles[index]);
|
||||
break;
|
||||
case RefFileKind.TypeReferenceDirective:
|
||||
({ pos, end } = refFile.typeReferenceDirectives[index]);
|
||||
break;
|
||||
default:
|
||||
return Debug.assertNever(kind);
|
||||
function createDiagnosticExplainingFile(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason | undefined, diagnostic: DiagnosticMessage, args: (string | number | undefined)[] | undefined): Diagnostic {
|
||||
let fileIncludeReasons: DiagnosticMessageChain[] | undefined;
|
||||
let relatedInfo: Diagnostic[] | undefined;
|
||||
let locationReason = isReferencedFile(fileProcessingReason) ? fileProcessingReason : undefined;
|
||||
if (file) fileReasons.get(file.path)?.forEach(processReason);
|
||||
if (fileProcessingReason) processReason(fileProcessingReason);
|
||||
// If we have location and there is only one reason file is in which is the location, dont add details for file include
|
||||
if (locationReason && fileIncludeReasons?.length === 1) fileIncludeReasons = undefined;
|
||||
const location = locationReason && getReferencedFileLocation(getSourceFileByPath, locationReason);
|
||||
const fileIncludeReasonDetails = fileIncludeReasons && chainDiagnosticMessages(fileIncludeReasons, Diagnostics.The_file_is_in_the_program_because_Colon);
|
||||
const redirectInfo = file && explainIfFileIsRedirect(file);
|
||||
const chain = chainDiagnosticMessages(redirectInfo ? fileIncludeReasonDetails ? [fileIncludeReasonDetails, ...redirectInfo] : redirectInfo : fileIncludeReasonDetails, diagnostic, ...args || emptyArray);
|
||||
return location && isReferenceFileLocation(location) ?
|
||||
createFileDiagnosticFromMessageChain(location.file, location.pos, location.end - location.pos, chain, relatedInfo) :
|
||||
createCompilerDiagnosticFromMessageChain(chain, relatedInfo);
|
||||
|
||||
function processReason(reason: FileIncludeReason) {
|
||||
(fileIncludeReasons ||= []).push(fileIncludeReasonToDiagnostics(program, reason));
|
||||
if (!locationReason && isReferencedFile(reason)) {
|
||||
// Report error at first reference file or file currently in processing and dont report in related information
|
||||
locationReason = reason;
|
||||
}
|
||||
else if (locationReason !== reason) {
|
||||
relatedInfo = append(relatedInfo, fileIncludeReasonToRelatedInformation(reason));
|
||||
}
|
||||
// Remove fileProcessingReason if its already included in fileReasons of the program
|
||||
if (reason === fileProcessingReason) fileProcessingReason = undefined;
|
||||
}
|
||||
return createFileDiagnostic(refFile, pos, end - pos, message, ...args);
|
||||
}
|
||||
|
||||
function addProgramDiagnosticAtRefPath(file: SourceFile, rootPaths: Set<Path>, message: DiagnosticMessage, ...args: (string | number | undefined)[]) {
|
||||
const refPaths = refFileMap?.get(file.path);
|
||||
const refPathToReportErrorOn = forEach(refPaths, refPath => rootPaths.has(refPath.file) ? refPath : undefined) ||
|
||||
elementAt(refPaths, 0);
|
||||
programDiagnostics.add(
|
||||
refPathToReportErrorOn ?
|
||||
createFileDiagnosticAtReference(refPathToReportErrorOn, message, ...args) :
|
||||
createCompilerDiagnostic(message, ...args)
|
||||
function addFilePreprocessingFileExplainingDiagnostic(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason, diagnostic: DiagnosticMessage, args?: (string | number | undefined)[]) {
|
||||
(fileProcessingDiagnostics ||= []).push({
|
||||
kind: FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic,
|
||||
file: file && file.path,
|
||||
fileProcessingReason,
|
||||
diagnostic,
|
||||
args
|
||||
});
|
||||
}
|
||||
|
||||
function addProgramDiagnosticExplainingFile(file: SourceFile, diagnostic: DiagnosticMessage, args?: (string | number | undefined)[]) {
|
||||
programDiagnostics.add(createDiagnosticExplainingFile(file, /*fileProcessingReason*/ undefined, diagnostic, args));
|
||||
}
|
||||
|
||||
function fileIncludeReasonToRelatedInformation(reason: FileIncludeReason): DiagnosticWithLocation | undefined {
|
||||
if (isReferencedFile(reason)) {
|
||||
const referenceLocation = getReferencedFileLocation(getSourceFileByPath, reason);
|
||||
let message: DiagnosticMessage;
|
||||
switch (reason.kind) {
|
||||
case FileIncludeKind.Import:
|
||||
message = Diagnostics.File_is_included_via_import_here;
|
||||
break;
|
||||
case FileIncludeKind.ReferenceFile:
|
||||
message = Diagnostics.File_is_included_via_reference_here;
|
||||
break;
|
||||
case FileIncludeKind.TypeReferenceDirective:
|
||||
message = Diagnostics.File_is_included_via_type_library_reference_here;
|
||||
break;
|
||||
case FileIncludeKind.LibReferenceDirective:
|
||||
message = Diagnostics.File_is_included_via_library_reference_here;
|
||||
break;
|
||||
default:
|
||||
Debug.assertNever(reason);
|
||||
}
|
||||
return isReferenceFileLocation(referenceLocation) ? createFileDiagnostic(
|
||||
referenceLocation.file,
|
||||
referenceLocation.pos,
|
||||
referenceLocation.end - referenceLocation.pos,
|
||||
message,
|
||||
) : undefined;
|
||||
}
|
||||
|
||||
if (!options.configFile) return undefined;
|
||||
let configFileNode: Node | undefined;
|
||||
let message: DiagnosticMessage;
|
||||
switch (reason.kind) {
|
||||
case FileIncludeKind.RootFile:
|
||||
if (!options.configFile.configFileSpecs) return undefined;
|
||||
const fileName = getNormalizedAbsolutePath(rootNames[reason.index], currentDirectory);
|
||||
const matchedByFiles = getMatchedFileSpec(program, fileName);
|
||||
if (matchedByFiles) {
|
||||
configFileNode = getTsConfigPropArrayElementValue(options.configFile, "files", matchedByFiles);
|
||||
message = Diagnostics.File_is_matched_by_files_list_specified_here;
|
||||
break;
|
||||
}
|
||||
const matchedByInclude = getMatchedIncludeSpec(program, fileName);
|
||||
// Could be additional files specified as roots
|
||||
if (!matchedByInclude) return undefined;
|
||||
configFileNode = getTsConfigPropArrayElementValue(options.configFile, "include", matchedByInclude);
|
||||
message = Diagnostics.File_is_matched_by_include_pattern_specified_here;
|
||||
break;
|
||||
case FileIncludeKind.SourceFromProjectReference:
|
||||
case FileIncludeKind.OutputFromProjectReference:
|
||||
const referencedResolvedRef = Debug.checkDefined(resolvedProjectReferences?.[reason.index]);
|
||||
const referenceInfo = forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, parent, index) =>
|
||||
resolvedRef === referencedResolvedRef ? { sourceFile: parent?.sourceFile || options.configFile!, index } : undefined
|
||||
);
|
||||
if (!referenceInfo) return undefined;
|
||||
const { sourceFile, index } = referenceInfo;
|
||||
const referencesSyntax = firstDefined(getTsConfigPropArray(sourceFile as TsConfigSourceFile, "references"),
|
||||
property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
|
||||
return referencesSyntax && referencesSyntax.elements.length > index ?
|
||||
createDiagnosticForNodeInSourceFile(
|
||||
sourceFile,
|
||||
referencesSyntax.elements[index],
|
||||
reason.kind === FileIncludeKind.OutputFromProjectReference ?
|
||||
Diagnostics.File_is_output_from_referenced_project_specified_here :
|
||||
Diagnostics.File_is_source_from_referenced_project_specified_here,
|
||||
) :
|
||||
undefined;
|
||||
case FileIncludeKind.AutomaticTypeDirectiveFile:
|
||||
if (!options.types) return undefined;
|
||||
configFileNode = getOptionsSyntaxByArrayElementValue("types", reason.typeReference);
|
||||
message = Diagnostics.File_is_entry_point_of_type_library_specified_here;
|
||||
break;
|
||||
case FileIncludeKind.LibFile:
|
||||
if (reason.index !== undefined) {
|
||||
configFileNode = getOptionsSyntaxByArrayElementValue("lib", options.lib![reason.index]);
|
||||
message = Diagnostics.File_is_library_specified_here;
|
||||
break;
|
||||
}
|
||||
const target = forEachEntry(targetOptionDeclaration.type, (value, key) => value === options.target ? key : undefined);
|
||||
configFileNode = target ? getOptionsSyntaxByValue("target", target) : undefined;
|
||||
message = Diagnostics.File_is_default_library_for_target_specified_here;
|
||||
break;
|
||||
default:
|
||||
Debug.assertNever(reason);
|
||||
}
|
||||
return configFileNode && createDiagnosticForNodeInSourceFile(
|
||||
options.configFile,
|
||||
configFileNode,
|
||||
message,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3447,16 +3519,23 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getOptionsSyntaxByName(name: string): object | undefined {
|
||||
function getOptionsSyntaxByName(name: string) {
|
||||
const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
|
||||
if (compilerOptionsObjectLiteralSyntax) {
|
||||
return getPropertyAssignment(compilerOptionsObjectLiteralSyntax, name);
|
||||
}
|
||||
return undefined;
|
||||
return compilerOptionsObjectLiteralSyntax && getPropertyAssignment(compilerOptionsObjectLiteralSyntax, name);
|
||||
}
|
||||
|
||||
function getOptionPathsSyntax(): PropertyAssignment[] {
|
||||
return getOptionsSyntaxByName("paths") as PropertyAssignment[] || emptyArray;
|
||||
function getOptionPathsSyntax() {
|
||||
return getOptionsSyntaxByName("paths") || emptyArray;
|
||||
}
|
||||
|
||||
function getOptionsSyntaxByValue(name: string, value: string) {
|
||||
const syntaxByName = getOptionsSyntaxByName(name);
|
||||
return syntaxByName && firstDefined(syntaxByName, property => isStringLiteral(property.initializer) && property.initializer.text === value ? property.initializer : undefined);
|
||||
}
|
||||
|
||||
function getOptionsSyntaxByArrayElementValue(name: string, value: string) {
|
||||
const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
|
||||
return compilerOptionsObjectLiteralSyntax && getPropertyArrayElementValue(compilerOptionsObjectLiteralSyntax, name, value);
|
||||
}
|
||||
|
||||
function createDiagnosticForOptionName(message: DiagnosticMessage, option1: string, option2?: string, option3?: string) {
|
||||
@@ -3490,7 +3569,7 @@ namespace ts {
|
||||
|
||||
function getCompilerOptionsObjectLiteralSyntax() {
|
||||
if (_compilerOptionsObjectLiteralSyntax === undefined) {
|
||||
_compilerOptionsObjectLiteralSyntax = null; // eslint-disable-line no-null/no-null
|
||||
_compilerOptionsObjectLiteralSyntax = false;
|
||||
const jsonObjectLiteral = getTsConfigObjectLiteralExpression(options.configFile);
|
||||
if (jsonObjectLiteral) {
|
||||
for (const prop of getPropertyAssignment(jsonObjectLiteral, "compilerOptions")) {
|
||||
@@ -3501,7 +3580,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
return _compilerOptionsObjectLiteralSyntax;
|
||||
return _compilerOptionsObjectLiteralSyntax || undefined;
|
||||
}
|
||||
|
||||
function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage, arg0: string | number, arg1?: string | number, arg2?: string | number): boolean {
|
||||
@@ -3743,8 +3822,8 @@ namespace ts {
|
||||
export const emitSkippedWithNoDiagnostics: EmitResult = { diagnostics: emptyArray, sourceMaps: undefined, emittedFiles: undefined, emitSkipped: true };
|
||||
|
||||
/*@internal*/
|
||||
export function handleNoEmitOptions(
|
||||
program: ProgramToEmitFilesAndReportErrors,
|
||||
export function handleNoEmitOptions<T extends BuilderProgram>(
|
||||
program: Program | T,
|
||||
sourceFile: SourceFile | undefined,
|
||||
writeFile: WriteFileCallback | undefined,
|
||||
cancellationToken: CancellationToken | undefined
|
||||
@@ -3893,4 +3972,17 @@ namespace ts {
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function getModuleNameStringLiteralAt({ imports, moduleAugmentations }: SourceFile, index: number): StringLiteralLike {
|
||||
if (index < imports.length) return imports[index];
|
||||
let augIndex = imports.length;
|
||||
for (const aug of moduleAugmentations) {
|
||||
if (aug.kind === SyntaxKind.StringLiteral) {
|
||||
if (index === augIndex) return aug;
|
||||
augIndex++;
|
||||
}
|
||||
// Do nothing if it's an Identifier; we don't need to do module resolution for `declare global`.
|
||||
}
|
||||
Debug.fail("should never ask for module name at index higher than possible module name");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace ts {
|
||||
/*@internal*/ preserveWatchOutput?: boolean;
|
||||
/*@internal*/ listEmittedFiles?: boolean;
|
||||
/*@internal*/ listFiles?: boolean;
|
||||
/*@internal*/ explainFiles?: boolean;
|
||||
/*@internal*/ pretty?: boolean;
|
||||
incremental?: boolean;
|
||||
assumeChangesOnlyAffectDirectDependencies?: boolean;
|
||||
@@ -215,7 +216,7 @@ namespace ts {
|
||||
readonly currentDirectory: string;
|
||||
readonly getCanonicalFileName: GetCanonicalFileName;
|
||||
readonly parseConfigFileHost: ParseConfigFileHost;
|
||||
readonly writeFileName: ((s: string) => void) | undefined;
|
||||
readonly write: ((s: string) => void) | undefined;
|
||||
|
||||
// State of solution
|
||||
readonly options: BuildOptions;
|
||||
@@ -287,7 +288,7 @@ namespace ts {
|
||||
currentDirectory,
|
||||
getCanonicalFileName,
|
||||
parseConfigFileHost: parseConfigHostFromCompilerHostLike(host),
|
||||
writeFileName: host.trace ? (s: string) => host.trace!(s) : undefined,
|
||||
write: maybeBind(host, host.trace),
|
||||
|
||||
// State of solution
|
||||
options,
|
||||
@@ -892,7 +893,7 @@ namespace ts {
|
||||
const { emitResult } = emitFilesAndReportErrors(
|
||||
program,
|
||||
reportDeclarationDiagnostics,
|
||||
/*writeFileName*/ undefined,
|
||||
/*write*/ undefined,
|
||||
/*reportSummary*/ undefined,
|
||||
(name, text, writeByteOrderMark) => outputFiles.push({ name, text, writeByteOrderMark }),
|
||||
cancellationToken,
|
||||
@@ -965,7 +966,7 @@ namespace ts {
|
||||
buildResult = BuildResultFlags.EmitErrors & buildResult!;
|
||||
}
|
||||
|
||||
if (emitResult.emittedFiles && state.writeFileName) {
|
||||
if (emitResult.emittedFiles && state.write) {
|
||||
emitResult.emittedFiles.forEach(name => listEmittedFile(state, config, name));
|
||||
}
|
||||
afterProgramDone(state, program, config);
|
||||
@@ -995,7 +996,7 @@ namespace ts {
|
||||
return emitDiagnostics;
|
||||
}
|
||||
|
||||
if (state.writeFileName) {
|
||||
if (state.write) {
|
||||
emittedOutputs.forEach(name => listEmittedFile(state, config, name));
|
||||
}
|
||||
|
||||
@@ -1169,9 +1170,8 @@ namespace ts {
|
||||
}
|
||||
else if (reloadLevel === ConfigFileProgramReloadLevel.Partial) {
|
||||
// Update file names
|
||||
const result = getFileNamesFromConfigSpecs(config.configFileSpecs!, getDirectoryPath(project), config.options, state.parseConfigFileHost);
|
||||
updateErrorForNoInputFiles(result, project, config.configFileSpecs!, config.errors, canJsonReportNoInputFiles(config.raw));
|
||||
config.fileNames = result.fileNames;
|
||||
config.fileNames = getFileNamesFromConfigSpecs(config.options.configFile!.configFileSpecs!, getDirectoryPath(project), config.options, state.parseConfigFileHost);
|
||||
updateErrorForNoInputFiles(config.fileNames, project, config.options.configFile!.configFileSpecs!, config.errors, canJsonReportNoInputFiles(config.raw));
|
||||
watchInputFiles(state, project, projectPath, config);
|
||||
}
|
||||
|
||||
@@ -1240,9 +1240,9 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function listEmittedFile({ writeFileName }: SolutionBuilderState, proj: ParsedCommandLine, file: string) {
|
||||
if (writeFileName && proj.options.listEmittedFiles) {
|
||||
writeFileName(`TSFILE: ${file}`);
|
||||
function listEmittedFile({ write }: SolutionBuilderState, proj: ParsedCommandLine, file: string) {
|
||||
if (write && proj.options.listEmittedFiles) {
|
||||
write(`TSFILE: ${file}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1259,7 +1259,7 @@ namespace ts {
|
||||
config: ParsedCommandLine
|
||||
) {
|
||||
if (program) {
|
||||
if (program && state.writeFileName) listFiles(program, state.writeFileName);
|
||||
if (program && state.write) listFiles(program, state.write);
|
||||
if (state.host.afterProgramEmitAndDiagnostics) {
|
||||
state.host.afterProgramEmitAndDiagnostics(program);
|
||||
}
|
||||
@@ -1283,7 +1283,6 @@ namespace ts {
|
||||
const canEmitBuildInfo = !(buildResult & BuildResultFlags.SyntaxErrors) && program && !outFile(program.getCompilerOptions());
|
||||
|
||||
reportAndStoreErrors(state, resolvedPath, diagnostics);
|
||||
// List files if any other build error using program (emit errors already report files)
|
||||
state.projectStatus.set(resolvedPath, { type: UpToDateStatusType.Unbuildable, reason: `${errorType} errors` });
|
||||
if (canEmitBuildInfo) return { buildResult, step: BuildStep.EmitBuildInfo };
|
||||
afterProgramDone(state, program, config);
|
||||
@@ -1794,7 +1793,7 @@ namespace ts {
|
||||
if (!state.watch) return;
|
||||
updateWatchingWildcardDirectories(
|
||||
getOrCreateValueMapFromConfigFileMap(state.allWatchedWildcardDirectories, resolvedPath),
|
||||
new Map(getEntries(parsed.configFileSpecs!.wildcardDirectories)),
|
||||
new Map(getEntries(parsed.wildcardDirectories!)),
|
||||
(dir, flags) => state.watchDirectory(
|
||||
dir,
|
||||
fileOrDirectory => {
|
||||
@@ -1803,7 +1802,6 @@ namespace ts {
|
||||
fileOrDirectory,
|
||||
fileOrDirectoryPath: toPath(state, fileOrDirectory),
|
||||
configFileName: resolved,
|
||||
configFileSpecs: parsed.configFileSpecs!,
|
||||
currentDirectory: state.currentDirectory,
|
||||
options: parsed.options,
|
||||
program: state.builderPrograms.get(resolvedPath),
|
||||
|
||||
+85
-19
@@ -3620,6 +3620,7 @@ namespace ts {
|
||||
|
||||
export interface TsConfigSourceFile extends JsonSourceFile {
|
||||
extendedSourceFiles?: string[];
|
||||
/*@internal*/ configFileSpecs?: ConfigFileSpecs;
|
||||
}
|
||||
|
||||
export interface JsonMinusNumericLiteral extends PrefixUnaryExpression {
|
||||
@@ -3689,20 +3690,94 @@ namespace ts {
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export enum RefFileKind {
|
||||
export enum FileIncludeKind {
|
||||
RootFile,
|
||||
SourceFromProjectReference,
|
||||
OutputFromProjectReference,
|
||||
Import,
|
||||
ReferenceFile,
|
||||
TypeReferenceDirective
|
||||
TypeReferenceDirective,
|
||||
LibFile,
|
||||
LibReferenceDirective,
|
||||
AutomaticTypeDirectiveFile
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface RefFile {
|
||||
referencedFileName: string;
|
||||
kind: RefFileKind;
|
||||
export interface RootFile {
|
||||
kind: FileIncludeKind.RootFile,
|
||||
index: number;
|
||||
file: Path;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface LibFile {
|
||||
kind: FileIncludeKind.LibFile;
|
||||
index?: number;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export type ProjectReferenceFileKind = FileIncludeKind.SourceFromProjectReference |
|
||||
FileIncludeKind.OutputFromProjectReference;
|
||||
|
||||
/*@internal*/
|
||||
export interface ProjectReferenceFile {
|
||||
kind: ProjectReferenceFileKind;
|
||||
index: number;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export type ReferencedFileKind = FileIncludeKind.Import |
|
||||
FileIncludeKind.ReferenceFile |
|
||||
FileIncludeKind.TypeReferenceDirective |
|
||||
FileIncludeKind.LibReferenceDirective;
|
||||
|
||||
/*@internal*/
|
||||
export interface ReferencedFile {
|
||||
kind: ReferencedFileKind;
|
||||
file: Path;
|
||||
index: number;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface AutomaticTypeDirectiveFile {
|
||||
kind: FileIncludeKind.AutomaticTypeDirectiveFile;
|
||||
typeReference: string;
|
||||
packageId: PackageId | undefined;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export type FileIncludeReason =
|
||||
RootFile |
|
||||
LibFile |
|
||||
ProjectReferenceFile |
|
||||
ReferencedFile |
|
||||
AutomaticTypeDirectiveFile;
|
||||
|
||||
/*@internal*/
|
||||
export const enum FilePreprocessingDiagnosticsKind {
|
||||
FilePreprocessingReferencedDiagnostic,
|
||||
FilePreprocessingFileExplainingDiagnostic
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface FilePreprocessingReferencedDiagnostic {
|
||||
kind: FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic;
|
||||
reason: ReferencedFile;
|
||||
diagnostic: DiagnosticMessage;
|
||||
args?: (string | number | undefined)[];
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface FilePreprocessingFileExplainingDiagnostic {
|
||||
kind: FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic;
|
||||
file?: Path;
|
||||
fileProcessingReason: FileIncludeReason;
|
||||
diagnostic: DiagnosticMessage;
|
||||
args?: (string | number | undefined)[];
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export type FilePreprocessingDiagnostics = FilePreprocessingReferencedDiagnostic | FilePreprocessingFileExplainingDiagnostic;
|
||||
|
||||
export interface Program extends ScriptReferenceHost {
|
||||
getCurrentDirectory(): string;
|
||||
/**
|
||||
@@ -3722,8 +3797,6 @@ namespace ts {
|
||||
/* @internal */
|
||||
getMissingFilePaths(): readonly Path[];
|
||||
/* @internal */
|
||||
getRefFileMap(): MultiMap<Path, RefFile> | undefined;
|
||||
/* @internal */
|
||||
getFilesByNameMap(): ESMap<string, SourceFile | false | undefined>;
|
||||
|
||||
/**
|
||||
@@ -3777,7 +3850,7 @@ namespace ts {
|
||||
getInstantiationCount(): number;
|
||||
getRelationCacheSizes(): { assignable: number, identity: number, subtype: number, strictSubtype: number };
|
||||
|
||||
/* @internal */ getFileProcessingDiagnostics(): DiagnosticCollection;
|
||||
/* @internal */ getFileProcessingDiagnostics(): FilePreprocessingDiagnostics[] | undefined;
|
||||
/* @internal */ getResolvedTypeReferenceDirectives(): ESMap<string, ResolvedTypeReferenceDirective | undefined>;
|
||||
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
|
||||
isSourceFileDefaultLibrary(file: SourceFile): boolean;
|
||||
@@ -3795,6 +3868,8 @@ namespace ts {
|
||||
/* @internal */ redirectTargetsMap: MultiMap<string, string>;
|
||||
/** Is the file emitted file */
|
||||
/* @internal */ isEmittedFile(file: string): boolean;
|
||||
/* @internal */ getFileIncludeReasons(): MultiMap<Path, FileIncludeReason>;
|
||||
/* @internal */ useCaseSensitiveFileNames(): boolean;
|
||||
|
||||
/* @internal */ getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations | undefined;
|
||||
|
||||
@@ -5769,6 +5844,7 @@ namespace ts {
|
||||
lib?: string[];
|
||||
/*@internal*/listEmittedFiles?: boolean;
|
||||
/*@internal*/listFiles?: boolean;
|
||||
/*@internal*/explainFiles?: boolean;
|
||||
/*@internal*/listFilesOnly?: boolean;
|
||||
locale?: string;
|
||||
mapRoot?: string;
|
||||
@@ -5957,7 +6033,6 @@ namespace ts {
|
||||
errors: Diagnostic[];
|
||||
wildcardDirectories?: MapLike<WatchDirectoryFlags>;
|
||||
compileOnSave?: boolean;
|
||||
/* @internal */ configFileSpecs?: ConfigFileSpecs;
|
||||
}
|
||||
|
||||
export const enum WatchDirectoryFlags {
|
||||
@@ -5979,13 +6054,6 @@ namespace ts {
|
||||
validatedFilesSpec: readonly string[] | undefined;
|
||||
validatedIncludeSpecs: readonly string[] | undefined;
|
||||
validatedExcludeSpecs: readonly string[] | undefined;
|
||||
wildcardDirectories: MapLike<WatchDirectoryFlags>;
|
||||
}
|
||||
|
||||
export interface ExpandResult {
|
||||
fileNames: string[];
|
||||
wildcardDirectories: MapLike<WatchDirectoryFlags>;
|
||||
/* @internal */ spec: ConfigFileSpecs;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -7914,8 +7982,6 @@ namespace ts {
|
||||
// Otherwise, returns all the diagnostics (global and file associated) in this collection.
|
||||
getDiagnostics(): Diagnostic[];
|
||||
getDiagnostics(fileName: string): DiagnosticWithLocation[];
|
||||
|
||||
reattachFileDiagnostics(newFile: SourceFile): void;
|
||||
}
|
||||
|
||||
// SyntaxKind.SyntaxList
|
||||
|
||||
+34
-19
@@ -988,10 +988,25 @@ namespace ts {
|
||||
export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain, relatedInformation?: DiagnosticRelatedInformation[]): DiagnosticWithLocation {
|
||||
const sourceFile = getSourceFileOfNode(node);
|
||||
const span = getErrorSpanForNode(sourceFile, node);
|
||||
return createFileDiagnosticFromMessageChain(sourceFile, span.start, span.length, messageChain, relatedInformation);
|
||||
}
|
||||
|
||||
function assertDiagnosticLocation(file: SourceFile | undefined, start: number, length: number) {
|
||||
Debug.assertGreaterThanOrEqual(start, 0);
|
||||
Debug.assertGreaterThanOrEqual(length, 0);
|
||||
|
||||
if (file) {
|
||||
Debug.assertLessThanOrEqual(start, file.text.length);
|
||||
Debug.assertLessThanOrEqual(start + length, file.text.length);
|
||||
}
|
||||
}
|
||||
|
||||
export function createFileDiagnosticFromMessageChain(file: SourceFile, start: number, length: number, messageChain: DiagnosticMessageChain, relatedInformation?: DiagnosticRelatedInformation[]): DiagnosticWithLocation {
|
||||
assertDiagnosticLocation(file, start, length);
|
||||
return {
|
||||
file: sourceFile,
|
||||
start: span.start,
|
||||
length: span.length,
|
||||
file,
|
||||
start,
|
||||
length,
|
||||
code: messageChain.code,
|
||||
category: messageChain.category,
|
||||
messageText: messageChain.next ? messageChain : messageChain.messageText,
|
||||
@@ -1496,6 +1511,13 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
export function getPropertyArrayElementValue(objectLiteral: ObjectLiteralExpression, propKey: string, elementValue: string): StringLiteral | undefined {
|
||||
return firstDefined(getPropertyAssignment(objectLiteral, propKey), property =>
|
||||
isArrayLiteralExpression(property.initializer) ?
|
||||
find(property.initializer.elements, (element): element is StringLiteral => isStringLiteral(element) && element.text === elementValue) :
|
||||
undefined);
|
||||
}
|
||||
|
||||
export function getTsConfigObjectLiteralExpression(tsConfigSourceFile: TsConfigSourceFile | undefined): ObjectLiteralExpression | undefined {
|
||||
if (tsConfigSourceFile && tsConfigSourceFile.statements.length) {
|
||||
const expression = tsConfigSourceFile.statements[0].expression;
|
||||
@@ -3667,13 +3689,8 @@ namespace ts {
|
||||
lookup,
|
||||
getGlobalDiagnostics,
|
||||
getDiagnostics,
|
||||
reattachFileDiagnostics
|
||||
};
|
||||
|
||||
function reattachFileDiagnostics(newFile: SourceFile): void {
|
||||
forEach(fileDiagnostics.get(newFile.fileName), diagnostic => diagnostic.file = newFile);
|
||||
}
|
||||
|
||||
function lookup(diagnostic: Diagnostic): Diagnostic | undefined {
|
||||
let diagnostics: SortedArray<Diagnostic> | undefined;
|
||||
if (diagnostic.file) {
|
||||
@@ -5693,9 +5710,7 @@ namespace ts {
|
||||
|
||||
export function createDetachedDiagnostic(fileName: string, start: number, length: number, message: DiagnosticMessage, ...args: (string | number | undefined)[]): DiagnosticWithDetachedLocation;
|
||||
export function createDetachedDiagnostic(fileName: string, start: number, length: number, message: DiagnosticMessage): DiagnosticWithDetachedLocation {
|
||||
Debug.assertGreaterThanOrEqual(start, 0);
|
||||
Debug.assertGreaterThanOrEqual(length, 0);
|
||||
|
||||
assertDiagnosticLocation(/*file*/ undefined, start, length);
|
||||
let text = getLocaleSpecificMessage(message);
|
||||
|
||||
if (arguments.length > 4) {
|
||||
@@ -5763,13 +5778,7 @@ namespace ts {
|
||||
|
||||
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ...args: (string | number | undefined)[]): DiagnosticWithLocation;
|
||||
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage): DiagnosticWithLocation {
|
||||
Debug.assertGreaterThanOrEqual(start, 0);
|
||||
Debug.assertGreaterThanOrEqual(length, 0);
|
||||
|
||||
if (file) {
|
||||
Debug.assertLessThanOrEqual(start, file.text.length);
|
||||
Debug.assertLessThanOrEqual(start + length, file.text.length);
|
||||
}
|
||||
assertDiagnosticLocation(file, start, length);
|
||||
|
||||
let text = getLocaleSpecificMessage(message);
|
||||
|
||||
@@ -5822,7 +5831,7 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
export function createCompilerDiagnosticFromMessageChain(chain: DiagnosticMessageChain): Diagnostic {
|
||||
export function createCompilerDiagnosticFromMessageChain(chain: DiagnosticMessageChain, relatedInformation?: DiagnosticRelatedInformation[]): Diagnostic {
|
||||
return {
|
||||
file: undefined,
|
||||
start: undefined,
|
||||
@@ -5831,6 +5840,7 @@ namespace ts {
|
||||
code: chain.code,
|
||||
category: chain.category,
|
||||
messageText: chain.next ? chain : chain.messageText,
|
||||
relatedInformation
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6222,6 +6232,11 @@ namespace ts {
|
||||
return !/[.*?]/.test(lastPathComponent);
|
||||
}
|
||||
|
||||
export function getPatternFromSpec(spec: string, basePath: string, usage: "files" | "directories" | "exclude") {
|
||||
const pattern = spec && getSubPatternFromSpec(spec, basePath, usage, wildcardMatchers[usage]);
|
||||
return pattern && `^(${pattern})${usage === "exclude" ? "($|/)" : "$"}`;
|
||||
}
|
||||
|
||||
function getSubPatternFromSpec(spec: string, basePath: string, usage: "files" | "directories" | "exclude", { singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter }: WildcardMatcher): string | undefined {
|
||||
let subpattern = "";
|
||||
let hasWrittenComponent = false;
|
||||
|
||||
+189
-30
@@ -113,38 +113,197 @@ namespace ts {
|
||||
return `${newLine}${flattenDiagnosticMessageText(d.messageText, newLine)}${newLine}${newLine}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Program structure needed to emit the files and report diagnostics
|
||||
*/
|
||||
export interface ProgramToEmitFilesAndReportErrors {
|
||||
getCurrentDirectory(): string;
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
getSourceFiles(): readonly SourceFile[];
|
||||
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
getOptionsDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
getGlobalDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[];
|
||||
getConfigFileParsingDiagnostics(): readonly Diagnostic[];
|
||||
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult;
|
||||
emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult;
|
||||
export function isBuilderProgram<T extends BuilderProgram>(program: Program | T): program is T {
|
||||
return !!(program as T).getState;
|
||||
}
|
||||
|
||||
export function listFiles(program: ProgramToEmitFilesAndReportErrors, writeFileName: (s: string) => void) {
|
||||
if (program.getCompilerOptions().listFiles || program.getCompilerOptions().listFilesOnly) {
|
||||
export function listFiles<T extends BuilderProgram>(program: Program | T, write: (s: string) => void) {
|
||||
const options = program.getCompilerOptions();
|
||||
if (options.explainFiles) {
|
||||
explainFiles(isBuilderProgram(program) ? program.getProgram() : program, write);
|
||||
}
|
||||
else if (options.listFiles || options.listFilesOnly) {
|
||||
forEach(program.getSourceFiles(), file => {
|
||||
writeFileName(file.fileName);
|
||||
write(file.fileName);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function explainFiles(program: Program, write: (s: string) => void) {
|
||||
const reasons = program.getFileIncludeReasons();
|
||||
const getCanonicalFileName = createGetCanonicalFileName(program.useCaseSensitiveFileNames());
|
||||
const relativeFileName = (fileName: string) => convertToRelativePath(fileName, program.getCurrentDirectory(), getCanonicalFileName);
|
||||
for (const file of program.getSourceFiles()) {
|
||||
write(`${toFileName(file, relativeFileName)}`);
|
||||
reasons.get(file.path)?.forEach(reason => write(` ${fileIncludeReasonToDiagnostics(program, reason, relativeFileName).messageText}`));
|
||||
explainIfFileIsRedirect(file, relativeFileName)?.forEach(d => write(` ${d.messageText}`));
|
||||
}
|
||||
}
|
||||
|
||||
export function explainIfFileIsRedirect(file: SourceFile, fileNameConvertor?: (fileName: string) => string): DiagnosticMessageChain[] | undefined {
|
||||
let result: DiagnosticMessageChain[] | undefined;
|
||||
if (file.path !== file.resolvedPath) {
|
||||
(result ||= []).push(chainDiagnosticMessages(
|
||||
/*details*/ undefined,
|
||||
Diagnostics.File_is_output_of_project_reference_source_0,
|
||||
toFileName(file.originalFileName, fileNameConvertor)
|
||||
));
|
||||
}
|
||||
if (file.redirectInfo) {
|
||||
(result ||= []).push(chainDiagnosticMessages(
|
||||
/*details*/ undefined,
|
||||
Diagnostics.File_redirects_to_file_0,
|
||||
toFileName(file.redirectInfo.redirectTarget, fileNameConvertor)
|
||||
));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function getMatchedFileSpec(program: Program, fileName: string) {
|
||||
const configFile = program.getCompilerOptions().configFile;
|
||||
if (!configFile?.configFileSpecs?.validatedFilesSpec) return undefined;
|
||||
|
||||
const getCanonicalFileName = createGetCanonicalFileName(program.useCaseSensitiveFileNames());
|
||||
const filePath = getCanonicalFileName(fileName);
|
||||
const basePath = getDirectoryPath(getNormalizedAbsolutePath(configFile.fileName, program.getCurrentDirectory()));
|
||||
return find(configFile.configFileSpecs.validatedFilesSpec, fileSpec => getCanonicalFileName(getNormalizedAbsolutePath(fileSpec, basePath)) === filePath);
|
||||
}
|
||||
|
||||
export function getMatchedIncludeSpec(program: Program, fileName: string) {
|
||||
const configFile = program.getCompilerOptions().configFile;
|
||||
if (!configFile?.configFileSpecs?.validatedIncludeSpecs) return undefined;
|
||||
|
||||
const isJsonFile = fileExtensionIs(fileName, Extension.Json);
|
||||
const basePath = getDirectoryPath(getNormalizedAbsolutePath(configFile.fileName, program.getCurrentDirectory()));
|
||||
const useCaseSensitiveFileNames = program.useCaseSensitiveFileNames();
|
||||
return find(configFile?.configFileSpecs?.validatedIncludeSpecs, includeSpec => {
|
||||
if (isJsonFile && !endsWith(includeSpec, Extension.Json)) return false;
|
||||
const pattern = getPatternFromSpec(includeSpec, basePath, "files");
|
||||
return !!pattern && getRegexFromPattern(`(${pattern})$`, useCaseSensitiveFileNames).test(fileName);
|
||||
});
|
||||
}
|
||||
|
||||
export function fileIncludeReasonToDiagnostics(program: Program, reason: FileIncludeReason, fileNameConvertor?: (fileName: string) => string,): DiagnosticMessageChain {
|
||||
const options = program.getCompilerOptions();
|
||||
if (isReferencedFile(reason)) {
|
||||
const referenceLocation = getReferencedFileLocation(path => program.getSourceFileByPath(path), reason);
|
||||
const referenceText = isReferenceFileLocation(referenceLocation) ? referenceLocation.file.text.substring(referenceLocation.pos, referenceLocation.end) : `"${referenceLocation.text}"`;
|
||||
let message: DiagnosticMessage;
|
||||
Debug.assert(isReferenceFileLocation(referenceLocation) || reason.kind === FileIncludeKind.Import, "Only synthetic references are imports");
|
||||
switch (reason.kind) {
|
||||
case FileIncludeKind.Import:
|
||||
if (isReferenceFileLocation(referenceLocation)) {
|
||||
message = referenceLocation.packageId ?
|
||||
Diagnostics.Imported_via_0_from_file_1_with_packageId_2 :
|
||||
Diagnostics.Imported_via_0_from_file_1;
|
||||
}
|
||||
else if (referenceLocation.text === externalHelpersModuleNameText) {
|
||||
message = referenceLocation.packageId ?
|
||||
Diagnostics.Imported_via_0_from_file_1_with_packageId_2_to_import_importHelpers_as_specified_in_compilerOptions :
|
||||
Diagnostics.Imported_via_0_from_file_1_to_import_importHelpers_as_specified_in_compilerOptions;
|
||||
}
|
||||
else {
|
||||
message = referenceLocation.packageId ?
|
||||
Diagnostics.Imported_via_0_from_file_1_with_packageId_2_to_import_jsx_and_jsxs_factory_functions :
|
||||
Diagnostics.Imported_via_0_from_file_1_to_import_jsx_and_jsxs_factory_functions;
|
||||
}
|
||||
break;
|
||||
case FileIncludeKind.ReferenceFile:
|
||||
Debug.assert(!referenceLocation.packageId);
|
||||
message = Diagnostics.Referenced_via_0_from_file_1;
|
||||
break;
|
||||
case FileIncludeKind.TypeReferenceDirective:
|
||||
message = referenceLocation.packageId ?
|
||||
Diagnostics.Type_library_referenced_via_0_from_file_1_with_packageId_2 :
|
||||
Diagnostics.Type_library_referenced_via_0_from_file_1;
|
||||
break;
|
||||
case FileIncludeKind.LibReferenceDirective:
|
||||
Debug.assert(!referenceLocation.packageId);
|
||||
message = Diagnostics.Library_referenced_via_0_from_file_1;
|
||||
break;
|
||||
default:
|
||||
Debug.assertNever(reason);
|
||||
}
|
||||
return chainDiagnosticMessages(
|
||||
/*details*/ undefined,
|
||||
message,
|
||||
referenceText,
|
||||
toFileName(referenceLocation.file, fileNameConvertor),
|
||||
referenceLocation.packageId && packageIdToString(referenceLocation.packageId)
|
||||
);
|
||||
}
|
||||
switch (reason.kind) {
|
||||
case FileIncludeKind.RootFile:
|
||||
if (!options.configFile?.configFileSpecs) return chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Root_file_specified_for_compilation);
|
||||
const fileName = getNormalizedAbsolutePath(program.getRootFileNames()[reason.index], program.getCurrentDirectory());
|
||||
const matchedByFiles = getMatchedFileSpec(program, fileName);
|
||||
if (matchedByFiles) return chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Part_of_files_list_in_tsconfig_json);
|
||||
const matchedByInclude = getMatchedIncludeSpec(program, fileName);
|
||||
return matchedByInclude ?
|
||||
chainDiagnosticMessages(
|
||||
/*details*/ undefined,
|
||||
Diagnostics.Matched_by_include_pattern_0_in_1,
|
||||
matchedByInclude,
|
||||
toFileName(options.configFile, fileNameConvertor)
|
||||
) :
|
||||
// Could be additional files specified as roots
|
||||
chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Root_file_specified_for_compilation);
|
||||
case FileIncludeKind.SourceFromProjectReference:
|
||||
case FileIncludeKind.OutputFromProjectReference:
|
||||
const isOutput = reason.kind === FileIncludeKind.OutputFromProjectReference;
|
||||
const referencedResolvedRef = Debug.checkDefined(program.getResolvedProjectReferences()?.[reason.index]);
|
||||
return chainDiagnosticMessages(
|
||||
/*details*/ undefined,
|
||||
outFile(options) ?
|
||||
isOutput ?
|
||||
Diagnostics.Output_from_referenced_project_0_included_because_1_specified :
|
||||
Diagnostics.Source_from_referenced_project_0_included_because_1_specified :
|
||||
isOutput ?
|
||||
Diagnostics.Output_from_referenced_project_0_included_because_module_is_specified_as_none :
|
||||
Diagnostics.Source_from_referenced_project_0_included_because_module_is_specified_as_none,
|
||||
toFileName(referencedResolvedRef.sourceFile.fileName, fileNameConvertor),
|
||||
options.outFile ? "--outFile" : "--out",
|
||||
);
|
||||
case FileIncludeKind.AutomaticTypeDirectiveFile:
|
||||
return chainDiagnosticMessages(
|
||||
/*details*/ undefined,
|
||||
options.types ?
|
||||
reason.packageId ?
|
||||
Diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions_with_packageId_1 :
|
||||
Diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions :
|
||||
reason.packageId ?
|
||||
Diagnostics.Entry_point_for_implicit_type_library_0_with_packageId_1 :
|
||||
Diagnostics.Entry_point_for_implicit_type_library_0,
|
||||
reason.typeReference,
|
||||
reason.packageId && packageIdToString(reason.packageId),
|
||||
);
|
||||
case FileIncludeKind.LibFile:
|
||||
if (reason.index !== undefined) return chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Library_0_specified_in_compilerOptions, options.lib![reason.index]);
|
||||
const target = forEachEntry(targetOptionDeclaration.type, (value, key) => value === options.target ? key : undefined);
|
||||
return chainDiagnosticMessages(
|
||||
/*details*/ undefined,
|
||||
target ?
|
||||
Diagnostics.Default_library_for_target_0 :
|
||||
Diagnostics.Default_library,
|
||||
target,
|
||||
);
|
||||
default:
|
||||
Debug.assertNever(reason);
|
||||
}
|
||||
}
|
||||
|
||||
function toFileName(file: SourceFile | string, fileNameConvertor?: (fileName: string) => string) {
|
||||
const fileName = isString(file) ? file : file.fileName;
|
||||
return fileNameConvertor ? fileNameConvertor(fileName) : fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options
|
||||
*/
|
||||
export function emitFilesAndReportErrors(
|
||||
program: ProgramToEmitFilesAndReportErrors,
|
||||
export function emitFilesAndReportErrors<T extends BuilderProgram>(
|
||||
program: Program | T,
|
||||
reportDiagnostic: DiagnosticReporter,
|
||||
writeFileName?: (s: string) => void,
|
||||
write?: (s: string) => void,
|
||||
reportSummary?: ReportEmitErrorSummary,
|
||||
writeFile?: WriteFileCallback,
|
||||
cancellationToken?: CancellationToken,
|
||||
@@ -181,13 +340,13 @@ namespace ts {
|
||||
|
||||
const diagnostics = sortAndDeduplicateDiagnostics(allDiagnostics);
|
||||
diagnostics.forEach(reportDiagnostic);
|
||||
if (writeFileName) {
|
||||
if (write) {
|
||||
const currentDir = program.getCurrentDirectory();
|
||||
forEach(emittedFiles, file => {
|
||||
const filepath = getNormalizedAbsolutePath(file, currentDir);
|
||||
writeFileName(`TSFILE: ${filepath}`);
|
||||
write(`TSFILE: ${filepath}`);
|
||||
});
|
||||
listFiles(program, writeFileName);
|
||||
listFiles(program, write);
|
||||
}
|
||||
|
||||
if (reportSummary) {
|
||||
@@ -200,10 +359,10 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
export function emitFilesAndReportErrorsAndGetExitStatus(
|
||||
program: ProgramToEmitFilesAndReportErrors,
|
||||
export function emitFilesAndReportErrorsAndGetExitStatus<T extends BuilderProgram>(
|
||||
program: Program | T,
|
||||
reportDiagnostic: DiagnosticReporter,
|
||||
writeFileName?: (s: string) => void,
|
||||
write?: (s: string) => void,
|
||||
reportSummary?: ReportEmitErrorSummary,
|
||||
writeFile?: WriteFileCallback,
|
||||
cancellationToken?: CancellationToken,
|
||||
@@ -213,7 +372,7 @@ namespace ts {
|
||||
const { emitResult, diagnostics } = emitFilesAndReportErrors(
|
||||
program,
|
||||
reportDiagnostic,
|
||||
writeFileName,
|
||||
write,
|
||||
reportSummary,
|
||||
writeFile,
|
||||
cancellationToken,
|
||||
@@ -385,7 +544,7 @@ namespace ts {
|
||||
* Creates the watch compiler host that can be extended with config file or root file names and options host
|
||||
*/
|
||||
function createWatchCompilerHost<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>(system = sys, createProgram: CreateProgram<T> | undefined, reportDiagnostic: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHost<T> {
|
||||
const writeFileName = (s: string) => system.write(s + system.newLine);
|
||||
const write = (s: string) => system.write(s + system.newLine);
|
||||
const result = createProgramHost(system, createProgram) as WatchCompilerHost<T>;
|
||||
copyProperties(result, createWatchHost(system, reportWatchStatus));
|
||||
result.afterProgramCreate = builderProgram => {
|
||||
@@ -395,7 +554,7 @@ namespace ts {
|
||||
emitFilesAndReportErrors(
|
||||
builderProgram,
|
||||
reportDiagnostic,
|
||||
writeFileName,
|
||||
write,
|
||||
errorCount => result.onWatchStatusChange!(
|
||||
createCompilerDiagnostic(getWatchErrorSummaryDiagnosticMessage(errorCount), errorCount),
|
||||
newLine,
|
||||
|
||||
@@ -260,7 +260,7 @@ namespace ts {
|
||||
const currentDirectory = host.getCurrentDirectory();
|
||||
const { configFileName, optionsToExtend: optionsToExtendForConfigFile = {}, watchOptionsToExtend, extraFileExtensions, createProgram } = host;
|
||||
let { rootFiles: rootFileNames, options: compilerOptions, watchOptions, projectReferences } = host;
|
||||
let configFileSpecs: ConfigFileSpecs;
|
||||
let wildcardDirectories: MapLike<WatchDirectoryFlags> | undefined;
|
||||
let configFileParsingDiagnostics: Diagnostic[] | undefined;
|
||||
let canConfigFileJsonReportNoInputFiles = false;
|
||||
let hasChangedConfigFileParsingErrors = false;
|
||||
@@ -635,11 +635,10 @@ namespace ts {
|
||||
|
||||
function reloadFileNamesFromConfigFile() {
|
||||
writeLog("Reloading new file names and options");
|
||||
const result = getFileNamesFromConfigSpecs(configFileSpecs, getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), compilerOptions, parseConfigFileHost, extraFileExtensions);
|
||||
if (updateErrorForNoInputFiles(result, getNormalizedAbsolutePath(configFileName, currentDirectory), configFileSpecs, configFileParsingDiagnostics!, canConfigFileJsonReportNoInputFiles)) {
|
||||
rootFileNames = getFileNamesFromConfigSpecs(compilerOptions.configFile!.configFileSpecs!, getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), compilerOptions, parseConfigFileHost, extraFileExtensions);
|
||||
if (updateErrorForNoInputFiles(rootFileNames, getNormalizedAbsolutePath(configFileName, currentDirectory), compilerOptions.configFile!.configFileSpecs!, configFileParsingDiagnostics!, canConfigFileJsonReportNoInputFiles)) {
|
||||
hasChangedConfigFileParsingErrors = true;
|
||||
}
|
||||
rootFileNames = result.fileNames;
|
||||
|
||||
// Update the program
|
||||
synchronizeProgram();
|
||||
@@ -668,8 +667,8 @@ namespace ts {
|
||||
rootFileNames = configFileParseResult.fileNames;
|
||||
compilerOptions = configFileParseResult.options;
|
||||
watchOptions = configFileParseResult.watchOptions;
|
||||
configFileSpecs = configFileParseResult.configFileSpecs!; // TODO: GH#18217
|
||||
projectReferences = configFileParseResult.projectReferences;
|
||||
wildcardDirectories = configFileParseResult.wildcardDirectories;
|
||||
configFileParsingDiagnostics = getConfigFileParsingDiagnostics(configFileParseResult).slice();
|
||||
canConfigFileJsonReportNoInputFiles = canJsonReportNoInputFiles(configFileParseResult.raw);
|
||||
hasChangedConfigFileParsingErrors = true;
|
||||
@@ -726,10 +725,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function watchConfigFileWildCardDirectories() {
|
||||
if (configFileSpecs) {
|
||||
if (wildcardDirectories) {
|
||||
updateWatchingWildcardDirectories(
|
||||
watchedWildcardDirectories || (watchedWildcardDirectories = new Map()),
|
||||
new Map(getEntries(configFileSpecs.wildcardDirectories)),
|
||||
new Map(getEntries(wildcardDirectories)),
|
||||
watchWildcardDirectory
|
||||
);
|
||||
}
|
||||
@@ -757,7 +756,6 @@ namespace ts {
|
||||
fileOrDirectory,
|
||||
fileOrDirectoryPath,
|
||||
configFileName,
|
||||
configFileSpecs,
|
||||
extraFileExtensions,
|
||||
options: compilerOptions,
|
||||
program: getCurrentBuilderProgram(),
|
||||
|
||||
@@ -336,7 +336,6 @@ namespace ts {
|
||||
fileOrDirectoryPath: Path;
|
||||
configFileName: string;
|
||||
options: CompilerOptions;
|
||||
configFileSpecs: ConfigFileSpecs;
|
||||
program: BuilderProgram | Program | undefined;
|
||||
extraFileExtensions?: readonly FileExtensionInfo[];
|
||||
currentDirectory: string;
|
||||
@@ -346,7 +345,7 @@ namespace ts {
|
||||
/* @internal */
|
||||
export function isIgnoredFileFromWildCardWatching({
|
||||
watchedDirPath, fileOrDirectory, fileOrDirectoryPath,
|
||||
configFileName, options, configFileSpecs, program, extraFileExtensions,
|
||||
configFileName, options, program, extraFileExtensions,
|
||||
currentDirectory, useCaseSensitiveFileNames,
|
||||
writeLog,
|
||||
}: IsIgnoredFileFromWildCardWatchingInput): boolean {
|
||||
@@ -366,7 +365,7 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isExcludedFile(fileOrDirectory, configFileSpecs, getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), useCaseSensitiveFileNames, currentDirectory)) {
|
||||
if (isExcludedFile(fileOrDirectory, options.configFile!.configFileSpecs!, getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), useCaseSensitiveFileNames, currentDirectory)) {
|
||||
writeLog(`Project: ${configFileName} Detected excluded file: ${fileOrDirectory}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -271,6 +271,7 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
let configParseResult: ts.ParsedCommandLine | undefined;
|
||||
if (configFileName) {
|
||||
const baseDir = ts.normalizePath(ts.getDirectoryPath(configFileName));
|
||||
const files: vfs.FileSet = { [baseDir]: {} };
|
||||
@@ -281,7 +282,8 @@ namespace FourSlash {
|
||||
const fs = new vfs.FileSystem(/*ignoreCase*/ true, { cwd: baseDir, files });
|
||||
const host = new fakes.ParseConfigHost(fs);
|
||||
const jsonSourceFile = ts.parseJsonText(configFileName, this.inputFiles.get(configFileName)!);
|
||||
compilationOptions = ts.parseJsonSourceFileConfigFileContent(jsonSourceFile, host, baseDir, compilationOptions, configFileName).options;
|
||||
configParseResult = ts.parseJsonSourceFileConfigFileContent(jsonSourceFile, host, baseDir, compilationOptions, configFileName);
|
||||
compilationOptions = configParseResult.options;
|
||||
}
|
||||
|
||||
if (compilationOptions.typeRoots) {
|
||||
@@ -336,7 +338,11 @@ namespace FourSlash {
|
||||
// resolveReference file-option is not specified then do not resolve any files and include all inputFiles
|
||||
this.inputFiles.forEach((file, fileName) => {
|
||||
if (!Harness.isDefaultLibraryFile(fileName)) {
|
||||
this.languageServiceAdapterHost.addScript(fileName, file, /*isRootFile*/ true);
|
||||
// all files if config file not specified, otherwise root files from the config and typings cache files are root files
|
||||
const isRootFile = !configParseResult ||
|
||||
ts.contains(configParseResult.fileNames, fileName) ||
|
||||
(ts.isDeclarationFileName(fileName) && ts.containsPath("/Library/Caches/typescript", fileName));
|
||||
this.languageServiceAdapterHost.addScript(fileName, file, isRootFile);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1012,6 +1012,10 @@ interface Array<T> { length: number; [n: number]: T; }`
|
||||
}
|
||||
}
|
||||
|
||||
prependFile(path: string, content: string, options?: Partial<ReloadWatchInvokeOptions>): void {
|
||||
this.modifyFile(path, content + this.readFile(path), options);
|
||||
}
|
||||
|
||||
appendFile(path: string, content: string, options?: Partial<ReloadWatchInvokeOptions>): void {
|
||||
this.modifyFile(path, this.readFile(path) + content, options);
|
||||
}
|
||||
|
||||
@@ -1279,7 +1279,6 @@ namespace ts.server {
|
||||
fileOrDirectory,
|
||||
fileOrDirectoryPath,
|
||||
configFileName,
|
||||
configFileSpecs: project.configFileSpecs!,
|
||||
extraFileExtensions: this.hostConfiguration.extraFileExtensions,
|
||||
currentDirectory: this.currentDirectory,
|
||||
options: project.getCompilationSettings(),
|
||||
@@ -2128,7 +2127,6 @@ namespace ts.server {
|
||||
configHasExcludeProperty: parsedCommandLine.raw.exclude !== undefined
|
||||
};
|
||||
}
|
||||
project.configFileSpecs = parsedCommandLine.configFileSpecs;
|
||||
project.canConfigFileJsonReportNoInputFiles = canJsonReportNoInputFiles(parsedCommandLine.raw);
|
||||
project.setProjectErrors(configFileErrors);
|
||||
project.updateReferences(parsedCommandLine.projectReferences);
|
||||
@@ -2237,11 +2235,11 @@ namespace ts.server {
|
||||
*/
|
||||
/*@internal*/
|
||||
reloadFileNamesOfConfiguredProject(project: ConfiguredProject) {
|
||||
const configFileSpecs = project.configFileSpecs!; // TODO: GH#18217
|
||||
const configFileSpecs = project.getCompilerOptions().configFile!.configFileSpecs!;
|
||||
const configFileName = project.getConfigFilePath();
|
||||
const fileNamesResult = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFileName), project.getCompilationSettings(), project.getCachedDirectoryStructureHost(), this.hostConfiguration.extraFileExtensions);
|
||||
project.updateErrorOnNoInputFiles(fileNamesResult);
|
||||
this.updateNonInferredProjectFiles(project, fileNamesResult.fileNames.concat(project.getExternalFiles()), fileNamePropertyReader);
|
||||
const fileNames = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFileName), project.getCompilationSettings(), project.getCachedDirectoryStructureHost(), this.hostConfiguration.extraFileExtensions);
|
||||
project.updateErrorOnNoInputFiles(fileNames);
|
||||
this.updateNonInferredProjectFiles(project, fileNames.concat(project.getExternalFiles()), fileNamePropertyReader);
|
||||
return project.updateGraph();
|
||||
}
|
||||
|
||||
|
||||
@@ -1375,6 +1375,8 @@ namespace ts.server {
|
||||
for (const file of sourceFiles) {
|
||||
strBuilder += `\t${file.fileName}\n`;
|
||||
}
|
||||
strBuilder += "\n\n";
|
||||
explainFiles(this.program, s => strBuilder += `\t${s}\n`);
|
||||
}
|
||||
return strBuilder;
|
||||
}
|
||||
@@ -2066,9 +2068,6 @@ namespace ts.server {
|
||||
/* @internal */
|
||||
openFileWatchTriggered = new Map<string, true>();
|
||||
|
||||
/*@internal*/
|
||||
configFileSpecs: ConfigFileSpecs | undefined;
|
||||
|
||||
/*@internal*/
|
||||
canConfigFileJsonReportNoInputFiles = false;
|
||||
|
||||
@@ -2293,7 +2292,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
this.stopWatchingWildCards();
|
||||
this.configFileSpecs = undefined;
|
||||
this.projectErrors = undefined;
|
||||
this.openFileWatchTriggered.clear();
|
||||
this.compilerHost = undefined;
|
||||
super.close();
|
||||
@@ -2376,8 +2375,8 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
updateErrorOnNoInputFiles(fileNameResult: ExpandResult) {
|
||||
updateErrorForNoInputFiles(fileNameResult, this.getConfigFilePath(), this.configFileSpecs!, this.projectErrors!, this.canConfigFileJsonReportNoInputFiles);
|
||||
updateErrorOnNoInputFiles(fileNames: string[]) {
|
||||
updateErrorForNoInputFiles(fileNames, this.getConfigFilePath(), this.getCompilerOptions().configFile!.configFileSpecs!, this.projectErrors!, this.canConfigFileJsonReportNoInputFiles);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -611,12 +611,22 @@ export = C;
|
||||
"c.ts",
|
||||
`/// <reference path="D.ts"/>`.indexOf(`D.ts`),
|
||||
"D.ts".length,
|
||||
Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
"D.ts",
|
||||
"d.ts",
|
||||
tscWatch.getDiagnosticMessageChain(
|
||||
Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
["D.ts", "d.ts"],
|
||||
[
|
||||
tscWatch.getDiagnosticMessageChain(
|
||||
Diagnostics.The_file_is_in_the_program_because_Colon,
|
||||
emptyArray,
|
||||
[
|
||||
tscWatch.getDiagnosticMessageChain(Diagnostics.Referenced_via_0_from_file_1, ["D.ts", "c.ts"]),
|
||||
tscWatch.getDiagnosticMessageChain(Diagnostics.Root_file_specified_for_compilation)
|
||||
]
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
reportsUnnecessary: undefined,
|
||||
reportsDeprecated: undefined
|
||||
relatedInformation: undefined,
|
||||
}]
|
||||
);
|
||||
});
|
||||
@@ -638,12 +648,22 @@ export = C;
|
||||
"c.ts",
|
||||
`import {x} from "D"`.indexOf(`"D"`),
|
||||
`"D"`.length,
|
||||
Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
"/a/b/D.ts",
|
||||
"d.ts",
|
||||
tscWatch.getDiagnosticMessageChain(
|
||||
Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
["/a/b/D.ts", "d.ts"],
|
||||
[
|
||||
tscWatch.getDiagnosticMessageChain(
|
||||
Diagnostics.The_file_is_in_the_program_because_Colon,
|
||||
emptyArray,
|
||||
[
|
||||
tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [`"D"`, "c.ts"]),
|
||||
tscWatch.getDiagnosticMessageChain(Diagnostics.Root_file_specified_for_compilation)
|
||||
]
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
reportsUnnecessary: undefined,
|
||||
reportsDeprecated: undefined
|
||||
relatedInformation: undefined,
|
||||
}]
|
||||
);
|
||||
});
|
||||
@@ -665,12 +685,22 @@ export = C;
|
||||
"moduleA.ts",
|
||||
`import {x} from "./ModuleB"`.indexOf(`"./ModuleB"`),
|
||||
`"./ModuleB"`.length,
|
||||
Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
"ModuleB.ts",
|
||||
"moduleB.ts",
|
||||
tscWatch.getDiagnosticMessageChain(
|
||||
Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
["ModuleB.ts", "moduleB.ts"],
|
||||
[
|
||||
tscWatch.getDiagnosticMessageChain(
|
||||
Diagnostics.The_file_is_in_the_program_because_Colon,
|
||||
emptyArray,
|
||||
[
|
||||
tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [`"./ModuleB"`, "moduleA.ts"]),
|
||||
tscWatch.getDiagnosticMessageChain(Diagnostics.Root_file_specified_for_compilation)
|
||||
]
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
reportsUnnecessary: undefined,
|
||||
reportsDeprecated: undefined
|
||||
relatedInformation: undefined
|
||||
}]
|
||||
);
|
||||
});
|
||||
@@ -693,12 +723,22 @@ export = C;
|
||||
"c.ts",
|
||||
`import {x} from "D"`.indexOf(`"D"`),
|
||||
`"D"`.length,
|
||||
Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
"/a/b/D.ts",
|
||||
"d.ts",
|
||||
tscWatch.getDiagnosticMessageChain(
|
||||
Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
["/a/b/D.ts", "d.ts"],
|
||||
[
|
||||
tscWatch.getDiagnosticMessageChain(
|
||||
Diagnostics.The_file_is_in_the_program_because_Colon,
|
||||
emptyArray,
|
||||
[
|
||||
tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [`"D"`, "c.ts"]),
|
||||
tscWatch.getDiagnosticMessageChain(Diagnostics.Root_file_specified_for_compilation)
|
||||
]
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
reportsUnnecessary: undefined,
|
||||
reportsDeprecated: undefined
|
||||
relatedInformation: undefined
|
||||
}]
|
||||
);
|
||||
});
|
||||
@@ -715,34 +755,65 @@ export = C;
|
||||
"",
|
||||
/*useCaseSensitiveFileNames*/ false,
|
||||
["moduleA.ts", "moduleB.ts", "moduleC.ts"],
|
||||
program => [
|
||||
{
|
||||
program => {
|
||||
const importInA = {
|
||||
...tscWatch.getDiagnosticOfFileFromProgram(
|
||||
program,
|
||||
"moduleA.ts",
|
||||
`import a = require("./ModuleC")`.indexOf(`"./ModuleC"`),
|
||||
`"./ModuleC"`.length,
|
||||
Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
"ModuleC.ts",
|
||||
"moduleC.ts",
|
||||
Diagnostics.File_is_included_via_import_here,
|
||||
),
|
||||
reportsUnnecessary: undefined,
|
||||
reportsDeprecated: undefined
|
||||
},
|
||||
{
|
||||
};
|
||||
const importInB = {
|
||||
...tscWatch.getDiagnosticOfFileFromProgram(
|
||||
program,
|
||||
"moduleB.ts",
|
||||
`import a = require("./moduleC")`.indexOf(`"./moduleC"`),
|
||||
`"./moduleC"`.length,
|
||||
Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing,
|
||||
"moduleC.ts",
|
||||
"ModuleC.ts"
|
||||
Diagnostics.File_is_included_via_import_here,
|
||||
),
|
||||
reportsUnnecessary: undefined,
|
||||
reportsDeprecated: undefined
|
||||
}
|
||||
]
|
||||
};
|
||||
const importHereInA = tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [`"./ModuleC"`, "moduleA.ts"]);
|
||||
const importHereInB = tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [`"./moduleC"`, "moduleB.ts"]);
|
||||
const details = [tscWatch.getDiagnosticMessageChain(
|
||||
Diagnostics.The_file_is_in_the_program_because_Colon,
|
||||
emptyArray,
|
||||
[importHereInA, importHereInB, tscWatch.getDiagnosticMessageChain(Diagnostics.Root_file_specified_for_compilation)]
|
||||
)];
|
||||
return [
|
||||
{
|
||||
...tscWatch.getDiagnosticOfFileFrom(
|
||||
importInA.file,
|
||||
importInA.start,
|
||||
importInA.length,
|
||||
tscWatch.getDiagnosticMessageChain(
|
||||
Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
["ModuleC.ts", "moduleC.ts" ],
|
||||
details,
|
||||
)
|
||||
),
|
||||
relatedInformation: [importInB]
|
||||
},
|
||||
{
|
||||
...tscWatch.getDiagnosticOfFileFrom(
|
||||
importInB.file,
|
||||
importInB.start,
|
||||
importInB.length,
|
||||
tscWatch.getDiagnosticMessageChain(
|
||||
Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing,
|
||||
["moduleC.ts", "ModuleC.ts"],
|
||||
details,
|
||||
)
|
||||
),
|
||||
relatedInformation: [importInA]
|
||||
}
|
||||
];
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -768,12 +839,34 @@ import b = require("./moduleB");
|
||||
"moduleB.ts",
|
||||
`import a = require("./moduleC")`.indexOf(`"./moduleC"`),
|
||||
`"./moduleC"`.length,
|
||||
Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing,
|
||||
"/a/B/c/moduleC.ts",
|
||||
"/a/B/c/ModuleC.ts"
|
||||
tscWatch.getDiagnosticMessageChain(
|
||||
Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing,
|
||||
["/a/B/c/moduleC.ts", "/a/B/c/ModuleC.ts"],
|
||||
[
|
||||
tscWatch.getDiagnosticMessageChain(
|
||||
Diagnostics.The_file_is_in_the_program_because_Colon,
|
||||
emptyArray,
|
||||
[
|
||||
tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [`"./ModuleC"`, "/a/B/c/moduleA.ts"]),
|
||||
tscWatch.getDiagnosticMessageChain(Diagnostics.Imported_via_0_from_file_1, [`"./moduleC"`, "/a/B/c/moduleB.ts"])
|
||||
]
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
reportsUnnecessary: undefined,
|
||||
reportsDeprecated: undefined
|
||||
relatedInformation: [
|
||||
{
|
||||
...tscWatch.getDiagnosticOfFileFromProgram(
|
||||
program,
|
||||
"moduleA.ts",
|
||||
`import a = require("./ModuleC")`.indexOf(`"./ModuleC"`),
|
||||
`"./ModuleC"`.length,
|
||||
Diagnostics.File_is_included_via_import_here,
|
||||
),
|
||||
reportsUnnecessary: undefined,
|
||||
reportsDeprecated: undefined
|
||||
}
|
||||
]
|
||||
}]
|
||||
);
|
||||
});
|
||||
@@ -1384,14 +1477,14 @@ import b = require("./moduleB");
|
||||
},
|
||||
};
|
||||
const program1 = createProgram(names, {}, compilerHost);
|
||||
const diagnostics1 = program1.getFileProcessingDiagnostics().getDiagnostics();
|
||||
const diagnostics1 = program1.getOptionsDiagnostics();
|
||||
assert.equal(diagnostics1.length, 1, "expected one diagnostic");
|
||||
|
||||
const program2 = createProgram(names, {}, compilerHost, program1);
|
||||
assert.isTrue(program2.structureIsReused === StructureIsReused.Completely);
|
||||
const diagnostics2 = program1.getFileProcessingDiagnostics().getDiagnostics();
|
||||
const diagnostics2 = program2.getOptionsDiagnostics();
|
||||
assert.equal(diagnostics2.length, 1, "expected one diagnostic");
|
||||
assert.equal(diagnostics1[0].messageText, diagnostics2[0].messageText, "expected one diagnostic");
|
||||
assert.deepEqual(diagnostics1[0].messageText, diagnostics2[0].messageText, "expected one diagnostic");
|
||||
});
|
||||
|
||||
it("Modules in the same .d.ts file are preferred to external files", () => {
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace ts {
|
||||
const program = createProgram(["test.ts"], { module: ModuleKind.ES2015 }, host);
|
||||
assert(program.getSourceFiles().length === 1, "expected 'getSourceFiles' length to be 1");
|
||||
assert(program.getMissingFilePaths().length === 0, "expected 'getMissingFilePaths' length to be 0");
|
||||
assert(program.getFileProcessingDiagnostics().getDiagnostics().length === 0, "expected 'getFileProcessingDiagnostics' length to be 0");
|
||||
assert((program.getFileProcessingDiagnostics()?.length || 0) === 0, "expected 'getFileProcessingDiagnostics' length to be 0");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@ namespace ts {
|
||||
ignoreDtsChanged?: true;
|
||||
ignoreDtsUnchanged?: true;
|
||||
baselineOnly?: true;
|
||||
additionalCommandLineArgs?: string[];
|
||||
}
|
||||
|
||||
function verifyOutFileScenario({
|
||||
@@ -92,7 +93,8 @@ namespace ts {
|
||||
modifyAgainFs,
|
||||
ignoreDtsChanged,
|
||||
ignoreDtsUnchanged,
|
||||
baselineOnly
|
||||
baselineOnly,
|
||||
additionalCommandLineArgs,
|
||||
}: VerifyOutFileScenarioInput) {
|
||||
const incrementalScenarios: TscIncremental[] = [];
|
||||
if (!ignoreDtsChanged) {
|
||||
@@ -117,7 +119,7 @@ namespace ts {
|
||||
subScenario,
|
||||
fs: () => outFileFs,
|
||||
scenario: "outfile-concat",
|
||||
commandLineArgs: ["--b", "/src/third", "--verbose"],
|
||||
commandLineArgs: ["--b", "/src/third", "--verbose", ...(additionalCommandLineArgs || [])],
|
||||
baselineSourceMap: true,
|
||||
modifyFs,
|
||||
baselineReadFileCalls: !baselineOnly,
|
||||
@@ -133,6 +135,12 @@ namespace ts {
|
||||
subScenario: "baseline sectioned sourcemaps",
|
||||
});
|
||||
|
||||
verifyOutFileScenario({
|
||||
subScenario: "explainFiles",
|
||||
additionalCommandLineArgs: ["--explainFiles"],
|
||||
baselineOnly: true
|
||||
});
|
||||
|
||||
// Verify baseline with build info + dts unChanged
|
||||
verifyOutFileScenario({
|
||||
subScenario: "when final project is not composite but uses project references",
|
||||
|
||||
@@ -13,21 +13,21 @@ namespace ts {
|
||||
scenario: "resolveJsonModule",
|
||||
subScenario: "include only",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig_withInclude.json"],
|
||||
commandLineArgs: ["--b", "/src/tsconfig_withInclude.json", "--v", "--explainFiles"],
|
||||
});
|
||||
|
||||
verifyTsc({
|
||||
scenario: "resolveJsonModule",
|
||||
subScenario: "include of json along with other include",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig_withIncludeOfJson.json"],
|
||||
commandLineArgs: ["--b", "/src/tsconfig_withIncludeOfJson.json", "--v", "--explainFiles"],
|
||||
});
|
||||
|
||||
verifyTsc({
|
||||
scenario: "resolveJsonModule",
|
||||
subScenario: "include of json along with other include and file name matches ts file",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig_withIncludeOfJson.json"],
|
||||
commandLineArgs: ["--b", "/src/tsconfig_withIncludeOfJson.json", "--v", "--explainFiles"],
|
||||
modifyFs: fs => {
|
||||
fs.rimrafSync("/src/src/hello.json");
|
||||
fs.writeFileSync("/src/src/index.json", JSON.stringify({ hello: "world" }));
|
||||
@@ -41,21 +41,21 @@ export default hello.hello`);
|
||||
scenario: "resolveJsonModule",
|
||||
subScenario: "files containing json file",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig_withFiles.json"],
|
||||
commandLineArgs: ["--b", "/src/tsconfig_withFiles.json", "--v", "--explainFiles"],
|
||||
});
|
||||
|
||||
verifyTsc({
|
||||
scenario: "resolveJsonModule",
|
||||
subScenario: "include and files",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig_withIncludeAndFiles.json"],
|
||||
commandLineArgs: ["--b", "/src/tsconfig_withIncludeAndFiles.json", "--v", "--explainFiles"],
|
||||
});
|
||||
|
||||
verifyTscSerializedIncrementalEdits({
|
||||
scenario: "resolveJsonModule",
|
||||
subScenario: "sourcemap",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "src/tsconfig_withFiles.json", "--verbose"],
|
||||
commandLineArgs: ["--b", "src/tsconfig_withFiles.json", "--verbose", "--explainFiles"],
|
||||
modifyFs: fs => replaceText(fs, "src/tsconfig_withFiles.json", `"composite": true,`, `"composite": true, "sourceMap": true,`),
|
||||
incrementalScenarios: noChangeOnlyRuns
|
||||
});
|
||||
@@ -75,7 +75,7 @@ export default hello.hello`);
|
||||
scenario: "resolveJsonModule",
|
||||
subScenario: "importing json module from project reference",
|
||||
fs: () => loadProjectFromDisk("tests/projects/importJsonFromProjectReference"),
|
||||
commandLineArgs: ["--b", "src/tsconfig.json", "--verbose"],
|
||||
commandLineArgs: ["--b", "src/tsconfig.json", "--verbose", "--explainFiles"],
|
||||
incrementalScenarios: noChangeOnlyRuns
|
||||
});
|
||||
});
|
||||
|
||||
@@ -386,6 +386,13 @@ class someClass2 { }`),
|
||||
commandLineArgs: ["--b", "/src/tests", "--listEmittedFiles"],
|
||||
incrementalScenarios: coreChanges
|
||||
});
|
||||
verifyTscSerializedIncrementalEdits({
|
||||
scenario: "sample1",
|
||||
subScenario: "explainFiles",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tests", "--explainFiles", "--v"],
|
||||
incrementalScenarios: coreChanges
|
||||
});
|
||||
});
|
||||
|
||||
describe("emit output", () => {
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace ts {
|
||||
scenario: "declarationEmit",
|
||||
subScenario,
|
||||
sys: () => tscWatch.createWatchedSystem(files, { currentDirectory: tscWatch.projectRoot }),
|
||||
commandLineArgs: ["-p", rootProject, "--listFiles"],
|
||||
commandLineArgs: ["-p", rootProject, "--explainFiles"],
|
||||
changes: emptyArray
|
||||
});
|
||||
});
|
||||
@@ -33,7 +33,7 @@ namespace ts {
|
||||
files.map(f => changeCaseFile(f, changeCaseFileTestPath, str => str.replace("myproject", "myProject"))),
|
||||
{ currentDirectory: tscWatch.projectRoot }
|
||||
),
|
||||
commandLineArgs: ["-p", rootProject, "--listFiles"],
|
||||
commandLineArgs: ["-p", rootProject, "--explainFiles"],
|
||||
changes: emptyArray
|
||||
});
|
||||
});
|
||||
|
||||
@@ -37,9 +37,6 @@ namespace ts {
|
||||
getPrograms: () => readonly CommandLineProgram[];
|
||||
}
|
||||
|
||||
function isBuilderProgram<T extends BuilderProgram>(program: Program | T): program is T {
|
||||
return !!(program as T).getState;
|
||||
}
|
||||
function isAnyProgram(program: Program | EmitAndSemanticDiagnosticsBuilderProgram | ParsedCommandLine): program is Program | EmitAndSemanticDiagnosticsBuilderProgram {
|
||||
return !!(program as Program | EmitAndSemanticDiagnosticsBuilderProgram).getCompilerOptions;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace ts {
|
||||
]
|
||||
}`,
|
||||
}),
|
||||
commandLineArgs: ["--incremental", "--p", "src/project", "--tsBuildInfoFile", "src/project/.tsbuildinfo"],
|
||||
commandLineArgs: ["--incremental", "--p", "src/project", "--tsBuildInfoFile", "src/project/.tsbuildinfo", "--explainFiles"],
|
||||
incrementalScenarios: noChangeOnlyRuns
|
||||
});
|
||||
|
||||
|
||||
@@ -46,5 +46,78 @@ namespace ts.tscWatch {
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
verifyTscWatch({
|
||||
scenario: "forceConsistentCasingInFileNames",
|
||||
subScenario: "when relative information file location changes",
|
||||
commandLineArgs: ["--w", "--p", ".", "--explainFiles"],
|
||||
sys: () => {
|
||||
const moduleA: File = {
|
||||
path: `${projectRoot}/moduleA.ts`,
|
||||
content: `import a = require("./ModuleC")`
|
||||
};
|
||||
const moduleB: File = {
|
||||
path: `${projectRoot}/moduleB.ts`,
|
||||
content: `import a = require("./moduleC")`
|
||||
};
|
||||
const moduleC: File = {
|
||||
path: `${projectRoot}/moduleC.ts`,
|
||||
content: `export const x = 10;`
|
||||
};
|
||||
const tsconfig: File = {
|
||||
path: `${projectRoot}/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } })
|
||||
};
|
||||
return createWatchedSystem([moduleA, moduleB, moduleC, libFile, tsconfig], { currentDirectory: projectRoot });
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
caption: "Prepend a line to moduleA",
|
||||
change: sys => sys.prependFile(`${projectRoot}/moduleA.ts`, `// some comment
|
||||
`),
|
||||
timeouts: runQueuedTimeoutCallbacks,
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
verifyTscWatch({
|
||||
scenario: "forceConsistentCasingInFileNames",
|
||||
subScenario: "jsxImportSource option changed",
|
||||
commandLineArgs: ["--w", "--p", ".", "--explainFiles"],
|
||||
sys: () => createWatchedSystem([
|
||||
libFile,
|
||||
{
|
||||
path: `${projectRoot}/node_modules/react/Jsx-runtime/index.d.ts`,
|
||||
content: `export namespace JSX {
|
||||
interface Element {}
|
||||
interface IntrinsicElements {
|
||||
div: {
|
||||
propA?: boolean;
|
||||
};
|
||||
}
|
||||
}
|
||||
export function jsx(...args: any[]): void;
|
||||
export function jsxs(...args: any[]): void;
|
||||
export const Fragment: unique symbol;
|
||||
`,
|
||||
},
|
||||
{
|
||||
path: `${projectRoot}/node_modules/react/package.json`,
|
||||
content: JSON.stringify({ name: "react", version: "0.0.1" })
|
||||
},
|
||||
{
|
||||
path: `${projectRoot}/index.tsx`,
|
||||
content: `export const App = () => <div propA={true}></div>;`
|
||||
},
|
||||
{
|
||||
path: `${projectRoot}/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { jsx: "react-jsx", jsxImportSource: "react", forceConsistentCasingInFileNames: true },
|
||||
files: ["node_modules/react/Jsx-runtime/index.d.ts", "index.tsx"]
|
||||
})
|
||||
}
|
||||
], { currentDirectory: projectRoot }),
|
||||
changes: emptyArray,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -216,27 +216,32 @@ namespace ts.tscWatch {
|
||||
);
|
||||
}
|
||||
|
||||
export function getDiagnosticMessageChain(message: DiagnosticMessage, args?: (string | number)[], next?: DiagnosticMessageChain[]): DiagnosticMessageChain {
|
||||
let text = getLocaleSpecificMessage(message);
|
||||
if (args?.length) {
|
||||
text = formatStringFromArgs(text, args);
|
||||
}
|
||||
return {
|
||||
messageText: text,
|
||||
category: message.category,
|
||||
code: message.code,
|
||||
next
|
||||
};
|
||||
}
|
||||
|
||||
function isDiagnosticMessageChain(message: DiagnosticMessage | DiagnosticMessageChain): message is DiagnosticMessageChain {
|
||||
return !!(message as DiagnosticMessageChain).messageText;
|
||||
}
|
||||
|
||||
export function getDiagnosticOfFileFrom(file: SourceFile | undefined, start: number | undefined, length: number | undefined, message: DiagnosticMessage | DiagnosticMessageChain, ..._args: (string | number)[]): Diagnostic {
|
||||
let text: DiagnosticMessageChain | string;
|
||||
if (isDiagnosticMessageChain(message)) {
|
||||
text = message;
|
||||
}
|
||||
else {
|
||||
text = getLocaleSpecificMessage(message);
|
||||
if (arguments.length > 4) {
|
||||
text = formatStringFromArgs(text, arguments, 4);
|
||||
}
|
||||
}
|
||||
export function getDiagnosticOfFileFrom(file: SourceFile | undefined, start: number | undefined, length: number | undefined, message: DiagnosticMessage | DiagnosticMessageChain, ...args: (string | number)[]): Diagnostic {
|
||||
return {
|
||||
file,
|
||||
start,
|
||||
length,
|
||||
|
||||
messageText: text,
|
||||
messageText: isDiagnosticMessageChain(message) ?
|
||||
message :
|
||||
getDiagnosticMessageChain(message, args).messageText,
|
||||
category: message.category,
|
||||
code: message.code,
|
||||
};
|
||||
|
||||
@@ -277,8 +277,9 @@ export interface A {
|
||||
modifyFs: host => host.deleteFile(`${project}/globals.d.ts`)
|
||||
});
|
||||
|
||||
const jsxImportSourceOptions = { module: "commonjs", jsx: "react-jsx", incremental: true, jsxImportSource: "react" };
|
||||
const jsxLibraryContent = `export namespace JSX {
|
||||
describe("with option jsxImportSource", () => {
|
||||
const jsxImportSourceOptions = { module: "commonjs", jsx: "react-jsx", incremental: true, jsxImportSource: "react" };
|
||||
const jsxLibraryContent = `export namespace JSX {
|
||||
interface Element {}
|
||||
interface IntrinsicElements {
|
||||
div: {
|
||||
@@ -291,64 +292,66 @@ export function jsxs(...args: any[]): void;
|
||||
export const Fragment: unique symbol;
|
||||
`;
|
||||
|
||||
verifyIncrementalWatchEmit({
|
||||
subScenario: "jsxImportSource option changed",
|
||||
files: () => [
|
||||
{ path: libFile.path, content: libContent },
|
||||
{ path: `${project}/node_modules/react/jsx-runtime/index.d.ts`, content: jsxLibraryContent },
|
||||
{ path: `${project}/node_modules/react/package.json`, content: JSON.stringify({ name: "react", version: "0.0.1" }) },
|
||||
{ path: `${project}/node_modules/preact/jsx-runtime/index.d.ts`, content: jsxLibraryContent.replace("propA", "propB") },
|
||||
{ path: `${project}/node_modules/preact/package.json`, content: JSON.stringify({ name: "preact", version: "0.0.1" }) },
|
||||
{ path: `${project}/index.tsx`, content: `export const App = () => <div propA={true}></div>;` },
|
||||
{ path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) }
|
||||
],
|
||||
modifyFs: host => host.writeFile(configFile.path, JSON.stringify({ compilerOptions: { ...jsxImportSourceOptions, jsxImportSource: "preact" } }))
|
||||
});
|
||||
verifyIncrementalWatchEmit({
|
||||
subScenario: "jsxImportSource option changed",
|
||||
files: () => [
|
||||
{ path: libFile.path, content: libContent },
|
||||
{ path: `${project}/node_modules/react/jsx-runtime/index.d.ts`, content: jsxLibraryContent },
|
||||
{ path: `${project}/node_modules/react/package.json`, content: JSON.stringify({ name: "react", version: "0.0.1" }) },
|
||||
{ path: `${project}/node_modules/preact/jsx-runtime/index.d.ts`, content: jsxLibraryContent.replace("propA", "propB") },
|
||||
{ path: `${project}/node_modules/preact/package.json`, content: JSON.stringify({ name: "preact", version: "0.0.1" }) },
|
||||
{ path: `${project}/index.tsx`, content: `export const App = () => <div propA={true}></div>;` },
|
||||
{ path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) }
|
||||
],
|
||||
modifyFs: host => host.writeFile(configFile.path, JSON.stringify({ compilerOptions: { ...jsxImportSourceOptions, jsxImportSource: "preact" } })),
|
||||
optionsToExtend: ["--explainFiles"]
|
||||
});
|
||||
|
||||
verifyIncrementalWatchEmit({
|
||||
subScenario: "jsxImportSource backing types added",
|
||||
files: () => [
|
||||
{ path: libFile.path, content: libContent },
|
||||
{ path: `${project}/index.tsx`, content: `export const App = () => <div propA={true}></div>;` },
|
||||
{ path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) }
|
||||
],
|
||||
modifyFs: host => {
|
||||
host.createDirectory(`${project}/node_modules`);
|
||||
host.createDirectory(`${project}/node_modules/react`);
|
||||
host.createDirectory(`${project}/node_modules/react/jsx-runtime`);
|
||||
host.writeFile(`${project}/node_modules/react/jsx-runtime/index.d.ts`, jsxLibraryContent);
|
||||
host.writeFile(`${project}/node_modules/react/package.json`, JSON.stringify({ name: "react", version: "0.0.1" }));
|
||||
}
|
||||
});
|
||||
verifyIncrementalWatchEmit({
|
||||
subScenario: "jsxImportSource backing types added",
|
||||
files: () => [
|
||||
{ path: libFile.path, content: libContent },
|
||||
{ path: `${project}/index.tsx`, content: `export const App = () => <div propA={true}></div>;` },
|
||||
{ path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) }
|
||||
],
|
||||
modifyFs: host => {
|
||||
host.createDirectory(`${project}/node_modules`);
|
||||
host.createDirectory(`${project}/node_modules/react`);
|
||||
host.createDirectory(`${project}/node_modules/react/jsx-runtime`);
|
||||
host.writeFile(`${project}/node_modules/react/jsx-runtime/index.d.ts`, jsxLibraryContent);
|
||||
host.writeFile(`${project}/node_modules/react/package.json`, JSON.stringify({ name: "react", version: "0.0.1" }));
|
||||
}
|
||||
});
|
||||
|
||||
verifyIncrementalWatchEmit({
|
||||
subScenario: "jsxImportSource backing types removed",
|
||||
files: () => [
|
||||
{ path: libFile.path, content: libContent },
|
||||
{ path: `${project}/node_modules/react/jsx-runtime/index.d.ts`, content: jsxLibraryContent },
|
||||
{ path: `${project}/node_modules/react/package.json`, content: JSON.stringify({ name: "react", version: "0.0.1" }) },
|
||||
{ path: `${project}/index.tsx`, content: `export const App = () => <div propA={true}></div>;` },
|
||||
{ path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) }
|
||||
],
|
||||
modifyFs: host => {
|
||||
host.deleteFile(`${project}/node_modules/react/jsx-runtime/index.d.ts`);
|
||||
host.deleteFile(`${project}/node_modules/react/package.json`);
|
||||
}
|
||||
});
|
||||
verifyIncrementalWatchEmit({
|
||||
subScenario: "jsxImportSource backing types removed",
|
||||
files: () => [
|
||||
{ path: libFile.path, content: libContent },
|
||||
{ path: `${project}/node_modules/react/jsx-runtime/index.d.ts`, content: jsxLibraryContent },
|
||||
{ path: `${project}/node_modules/react/package.json`, content: JSON.stringify({ name: "react", version: "0.0.1" }) },
|
||||
{ path: `${project}/index.tsx`, content: `export const App = () => <div propA={true}></div>;` },
|
||||
{ path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) }
|
||||
],
|
||||
modifyFs: host => {
|
||||
host.deleteFile(`${project}/node_modules/react/jsx-runtime/index.d.ts`);
|
||||
host.deleteFile(`${project}/node_modules/react/package.json`);
|
||||
}
|
||||
});
|
||||
|
||||
verifyIncrementalWatchEmit({
|
||||
subScenario: "importHelpers backing types removed",
|
||||
files: () => [
|
||||
{ path: libFile.path, content: libContent },
|
||||
{ path: `${project}/node_modules/tslib/index.d.ts`, content: "export function __assign(...args: any[]): any;" },
|
||||
{ path: `${project}/node_modules/tslib/package.json`, content: JSON.stringify({ name: "tslib", version: "0.0.1" }) },
|
||||
{ path: `${project}/index.tsx`, content: `export const x = {...{}};` },
|
||||
{ path: configFile.path, content: JSON.stringify({ compilerOptions: { importHelpers: true } }) }
|
||||
],
|
||||
modifyFs: host => {
|
||||
host.deleteFile(`${project}/node_modules/tslib/index.d.ts`);
|
||||
host.deleteFile(`${project}/node_modules/tslib/package.json`);
|
||||
}
|
||||
verifyIncrementalWatchEmit({
|
||||
subScenario: "importHelpers backing types removed",
|
||||
files: () => [
|
||||
{ path: libFile.path, content: libContent },
|
||||
{ path: `${project}/node_modules/tslib/index.d.ts`, content: "export function __assign(...args: any[]): any;" },
|
||||
{ path: `${project}/node_modules/tslib/package.json`, content: JSON.stringify({ name: "tslib", version: "0.0.1" }) },
|
||||
{ path: `${project}/index.tsx`, content: `export const x = {...{}};` },
|
||||
{ path: configFile.path, content: JSON.stringify({ compilerOptions: { importHelpers: true } }) }
|
||||
],
|
||||
modifyFs: host => {
|
||||
host.deleteFile(`${project}/node_modules/tslib/index.d.ts`);
|
||||
host.deleteFile(`${project}/node_modules/tslib/package.json`);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace ts.tscWatch {
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "handle recreated files correctly",
|
||||
commandLineArgs: ["-w", "-p", configFilePath],
|
||||
commandLineArgs: ["-w", "-p", configFilePath, "--explainFiles"],
|
||||
sys: () => {
|
||||
return createWatchedSystem([libFile, commonFile1, commonFile2, configFile]);
|
||||
},
|
||||
@@ -159,7 +159,7 @@ namespace ts.tscWatch {
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "should reflect change in config file",
|
||||
commandLineArgs: ["-w", "-p", configFilePath],
|
||||
commandLineArgs: ["-w", "-p", configFilePath, "--explainFiles"],
|
||||
sys: () => {
|
||||
const configFile: File = {
|
||||
path: configFilePath,
|
||||
@@ -373,7 +373,7 @@ export class A {
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "changes in files are reflected in project structure",
|
||||
commandLineArgs: ["-w", "/a/b/f1.ts"],
|
||||
commandLineArgs: ["-w", "/a/b/f1.ts", "--explainFiles"],
|
||||
sys: () => {
|
||||
const file1 = {
|
||||
path: "/a/b/f1.ts",
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace ts.projectSystem {
|
||||
content: "{}"
|
||||
};
|
||||
const host = createServerHost([f1, libFile, configFile, configFile2]);
|
||||
const service = createProjectService(host, { useSingleInferredProject: true }, { useInferredProjectPerProjectRoot: true });
|
||||
const service = createProjectService(host, { useSingleInferredProject: true, useInferredProjectPerProjectRoot: true });
|
||||
service.openClientFile(f1.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, projectDir);
|
||||
checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
assert.isDefined(service.configuredProjects.get(configFile.path));
|
||||
|
||||
@@ -108,7 +108,7 @@ var x = 10;`
|
||||
content: "const y = 10"
|
||||
};
|
||||
const host = createServerHost([config, file, libFile], { useCaseSensitiveFileNames: true });
|
||||
const service = createProjectService(host, /*parameters*/ undefined, { useInferredProjectPerProjectRoot: true });
|
||||
const service = createProjectService(host, { useInferredProjectPerProjectRoot: true });
|
||||
service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, tscWatch.projectRoot);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]);
|
||||
|
||||
@@ -146,8 +146,17 @@ namespace ts.projectSystem {
|
||||
semantic: [createDiagnostic(
|
||||
location.start,
|
||||
location.end,
|
||||
Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing,
|
||||
[loggerFile.path.toLowerCase(), loggerFile.path]
|
||||
{
|
||||
message: Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing,
|
||||
args: [loggerFile.path.toLowerCase(), loggerFile.path],
|
||||
next: [{
|
||||
message: Diagnostics.The_file_is_in_the_program_because_Colon,
|
||||
next: [
|
||||
{ message: Diagnostics.Matched_by_include_pattern_0_in_1, args: ["**/*", tsconfig.path] },
|
||||
{ message: Diagnostics.Imported_via_0_from_file_1, args: [`"./logger"`, anotherFile.path] }
|
||||
]
|
||||
}]
|
||||
}
|
||||
)],
|
||||
suggestion: []
|
||||
}]
|
||||
|
||||
@@ -383,17 +383,9 @@ namespace ts.projectSystem {
|
||||
}
|
||||
}
|
||||
|
||||
export interface CreateProjectServiceParameters {
|
||||
cancellationToken?: HostCancellationToken;
|
||||
logger?: server.Logger;
|
||||
useSingleInferredProject?: boolean;
|
||||
typingsInstaller?: server.ITypingsInstaller;
|
||||
eventHandler?: server.ProjectServiceEventHandler;
|
||||
}
|
||||
|
||||
export class TestProjectService extends server.ProjectService {
|
||||
constructor(host: server.ServerHost, logger: server.Logger, cancellationToken: HostCancellationToken, useSingleInferredProject: boolean,
|
||||
typingsInstaller: server.ITypingsInstaller, eventHandler: server.ProjectServiceEventHandler, opts: Partial<server.ProjectServiceOptions> = {}) {
|
||||
typingsInstaller: server.ITypingsInstaller, opts: Partial<server.ProjectServiceOptions> = {}) {
|
||||
super({
|
||||
host,
|
||||
logger,
|
||||
@@ -402,7 +394,6 @@ namespace ts.projectSystem {
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller,
|
||||
typesMapLocation: customTypesMap.path,
|
||||
eventHandler,
|
||||
...opts
|
||||
});
|
||||
}
|
||||
@@ -411,11 +402,12 @@ namespace ts.projectSystem {
|
||||
checkNumberOfProjects(this, count);
|
||||
}
|
||||
}
|
||||
export function createProjectService(host: server.ServerHost, parameters: CreateProjectServiceParameters = {}, options?: Partial<server.ProjectServiceOptions>) {
|
||||
const cancellationToken = parameters.cancellationToken || server.nullCancellationToken;
|
||||
const logger = parameters.logger || createHasErrorMessageLogger().logger;
|
||||
const useSingleInferredProject = parameters.useSingleInferredProject !== undefined ? parameters.useSingleInferredProject : false;
|
||||
return new TestProjectService(host, logger, cancellationToken, useSingleInferredProject, parameters.typingsInstaller!, parameters.eventHandler!, options); // TODO: GH#18217
|
||||
|
||||
export function createProjectService(host: server.ServerHost, options?: Partial<server.ProjectServiceOptions>) {
|
||||
const cancellationToken = options?.cancellationToken || server.nullCancellationToken;
|
||||
const logger = options?.logger || createHasErrorMessageLogger().logger;
|
||||
const useSingleInferredProject = options?.useSingleInferredProject !== undefined ? options.useSingleInferredProject : false;
|
||||
return new TestProjectService(host, logger, cancellationToken, useSingleInferredProject, options?.typingsInstaller || server.nullTypingsInstaller, options);
|
||||
}
|
||||
|
||||
export function checkNumberOfConfiguredProjects(projectService: server.ProjectService, expected: number) {
|
||||
@@ -700,8 +692,39 @@ namespace ts.projectSystem {
|
||||
checkNthEvent(session, server.toEvent(eventName, diagnostics), 0, isMostRecent);
|
||||
}
|
||||
|
||||
export function createDiagnostic(start: protocol.Location, end: protocol.Location, message: DiagnosticMessage, args: readonly string[] = [], category = diagnosticCategoryName(message), reportsUnnecessary?: {}, relatedInformation?: protocol.DiagnosticRelatedInformation[], reportsDeprecated?: {}): protocol.Diagnostic {
|
||||
return { start, end, text: formatStringFromArgs(message.message, args), code: message.code, category, reportsUnnecessary, reportsDeprecated, relatedInformation, source: undefined };
|
||||
interface DiagnosticChainText {
|
||||
message: DiagnosticMessage;
|
||||
args?: readonly string[];
|
||||
next?: DiagnosticChainText[];
|
||||
}
|
||||
|
||||
function isDiagnosticMessage(diagnostic: DiagnosticMessage | DiagnosticChainText): diagnostic is DiagnosticMessage {
|
||||
return !!diagnostic && isString((diagnostic as DiagnosticMessage).message);
|
||||
}
|
||||
function getTextForDiagnostic(diag: DiagnosticMessage | DiagnosticChainText | undefined, args?: readonly string[], indent = 0) {
|
||||
if (diag === undefined) return "";
|
||||
if (isDiagnosticMessage(diag)) return formatStringFromArgs(diag.message, args || emptyArray);
|
||||
let result = "";
|
||||
if (indent) {
|
||||
result += "\n";
|
||||
|
||||
for (let i = 0; i < indent; i++) {
|
||||
result += " ";
|
||||
}
|
||||
}
|
||||
result += formatStringFromArgs(diag.message.message, diag.args || emptyArray);
|
||||
indent++;
|
||||
if (diag.next) {
|
||||
for (const kid of diag.next) {
|
||||
result += getTextForDiagnostic(kid, /*args*/ undefined, indent);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function createDiagnostic(start: protocol.Location, end: protocol.Location, message: DiagnosticMessage | DiagnosticChainText, args?: readonly string[], category?: string, reportsUnnecessary?: {}, relatedInformation?: protocol.DiagnosticRelatedInformation[], reportsDeprecated?: {}): protocol.Diagnostic {
|
||||
const diag = isDiagnosticMessage(message) ? message : message.message;
|
||||
return { start, end, text: getTextForDiagnostic(message, args), code: diag.code, category: category || diagnosticCategoryName(diag), reportsUnnecessary, reportsDeprecated, relatedInformation, source: undefined };
|
||||
}
|
||||
|
||||
export function checkCompleteEvent(session: TestSession, numberOfCurrentEvents: number, expectedSequenceId: number, isMostRecent = true): void {
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace ts.projectSystem {
|
||||
};
|
||||
|
||||
const host = createServerHost([file1]);
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true }, { syntaxOnly: true });
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true, syntaxOnly: true });
|
||||
|
||||
projectService.openClientFile(file1.path, file1.content);
|
||||
|
||||
@@ -250,7 +250,7 @@ namespace ts.projectSystem {
|
||||
{ path: "/c/file3.ts", content: "let z = 4;" }
|
||||
];
|
||||
const host = createServerHost(files, { useCaseSensitiveFileNames });
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true, }, { useInferredProjectPerProjectRoot: true });
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true, useInferredProjectPerProjectRoot: true });
|
||||
projectService.setCompilerOptionsForInferredProjects({
|
||||
allowJs: true,
|
||||
target: ScriptTarget.ESNext
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace ts.projectSystem {
|
||||
const projName = "proj1";
|
||||
|
||||
const host = createServerHost([file1, file2]);
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true }, { eventHandler: noop });
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true, eventHandler: noop });
|
||||
|
||||
projectService.openExternalProject({ rootFiles: toExternalFiles([file1.path, file2.path]), options: {}, projectFileName: projName });
|
||||
const proj1 = projectService.findProject(projName)!;
|
||||
@@ -145,7 +145,7 @@ namespace ts.projectSystem {
|
||||
|
||||
const externalProjectName = "externalproject";
|
||||
const host = createServerHost([file1, config1]);
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true }, { syntaxOnly: true });
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true, syntaxOnly: true });
|
||||
projectService.openExternalProject({
|
||||
rootFiles: toExternalFiles([file1.path, config1.path]),
|
||||
options: {},
|
||||
@@ -175,7 +175,7 @@ namespace ts.projectSystem {
|
||||
};
|
||||
|
||||
const host = createServerHost([file1, config1]);
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true }, { syntaxOnly: true });
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true, syntaxOnly: true });
|
||||
projectService.openClientFile(file1.path, file1.content);
|
||||
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
@@ -201,7 +201,7 @@ namespace ts.projectSystem {
|
||||
};
|
||||
|
||||
const host = createServerHost([file1, config1]);
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true }, { syntaxOnly: true });
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true, syntaxOnly: true });
|
||||
projectService.applyChangesInOpenFiles(singleIterator({ fileName: file1.path, content: file1.content }));
|
||||
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace ts.projectSystem {
|
||||
|
||||
it("inferred project", () => {
|
||||
const host = createServerHost([libFile, file1, file2]);
|
||||
const service = createProjectService(host, /*parameters*/ undefined, { useInferredProjectPerProjectRoot: true, });
|
||||
const service = createProjectService(host, { useInferredProjectPerProjectRoot: true, });
|
||||
service.setHostConfiguration({ watchOptions: { excludeFiles: [file2.path] } });
|
||||
const timeoutId = host.getNextTimeoutId();
|
||||
service.setCompilerOptionsForInferredProjects({ excludeDirectories: ["node_modules"] }, tscWatch.projectRoot);
|
||||
|
||||
@@ -700,7 +700,7 @@ namespace ts.projectSystem {
|
||||
const { main, bar, foo } = setupFiles();
|
||||
const files = [libFile, main, bar, foo];
|
||||
const host = createServerHost(files, { currentDirectory: tscWatch.projectRoot });
|
||||
const service = createProjectService(host, {}, { useInferredProjectPerProjectRoot: true });
|
||||
const service = createProjectService(host, { useInferredProjectPerProjectRoot: true });
|
||||
setupConfigureHost(service, configureHost);
|
||||
service.setCompilerOptionsForInferredProjects({ excludeDirectories: ["node_modules"] }, tscWatch.projectRoot);
|
||||
service.openClientFile(main.path, main.content, ScriptKind.TS, tscWatch.projectRoot);
|
||||
@@ -743,7 +743,7 @@ namespace ts.projectSystem {
|
||||
const { main, bar, foo } = setupFiles();
|
||||
const files = [libFile, main, bar, foo];
|
||||
const host = createServerHost(files, { currentDirectory: tscWatch.projectRoot });
|
||||
const service = createProjectService(host, {}, { useInferredProjectPerProjectRoot: true });
|
||||
const service = createProjectService(host, { useInferredProjectPerProjectRoot: true });
|
||||
service.setCompilerOptionsForInferredProjects({ excludeDirectories: ["**/../*"] }, tscWatch.projectRoot);
|
||||
service.openClientFile(main.path, main.content, ScriptKind.TS, tscWatch.projectRoot);
|
||||
const project = service.inferredProjects[0];
|
||||
|
||||
Reference in New Issue
Block a user