/
githubmirror
/
TypeScript
Обзор
Документация
Войти
/
githubmirror
/
TypeScript
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/harness/tsserverLogger.ts
178 строк
7 KB
Jake Bailey
Eliminate `tests/lib/lib.d.ts`, fix up fourslash to use real libs and defaults (#63056)
28 янв 2026, 22:23
Не верифицирован
28 янв 2026, 22:23
2fed590
Код
Авторство
О чём код?
import * as ts from "./_namespaces/ts.js"; import { IO, libFolder, } from "./harnessIO.js"; export const HarnessLSCouldNotResolveModule = "HarnessLanguageService:: Could not resolve module"; export 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 Logger extends ts.server.Logger { logs?: string[]; log(s: string): void; host?: ts.server.ServerHost; } export function nullLogger(): Logger { return { close: ts.noop, hasLevel: ts.returnFalse, loggingEnabled: ts.returnFalse, perftrc: ts.noop, info: ts.noop, msg: ts.noop, startGroup: ts.noop, endGroup: ts.noop, getLogFileName: ts.returnUndefined, log: ts.noop, isTestLogger: true, }; } export function createHasErrorMessageLogger(): Logger { const logger = nullLogger(); logger.msg = (s, type) => ts.Debug.fail(`Error: ${s}, type: ${type}`); return logger; } function handleLoggerGroup(logger: Logger, host: ts.server.ServerHost, sanitizeLibs: true | undefined): Logger { const originaPush = logger.logs!.push; logger.hasLevel = ts.returnTrue; logger.loggingEnabled = ts.returnTrue; logger.host = host; let inGroup = false; let firstInGroup = false; logger.startGroup = () => { inGroup = true; firstInGroup = true; }; logger.endGroup = () => inGroup = false; logger.info = s => msg(s, ts.server.Msg.Info, log); logger.log = log; logger.logs!.push = log; return logger; function log(...args: string[]) { args.forEach(s => originaPush.call(logger.logs, (sanitizeLibs ? sanitizeLibFileText : ts.identity)(sanitizeLog(s)))); return 0; } function msg(s: string, type = ts.server.Msg.Err, write: (s: string) => void) { s = `[${nowString(logger)}] ${s}`; if (!inGroup || firstInGroup) s = padStringRight(type + " seq", " ") + s; if (ts.Debug.isDebugging) console.log(s); write(s); } function padStringRight(str: string, padding: string) { return (str + padding).slice(0, padding.length); } } export function nowString(logger: Logger) { // E.g. "12:34:56.789" logger.host?.now?.(); // To increment the time but not print it to avoid the baseline updates return `hh:mm:ss:mss`; } export function createLoggerWritingToConsole(host: ts.server.ServerHost, sanitizeLibs?: true) { const logger = createHasErrorMessageLogger(); logger.logs = []; logger.logs.push = (...args) => { args.forEach(s => console.log(s)); return 0; }; return handleLoggerGroup( logger, host, sanitizeLibs, ) as LoggerWithInMemoryLogs; } export 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 = s.replace(new RegExp(`\\b${ts.regExpEscape(ts.version)}\\b`, "g"), "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(/referenced projects in \d+(?:\.\d+)?/g, `referenced projects in *`); s = s.replace(/"exportMapKey":\s*"\d+ \d+ /g, match => match.replace(/ \d+ /, ` * `)); s = s.replace(/getIndentationAtPosition: getCurrentSourceFile: \d+(?:\.\d+)?/, `getIndentationAtPosition: getCurrentSourceFile: *`); s = s.replace(/getIndentationAtPosition: computeIndentation\s*: \d+(?:\.\d+)?/, `getIndentationAtPosition: computeIndentation: *`); s = s.replace(/"syntaxDiag":\s*\d+(?:.\d+)?/g, `"syntaxDiag": *`); s = s.replace(/"semanticDiag":\s*\d+(?:.\d+)?/g, `"semanticDiag": *`); s = s.replace(/"suggestionDiag":\s*\d+(?:.\d+)?/g, `"suggestionDiag": *`); s = s.replace(/"regionSemanticDiag":\s*\d+(?:.\d+)?/g, `"regionSemanticDiag": *`); s = s.replace(new RegExp(`\\b@ts${ts.regExpEscape(ts.versionMajorMinor)}\\b`, "g"), `@tsFakeMajor.Minor`); s = sanitizeHarnessLSException(s); return s; } function sanitizeHarnessLSException(s: string) { const index = s.indexOf(HarnessLSCouldNotResolveModule); if (index > 0) s = s.substring(0, index) + HarnessLSCouldNotResolveModule; return s; } const libFileTextReplacements = ts.memoize(() => { const replacements: { text: string; jsonText: string; replacement: string; }[] = []; // Read all lib files from built/local const libFiles = IO.listFiles(libFolder, /^lib.*\.d\.ts$/); for (const libPath of libFiles) { const content = IO.readFile(libPath); if (content) { const fileName = ts.getBaseFileName(libPath); replacements.push({ text: content, jsonText: JSON.stringify(content), replacement: `${fileName}-Text` }); } } return replacements; }); export function sanitizeLibFileText(s: string): string { for (const { text, jsonText, replacement } of libFileTextReplacements()) { s = replaceAll(s, jsonText, replacement); s = replaceAll(s, text, replacement); } return s; } export interface LoggerWithInMemoryLogs extends Logger { logs: string[]; } export function createLoggerWithInMemoryLogs(host: ts.server.ServerHost, sanitizeLibs?: true): LoggerWithInMemoryLogs { const logger = createHasErrorMessageLogger(); logger.logs = []; return handleLoggerGroup(logger, host, sanitizeLibs) as LoggerWithInMemoryLogs; }