Skip to content

Commit 959dee4

Browse files
committed
Ensure specs used are strings
Fixes #38164, #39856
1 parent 3664e03 commit 959dee4

File tree

2 files changed

+58
-53
lines changed

2 files changed

+58
-53
lines changed

src/compiler/commandLineParser.ts

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2308,53 +2308,32 @@ namespace ts {
23082308
};
23092309

23102310
function getFileNames(): ExpandResult {
2311-
let filesSpecs: readonly string[] | undefined;
2312-
if (hasProperty(raw, "files") && !isNullOrUndefined(raw.files)) {
2313-
if (isArray(raw.files)) {
2314-
filesSpecs = <readonly string[]>raw.files;
2315-
const hasReferences = hasProperty(raw, "references") && !isNullOrUndefined(raw.references);
2316-
const hasZeroOrNoReferences = !hasReferences || raw.references.length === 0;
2317-
const hasExtends = hasProperty(raw, "extends");
2318-
if (filesSpecs.length === 0 && hasZeroOrNoReferences && !hasExtends) {
2319-
if (sourceFile) {
2320-
const fileName = configFileName || "tsconfig.json";
2321-
const diagnosticMessage = Diagnostics.The_files_list_in_config_file_0_is_empty;
2322-
const nodeValue = firstDefined(getTsConfigPropArray(sourceFile, "files"), property => property.initializer);
2323-
const error = nodeValue
2324-
? createDiagnosticForNodeInSourceFile(sourceFile, nodeValue, diagnosticMessage, fileName)
2325-
: createCompilerDiagnostic(diagnosticMessage, fileName);
2326-
errors.push(error);
2327-
}
2328-
else {
2329-
createCompilerDiagnosticOnlyIfJson(Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json");
2330-
}
2311+
const filesSpecs = getSpecs("files")?.specs;
2312+
if (filesSpecs) {
2313+
const hasReferences = hasProperty(raw, "references") && !isNullOrUndefined(raw.references);
2314+
const hasZeroOrNoReferences = !hasReferences || raw.references.length === 0;
2315+
const hasExtends = hasProperty(raw, "extends");
2316+
if (filesSpecs.length === 0 && hasZeroOrNoReferences && !hasExtends) {
2317+
if (sourceFile) {
2318+
const fileName = configFileName || "tsconfig.json";
2319+
const diagnosticMessage = Diagnostics.The_files_list_in_config_file_0_is_empty;
2320+
const nodeValue = firstDefined(getTsConfigPropArray(sourceFile, "files"), property => property.initializer);
2321+
const error = nodeValue
2322+
? createDiagnosticForNodeInSourceFile(sourceFile, nodeValue, diagnosticMessage, fileName)
2323+
: createCompilerDiagnostic(diagnosticMessage, fileName);
2324+
errors.push(error);
2325+
}
2326+
else {
2327+
createCompilerDiagnosticOnlyIfJson(Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json");
23312328
}
2332-
}
2333-
else {
2334-
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "files", "Array");
23352329
}
23362330
}
23372331

2338-
let includeSpecs: readonly string[] | undefined;
2339-
if (hasProperty(raw, "include") && !isNullOrUndefined(raw.include)) {
2340-
if (isArray(raw.include)) {
2341-
includeSpecs = <readonly string[]>raw.include;
2342-
}
2343-
else {
2344-
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "include", "Array");
2345-
}
2346-
}
2332+
let includeSpecs = getSpecs("include")?.specs;
23472333

2348-
let excludeSpecs: readonly string[] | undefined;
2349-
if (hasProperty(raw, "exclude") && !isNullOrUndefined(raw.exclude)) {
2350-
if (isArray(raw.exclude)) {
2351-
excludeSpecs = <readonly string[]>raw.exclude;
2352-
}
2353-
else {
2354-
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "exclude", "Array");
2355-
}
2356-
}
2357-
else if (raw.compilerOptions) {
2334+
const excludeSpecResult = getSpecs("exclude");
2335+
let excludeSpecs = excludeSpecResult?.specs;
2336+
if (!excludeSpecResult && raw.compilerOptions) {
23582337
const outDir = raw.compilerOptions.outDir;
23592338
const declarationDir = raw.compilerOptions.declarationDir;
23602339

@@ -2396,6 +2375,22 @@ namespace ts {
23962375
return result;
23972376
}
23982377

2378+
function getSpecs(prop: "files" | "include" | "exclude") {
2379+
if (hasProperty(raw, prop) && !isNullOrUndefined(raw[prop])) {
2380+
let specs: readonly string[] | undefined;
2381+
if (isArray(raw[prop])) {
2382+
specs = <readonly string[]>raw[prop];
2383+
if (!sourceFile && !every(specs, isString)) {
2384+
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, prop, "string"));
2385+
}
2386+
}
2387+
else {
2388+
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, prop, "Array");
2389+
}
2390+
return { specs };
2391+
}
2392+
}
2393+
23992394
function createCompilerDiagnosticOnlyIfJson(message: DiagnosticMessage, arg0?: string, arg1?: string) {
24002395
if (!sourceFile) {
24012396
errors.push(createCompilerDiagnostic(message, arg0, arg1));
@@ -2941,7 +2936,15 @@ namespace ts {
29412936
// new entries in these paths.
29422937
const wildcardDirectories = getWildcardDirectories(validatedIncludeSpecs, validatedExcludeSpecs, basePath, host.useCaseSensitiveFileNames);
29432938

2944-
const spec: ConfigFileSpecs = { filesSpecs, includeSpecs, excludeSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories };
2939+
const spec: ConfigFileSpecs = {
2940+
filesSpecs,
2941+
includeSpecs,
2942+
excludeSpecs,
2943+
validatedFilesSpec: filter(filesSpecs, isString),
2944+
validatedIncludeSpecs,
2945+
validatedExcludeSpecs,
2946+
wildcardDirectories
2947+
};
29452948
return getFileNamesFromConfigSpecs(spec, basePath, options, host, extraFileExtensions);
29462949
}
29472950

@@ -2980,7 +2983,7 @@ namespace ts {
29802983
// file map with a possibly case insensitive key. We use this map to store paths matched
29812984
// via wildcard of *.json kind
29822985
const wildCardJsonFileMap = new Map<string, string>();
2983-
const { filesSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories } = spec;
2986+
const { validatedFilesSpec, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories } = spec;
29842987

29852988
// Rather than requery this for each file and filespec, we query the supported extensions
29862989
// once and store it on the expansion context.
@@ -2989,8 +2992,8 @@ namespace ts {
29892992

29902993
// Literal files are always included verbatim. An "include" or "exclude" specification cannot
29912994
// remove a literal file.
2992-
if (filesSpecs) {
2993-
for (const fileName of filesSpecs) {
2995+
if (validatedFilesSpec) {
2996+
for (const fileName of validatedFilesSpec) {
29942997
const file = getNormalizedAbsolutePath(fileName, basePath);
29952998
literalFileMap.set(keyMapper(file), file);
29962999
}
@@ -3056,14 +3059,14 @@ namespace ts {
30563059
useCaseSensitiveFileNames: boolean,
30573060
currentDirectory: string
30583061
): boolean {
3059-
const { filesSpecs, validatedIncludeSpecs, validatedExcludeSpecs } = spec;
3062+
const { validatedFilesSpec, validatedIncludeSpecs, validatedExcludeSpecs } = spec;
30603063
if (!length(validatedIncludeSpecs) || !length(validatedExcludeSpecs)) return false;
30613064

30623065
basePath = normalizePath(basePath);
30633066

30643067
const keyMapper = createGetCanonicalFileName(useCaseSensitiveFileNames);
3065-
if (filesSpecs) {
3066-
for (const fileName of filesSpecs) {
3068+
if (validatedFilesSpec) {
3069+
for (const fileName of validatedFilesSpec) {
30673070
if (keyMapper(getNormalizedAbsolutePath(fileName, basePath)) === pathToCheck) return false;
30683071
}
30693072
}
@@ -3077,6 +3080,7 @@ namespace ts {
30773080

30783081
function validateSpecs(specs: readonly string[], errors: Push<Diagnostic>, allowTrailingRecursion: boolean, jsonSourceFile: TsConfigSourceFile | undefined, specKey: string): readonly string[] {
30793082
return specs.filter(spec => {
3083+
if (!isString(spec)) return false;
30803084
const diag = specToDiagnostic(spec, allowTrailingRecursion);
30813085
if (diag !== undefined) {
30823086
errors.push(createDiagnostic(diag, spec));

src/compiler/types.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5880,13 +5880,14 @@ namespace ts {
58805880
/**
58815881
* Present to report errors (user specified specs), validatedIncludeSpecs are used for file name matching
58825882
*/
5883-
includeSpecs?: readonly string[];
5883+
includeSpecs: readonly string[] | undefined;
58845884
/**
58855885
* Present to report errors (user specified specs), validatedExcludeSpecs are used for file name matching
58865886
*/
5887-
excludeSpecs?: readonly string[];
5888-
validatedIncludeSpecs?: readonly string[];
5889-
validatedExcludeSpecs?: readonly string[];
5887+
excludeSpecs: readonly string[] | undefined;
5888+
validatedFilesSpec: readonly string[] | undefined;
5889+
validatedIncludeSpecs: readonly string[] | undefined;
5890+
validatedExcludeSpecs: readonly string[] | undefined;
58905891
wildcardDirectories: MapLike<WatchDirectoryFlags>;
58915892
}
58925893

0 commit comments

Comments
 (0)