Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use replaceAll instead of an incorrect RegExp for tsserver log sanitization. #54454

Merged
merged 1 commit into from May 30, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
76 changes: 54 additions & 22 deletions src/testRunner/unittests/helpers/tsserver.ts
Expand Up @@ -36,6 +36,29 @@ export const customTypesMap = {
}`
};

function replaceAll(source: string, searchValue: string, replaceValue: string): string {
let result: string | undefined =
(source as string & { replaceAll: typeof source.replace }).replaceAll?.(searchValue, replaceValue);

if (result !== undefined) {
return result;
}

result = "";
const searchLength = searchValue.length;
while (true) {
const index = source.indexOf(searchValue);
if (index < 0) {
break;
}
result += source.slice(0, index);
result += replaceValue;
source = source.slice(index + searchLength);
}
result += source;
return result;
}

export interface PostExecAction {
readonly success: boolean;
requestId: number;
Expand Down Expand Up @@ -115,23 +138,24 @@ export function createLoggerWritingToConsole(host: TestServerHost): Logger {
}, host);
}

function sanitizeLog(s: string) {
return s.replace(/Elapsed::?\s*\d+(?:\.\d+)?ms/g, "Elapsed:: *ms")
.replace(/\"updateGraphDurationMs\"\:\s*\d+(?:\.\d+)?/g, `"updateGraphDurationMs": *`)
.replace(/\"createAutoImportProviderProgramDurationMs\"\:\s*\d+(?:\.\d+)?/g, `"createAutoImportProviderProgramDurationMs": *`)
.replace(versionRegExp, `FakeVersion`)
.replace(/getCompletionData: Get current token: \d+(?:\.\d+)?/g, `getCompletionData: Get current token: *`)
.replace(/getCompletionData: Is inside comment: \d+(?:\.\d+)?/g, `getCompletionData: Is inside comment: *`)
.replace(/getCompletionData: Get previous token: \d+(?:\.\d+)?/g, `getCompletionData: Get previous token: *`)
.replace(/getCompletionsAtPosition: isCompletionListBlocker: \d+(?:\.\d+)?/g, `getCompletionsAtPosition: isCompletionListBlocker: *`)
.replace(/getCompletionData: Semantic work: \d+(?:\.\d+)?/g, `getCompletionData: Semantic work: *`)
.replace(/getCompletionsAtPosition: getCompletionEntriesFromSymbols: \d+(?:\.\d+)?/g, `getCompletionsAtPosition: getCompletionEntriesFromSymbols: *`)
.replace(/forEachExternalModuleToImportFrom autoImportProvider: \d+(?:\.\d+)?/g, `forEachExternalModuleToImportFrom autoImportProvider: *`)
.replace(/getExportInfoMap: done in \d+(?:\.\d+)?/g, `getExportInfoMap: done in *`)
.replace(/collectAutoImports: \d+(?:\.\d+)?/g, `collectAutoImports: *`)
.replace(/continuePreviousIncompleteResponse: \d+(?:\.\d+)?/g, `continuePreviousIncompleteResponse: *`)
.replace(/dependencies in \d+(?:\.\d+)?/g, `dependencies in *`)
.replace(/\"exportMapKey\"\:\s*\"[_$a-zA-Z][_$_$a-zA-Z0-9]*\|\d+\|/g, match => match.replace(/\|\d+\|/, `|*|`));
function sanitizeLog(s: string): string {
s = s.replace(/Elapsed::?\s*\d+(?:\.\d+)?ms/g, "Elapsed:: *ms");
s = s.replace(/\"updateGraphDurationMs\"\:\s*\d+(?:\.\d+)?/g, `"updateGraphDurationMs": *`);
s = s.replace(/\"createAutoImportProviderProgramDurationMs\"\:\s*\d+(?:\.\d+)?/g, `"createAutoImportProviderProgramDurationMs": *`);
s = replaceAll(s, ts.version, "FakeVersion");
s = s.replace(/getCompletionData: Get current token: \d+(?:\.\d+)?/g, `getCompletionData: Get current token: *`);
s = s.replace(/getCompletionData: Is inside comment: \d+(?:\.\d+)?/g, `getCompletionData: Is inside comment: *`);
s = s.replace(/getCompletionData: Get previous token: \d+(?:\.\d+)?/g, `getCompletionData: Get previous token: *`);
s = s.replace(/getCompletionsAtPosition: isCompletionListBlocker: \d+(?:\.\d+)?/g, `getCompletionsAtPosition: isCompletionListBlocker: *`);
s = s.replace(/getCompletionData: Semantic work: \d+(?:\.\d+)?/g, `getCompletionData: Semantic work: *`);
s = s.replace(/getCompletionsAtPosition: getCompletionEntriesFromSymbols: \d+(?:\.\d+)?/g, `getCompletionsAtPosition: getCompletionEntriesFromSymbols: *`);
s = s.replace(/forEachExternalModuleToImportFrom autoImportProvider: \d+(?:\.\d+)?/g, `forEachExternalModuleToImportFrom autoImportProvider: *`);
s = s.replace(/getExportInfoMap: done in \d+(?:\.\d+)?/g, `getExportInfoMap: done in *`);
s = s.replace(/collectAutoImports: \d+(?:\.\d+)?/g, `collectAutoImports: *`);
s = s.replace(/continuePreviousIncompleteResponse: \d+(?:\.\d+)?/g, `continuePreviousIncompleteResponse: *`);
s = s.replace(/dependencies in \d+(?:\.\d+)?/g, `dependencies in *`);
s = s.replace(/\"exportMapKey\"\:\s*\"[_$a-zA-Z][_$_$a-zA-Z0-9]*\|\d+\|/g, match => match.replace(/\|\d+\|/, `|*|`));
return s;
}

export function createLoggerWithInMemoryLogs(host: TestServerHost): Logger {
Expand Down Expand Up @@ -159,14 +183,22 @@ export function appendAllScriptInfos(session: TestSession) {
session.logger.log("");
}

const versionRegExp = new RegExp(ts.version, "g");
const tsMajorMinorVersion = new RegExp(`@ts${ts.versionMajorMinor}`, "g");
function loggerToTypingsInstallerLog(logger: Logger): ts.server.typingsInstaller.Log | undefined {
return logger?.loggingEnabled() ? {
isEnabled: ts.returnTrue,
writeLine: s => logger.log(`TI:: [${nowString(logger.host!)}] ${sanitizeLog(s).replace(versionRegExp, "FakeVersion")
.replace(tsMajorMinorVersion, `@tsFakeMajor.Minor`)
}`),
writeLine: s => {
// This is a VERY VERY NAIVE sanitization strategy.
// If a substring containing the exact TypeScript version is found,
// even if it's unrelated to TypeScript itself, then it will be replaced,
// leaving us with two options:
//
// 1. Deal with flip-flopping baselines.
// 2. Change the TypeScript version until no matching substring is found.
//
const initialLog = sanitizeLog(s);
const pseudoSanitizedLog = replaceAll(initialLog, `@ts${ts.versionMajorMinor}`, `@tsFakeMajor.Minor`);
return logger.log(`TI:: [${nowString(logger.host!)}] ${pseudoSanitizedLog}`);
},
} : undefined;
}

Expand Down