Refactor config file syntax search to callback model instead of constructing arrays to iterate over (#53416)

This commit is contained in:
Sheetal Nandi
2023-03-21 11:23:36 -07:00
committed by GitHub
parent de31ebecea
commit 377c4ce32f
3 changed files with 41 additions and 51 deletions

View File

@@ -41,11 +41,11 @@ import {
filterMutate,
find,
findIndex,
firstDefined,
firstOrUndefinedIterator,
flatten,
forEach,
forEachEntry,
forEachTsConfigPropArray,
getBaseFileName,
getDirectoryPath,
getFileMatcherPatterns,
@@ -59,7 +59,6 @@ import {
getSupportedExtensions,
getSupportedExtensionsWithJsonIfResolveJsonModule,
getTextOfPropertyName,
getTsConfigPropArray,
getTsConfigPropArrayElementValue,
hasExtension,
hasProperty,
@@ -2886,7 +2885,7 @@ function parseJsonConfigFileContentWorker(
if (sourceFile) {
const fileName = configFileName || "tsconfig.json";
const diagnosticMessage = Diagnostics.The_files_list_in_config_file_0_is_empty;
const nodeValue = firstDefined(getTsConfigPropArray(sourceFile, "files"), property => property.initializer);
const nodeValue = forEachTsConfigPropArray(sourceFile, "files", property => property.initializer);
const error = createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, nodeValue, diagnosticMessage, fileName);
errors.push(error);
}

View File

@@ -93,7 +93,6 @@ import {
filter,
find,
findIndex,
firstDefined,
firstDefinedIterator,
flatMap,
flatten,
@@ -104,7 +103,9 @@ import {
forEachEmittedFile,
forEachEntry,
forEachKey,
forEachPropertyAssignment,
forEachResolvedProjectReference as ts_forEachResolvedProjectReference,
forEachTsConfigPropArray,
FunctionLikeDeclaration,
getAllowJSCompilerOption,
getAutomaticTypeDirectiveNames,
@@ -138,7 +139,6 @@ import {
getPathFromPathComponents,
getPositionOfLineAndCharacter,
getPropertyArrayElementValue,
getPropertyAssignment,
getResolvedModule,
getResolveJsonModule,
getRootLength,
@@ -152,7 +152,6 @@ import {
getTransformers,
getTsBuildInfoEmitOutputFilePath,
getTsConfigObjectLiteralExpression,
getTsConfigPropArray,
getTsConfigPropArrayElementValue,
HasChangedAutomaticTypeDirectiveNames,
hasChangesInResolutions,
@@ -263,6 +262,7 @@ import {
ProjectReference,
ProjectReferenceFile,
projectReferenceIsEqualTo,
PropertyAssignment,
PropertyDeclaration,
ReferencedFile,
removeFileExtension,
@@ -4535,7 +4535,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
);
if (!referenceInfo) return undefined;
const { sourceFile, index } = referenceInfo;
const referencesSyntax = firstDefined(getTsConfigPropArray(sourceFile as TsConfigSourceFile, "references"),
const referencesSyntax = forEachTsConfigPropArray(sourceFile as TsConfigSourceFile, "references",
property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
return referencesSyntax && referencesSyntax.elements.length > index ?
createDiagnosticForNodeInSourceFile(
@@ -4610,19 +4610,17 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, ...args: DiagnosticArguments) {
let needCompilerDiagnostic = true;
const pathsSyntax = getOptionPathsSyntax();
for (const pathProp of pathsSyntax) {
forEachOptionPathsSyntax(pathProp => {
if (isObjectLiteralExpression(pathProp.initializer)) {
for (const keyProps of getPropertyAssignment(pathProp.initializer, key)) {
forEachPropertyAssignment(pathProp.initializer, key, keyProps => {
const initializer = keyProps.initializer;
if (isArrayLiteralExpression(initializer) && initializer.elements.length > valueIndex) {
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, initializer.elements[valueIndex], message, ...args));
needCompilerDiagnostic = false;
}
}
});
}
}
});
if (needCompilerDiagnostic) {
programDiagnostics.add(createCompilerDiagnostic(message, ...args));
}
@@ -4630,32 +4628,29 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
function createDiagnosticForOptionPaths(onKey: boolean, key: string, message: DiagnosticMessage, ...args: DiagnosticArguments) {
let needCompilerDiagnostic = true;
const pathsSyntax = getOptionPathsSyntax();
for (const pathProp of pathsSyntax) {
forEachOptionPathsSyntax(pathProp => {
if (isObjectLiteralExpression(pathProp.initializer) &&
createOptionDiagnosticInObjectLiteralSyntax(
pathProp.initializer, onKey, key, /*key2*/ undefined,
message, ...args)) {
needCompilerDiagnostic = false;
}
}
});
if (needCompilerDiagnostic) {
programDiagnostics.add(createCompilerDiagnostic(message, ...args));
}
}
function getOptionsSyntaxByName(name: string) {
const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
return compilerOptionsObjectLiteralSyntax && getPropertyAssignment(compilerOptionsObjectLiteralSyntax, name);
function forEachOptionsSyntaxByName<T>(name: string, callback: (prop: PropertyAssignment) => T | undefined): T | undefined {
return forEachPropertyAssignment(getCompilerOptionsObjectLiteralSyntax(), name, callback);
}
function getOptionPathsSyntax() {
return getOptionsSyntaxByName("paths") || emptyArray;
function forEachOptionPathsSyntax<T>(callback: (prop: PropertyAssignment) => T | undefined) {
return forEachOptionsSyntaxByName("paths", callback);
}
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);
return forEachOptionsSyntaxByName(name, property => isStringLiteral(property.initializer) && property.initializer.text === value ? property.initializer : undefined);
}
function getOptionsSyntaxByArrayElementValue(name: string, value: string) {
@@ -4673,7 +4668,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
}
function createDiagnosticForReference(sourceFile: JsonSourceFile | undefined, index: number, message: DiagnosticMessage, ...args: DiagnosticArguments) {
const referencesSyntax = firstDefined(getTsConfigPropArray(sourceFile || options.configFile, "references"),
const referencesSyntax = forEachTsConfigPropArray(sourceFile || options.configFile, "references",
property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
if (referencesSyntax && referencesSyntax.elements.length > index) {
programDiagnostics.add(createDiagnosticForNodeInSourceFile(sourceFile || options.configFile!, referencesSyntax.elements[index], message, ...args));
@@ -4703,16 +4698,11 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
function getCompilerOptionsObjectLiteralSyntax() {
if (_compilerOptionsObjectLiteralSyntax === undefined) {
_compilerOptionsObjectLiteralSyntax = false;
const jsonObjectLiteral = getTsConfigObjectLiteralExpression(options.configFile);
if (jsonObjectLiteral) {
for (const prop of getPropertyAssignment(jsonObjectLiteral, "compilerOptions")) {
if (isObjectLiteralExpression(prop.initializer)) {
_compilerOptionsObjectLiteralSyntax = prop.initializer;
break;
}
}
}
_compilerOptionsObjectLiteralSyntax = forEachPropertyAssignment(
getTsConfigObjectLiteralExpression(options.configFile),
"compilerOptions",
prop => isObjectLiteralExpression(prop.initializer) ? prop.initializer : undefined
) || false;
}
return _compilerOptionsObjectLiteralSyntax || undefined;
}
@@ -4721,8 +4711,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean;
function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): boolean;
function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): boolean {
const props = getPropertyAssignment(objectLiteral, key1, key2);
for (const prop of props) {
let needsCompilerDiagnostic = false;
forEachPropertyAssignment(objectLiteral, key1, prop => {
// eslint-disable-next-line local/no-in-operator
if ("messageText" in message) {
programDiagnostics.add(createDiagnosticForNodeFromMessageChain(options.configFile!, onKey ? prop.name : prop.initializer, message));
@@ -4730,8 +4720,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
else {
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, onKey ? prop.name : prop.initializer, message, ...args));
}
}
return !!props.length;
needsCompilerDiagnostic = true;
}, key2);
return needsCompilerDiagnostic;
}
/**

View File

@@ -2683,22 +2683,23 @@ export function isThisTypePredicate(predicate: TypePredicate): predicate is This
}
/** @internal */
export function getPropertyAssignment(objectLiteral: ObjectLiteralExpression, key: string, key2?: string): readonly PropertyAssignment[] {
return objectLiteral.properties.filter((property): property is PropertyAssignment => {
if (property.kind === SyntaxKind.PropertyAssignment) {
const propName = tryGetTextOfPropertyName(property.name);
return key === propName || (!!key2 && key2 === propName);
}
return false;
export function forEachPropertyAssignment<T>(objectLiteral: ObjectLiteralExpression | undefined, key: string, callback: (property: PropertyAssignment) => T | undefined, key2?: string) {
return forEach(objectLiteral?.properties, property => {
if (!isPropertyAssignment(property)) return undefined;
const propName = tryGetTextOfPropertyName(property.name);
return key === propName || (key2 && key2 === propName) ?
callback(property) :
undefined;
});
}
/** @internal */
export function getPropertyArrayElementValue(objectLiteral: ObjectLiteralExpression, propKey: string, elementValue: string): StringLiteral | undefined {
return firstDefined(getPropertyAssignment(objectLiteral, propKey), property =>
return forEachPropertyAssignment(objectLiteral, propKey, property =>
isArrayLiteralExpression(property.initializer) ?
find(property.initializer.elements, (element): element is StringLiteral => isStringLiteral(element) && element.text === elementValue) :
undefined);
undefined
);
}
/** @internal */
@@ -2711,16 +2712,15 @@ export function getTsConfigObjectLiteralExpression(tsConfigSourceFile: TsConfigS
/** @internal */
export function getTsConfigPropArrayElementValue(tsConfigSourceFile: TsConfigSourceFile | undefined, propKey: string, elementValue: string): StringLiteral | undefined {
return firstDefined(getTsConfigPropArray(tsConfigSourceFile, propKey), property =>
return forEachTsConfigPropArray(tsConfigSourceFile, propKey, property =>
isArrayLiteralExpression(property.initializer) ?
find(property.initializer.elements, (element): element is StringLiteral => isStringLiteral(element) && element.text === elementValue) :
undefined);
}
/** @internal */
export function getTsConfigPropArray(tsConfigSourceFile: TsConfigSourceFile | undefined, propKey: string): readonly PropertyAssignment[] {
const jsonObjectLiteral = getTsConfigObjectLiteralExpression(tsConfigSourceFile);
return jsonObjectLiteral ? getPropertyAssignment(jsonObjectLiteral, propKey) : emptyArray;
export function forEachTsConfigPropArray<T>(tsConfigSourceFile: TsConfigSourceFile | undefined, propKey: string, callback: (property: PropertyAssignment) => T | undefined) {
return forEachPropertyAssignment(getTsConfigObjectLiteralExpression(tsConfigSourceFile), propKey, callback);
}
/** @internal */