debt - reduce use of node.js `path` (#249423)

This commit is contained in:
Benjamin Pasero 2025-05-21 09:08:40 +02:00 committed by GitHub
parent ab9a74a9a1
commit 4534383902
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 56 additions and 67 deletions

View File

@ -3,10 +3,11 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as path from 'path';
import * as fs from 'fs';
import * as perf from '../common/performance.js';
import type { ILanguagePacks, INLSConfiguration } from '../../nls.js';
import { join } from 'path'; // using node.js 'path' only for historic reasons, should use our path lib if confident
import { promises } from 'fs';
import { mark } from '../common/performance.js';
import { ILanguagePacks, INLSConfiguration } from '../../nls.js';
import { Promises } from './pfs.js';
export interface IResolveNLSConfigurationContext {
@ -39,7 +40,7 @@ export interface IResolveNLSConfigurationContext {
}
export async function resolveNLSConfiguration({ userLocale, osLocale, userDataPath, commit, nlsMetadataPath }: IResolveNLSConfigurationContext): Promise<INLSConfiguration> {
perf.mark('code/willGenerateNls');
mark('code/willGenerateNls');
if (
process.env['VSCODE_DEV'] ||
@ -69,27 +70,27 @@ export async function resolveNLSConfiguration({ userLocale, osLocale, userDataPa
typeof languagePack.hash !== 'string' ||
!languagePack.translations ||
typeof mainLanguagePackPath !== 'string' ||
!(await exists(mainLanguagePackPath))
!(await Promises.exists(mainLanguagePackPath))
) {
return defaultNLSConfiguration(userLocale, osLocale, nlsMetadataPath);
}
const languagePackId = `${languagePack.hash}.${resolvedLanguage}`;
const globalLanguagePackCachePath = path.join(userDataPath, 'clp', languagePackId);
const commitLanguagePackCachePath = path.join(globalLanguagePackCachePath, commit);
const languagePackMessagesFile = path.join(commitLanguagePackCachePath, 'nls.messages.json');
const translationsConfigFile = path.join(globalLanguagePackCachePath, 'tcf.json');
const languagePackCorruptMarkerFile = path.join(globalLanguagePackCachePath, 'corrupted.info');
const globalLanguagePackCachePath = join(userDataPath, 'clp', languagePackId);
const commitLanguagePackCachePath = join(globalLanguagePackCachePath, commit);
const languagePackMessagesFile = join(commitLanguagePackCachePath, 'nls.messages.json');
const translationsConfigFile = join(globalLanguagePackCachePath, 'tcf.json');
const languagePackCorruptMarkerFile = join(globalLanguagePackCachePath, 'corrupted.info');
if (await exists(languagePackCorruptMarkerFile)) {
await fs.promises.rm(globalLanguagePackCachePath, { recursive: true, force: true, maxRetries: 3 }); // delete corrupted cache folder
if (await Promises.exists(languagePackCorruptMarkerFile)) {
await promises.rm(globalLanguagePackCachePath, { recursive: true, force: true, maxRetries: 3 }); // delete corrupted cache folder
}
const result: INLSConfiguration = {
userLocale,
osLocale,
resolvedLanguage,
defaultMessagesFile: path.join(nlsMetadataPath, 'nls.messages.json'),
defaultMessagesFile: join(nlsMetadataPath, 'nls.messages.json'),
languagePack: {
translationsConfigFile,
messagesFile: languagePackMessagesFile,
@ -107,9 +108,9 @@ export async function resolveNLSConfiguration({ userLocale, osLocale, userDataPa
_corruptedFile: languagePackCorruptMarkerFile
};
if (await exists(commitLanguagePackCachePath)) {
if (await Promises.exists(commitLanguagePackCachePath)) {
touch(commitLanguagePackCachePath).catch(() => { }); // We don't wait for this. No big harm if we can't touch
perf.mark('code/didGenerateNls');
mark('code/didGenerateNls');
return result;
}
@ -122,10 +123,10 @@ export async function resolveNLSConfiguration({ userLocale, osLocale, userDataPa
[unknown, Array<[string, string[]]>, string[], { contents: Record<string, Record<string, string>> }]
// ^moduleId ^nlsKeys ^moduleId ^nlsKey ^nlsValue
= await Promise.all([
fs.promises.mkdir(commitLanguagePackCachePath, { recursive: true }),
fs.promises.readFile(path.join(nlsMetadataPath, 'nls.keys.json'), 'utf-8').then(content => JSON.parse(content)),
fs.promises.readFile(path.join(nlsMetadataPath, 'nls.messages.json'), 'utf-8').then(content => JSON.parse(content)),
fs.promises.readFile(mainLanguagePackPath, 'utf-8').then(content => JSON.parse(content)),
promises.mkdir(commitLanguagePackCachePath, { recursive: true }),
promises.readFile(join(nlsMetadataPath, 'nls.keys.json'), 'utf-8').then(content => JSON.parse(content)),
promises.readFile(join(nlsMetadataPath, 'nls.messages.json'), 'utf-8').then(content => JSON.parse(content)),
promises.readFile(mainLanguagePackPath, 'utf-8').then(content => JSON.parse(content)),
]);
const nlsResult: string[] = [];
@ -145,11 +146,11 @@ export async function resolveNLSConfiguration({ userLocale, osLocale, userDataPa
}
await Promise.all([
fs.promises.writeFile(languagePackMessagesFile, JSON.stringify(nlsResult), 'utf-8'),
fs.promises.writeFile(translationsConfigFile, JSON.stringify(languagePack.translations), 'utf-8')
promises.writeFile(languagePackMessagesFile, JSON.stringify(nlsResult), 'utf-8'),
promises.writeFile(translationsConfigFile, JSON.stringify(languagePack.translations), 'utf-8')
]);
perf.mark('code/didGenerateNls');
mark('code/didGenerateNls');
return result;
} catch (error) {
@ -168,9 +169,9 @@ export async function resolveNLSConfiguration({ userLocale, osLocale, userDataPa
* The file is updated whenever a new language pack is installed or removed.
*/
async function getLanguagePackConfigurations(userDataPath: string): Promise<ILanguagePacks | undefined> {
const configFile = path.join(userDataPath, 'languagepacks.json');
const configFile = join(userDataPath, 'languagepacks.json');
try {
return JSON.parse(await fs.promises.readFile(configFile, 'utf-8'));
return JSON.parse(await promises.readFile(configFile, 'utf-8'));
} catch (err) {
return undefined; // Do nothing. If we can't read the file we have no language pack config.
}
@ -198,13 +199,13 @@ function resolveLanguagePackLanguage(languagePacks: ILanguagePacks, locale: stri
}
function defaultNLSConfiguration(userLocale: string, osLocale: string, nlsMetadataPath: string): INLSConfiguration {
perf.mark('code/didGenerateNls');
mark('code/didGenerateNls');
return {
userLocale,
osLocale,
resolvedLanguage: 'en',
defaultMessagesFile: path.join(nlsMetadataPath, 'nls.messages.json'),
defaultMessagesFile: join(nlsMetadataPath, 'nls.messages.json'),
// NLS: below 2 are a relic from old times only used by vscode-nls and deprecated
locale: userLocale,
@ -214,20 +215,10 @@ function defaultNLSConfiguration(userLocale: string, osLocale: string, nlsMetada
//#region fs helpers
async function exists(path: string): Promise<boolean> {
try {
await fs.promises.access(path);
return true;
} catch {
return false;
}
}
function touch(path: string): Promise<void> {
const date = new Date();
return fs.promises.utimes(path, date, date);
return promises.utimes(path, date, date);
}
//#endregion

View File

@ -9,7 +9,7 @@ import { getRandomTestPath } from './testUtils.js';
import { Promises } from '../../node/pfs.js';
import { SnapshotContext, assertSnapshot } from '../common/snapshot.js';
import { URI } from '../../common/uri.js';
import * as path from 'path';
import { join } from '../../common/path.js';
import { assertThrowsAsync, ensureNoDisposablesAreLeakedInTestSuite } from '../common/utils.js';
// tests for snapshot are in Node so that we can use native FS operations to
@ -46,7 +46,7 @@ suite('snapshot', () => {
const printDir = async (dir: string, indent: number) => {
const children = await Promises.readdir(dir);
for (const child of children) {
const p = path.join(dir, child);
const p = join(dir, child);
if ((await fs.promises.stat(p)).isFile()) {
const content = await fs.promises.readFile(p, 'utf-8');
str += `${' '.repeat(indent)}${child}:\n`;

View File

@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { dirname, join } from 'path';
import { dirname, join } from '../../../../base/common/path.js';
import { Disposable } from '../../../../base/common/lifecycle.js';
import { isWindows } from '../../../../base/common/platform.js';
import { URI } from '../../../../base/common/uri.js';

View File

@ -5,7 +5,7 @@
import assert from 'assert';
import { existsSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'fs';
import { join, resolve } from 'path';
import { join, resolve } from '../../../../base/common/path.js';
import { setUnexpectedErrorHandler } from '../../../../base/common/errors.js';
import { FileAccess } from '../../../../base/common/network.js';
import { DetailedLineRangeMapping, RangeMapping } from '../../../common/diff/rangeMapping.js';

View File

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { spawn } from 'child_process';
import { relative } from 'path';
import { relative } from '../../../base/common/path.js';
import { FileAccess } from '../../../base/common/network.js';
import { StopWatch } from '../../../base/common/stopwatch.js';
import { IEnvironmentService } from '../../environment/common/environment.js';

View File

@ -3,8 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as os from 'os';
import * as path from 'path';
import { homedir } from 'os';
import { resolve, isAbsolute, join } from 'path'; // using node.js 'path' only for historic reasons, should use our path lib if confident
import { NativeParsedArgs } from '../common/argv.js';
const cwd = process.env['VSCODE_CWD'] || process.cwd();
@ -25,11 +25,11 @@ export function getUserDataPath(cliArgs: NativeParsedArgs, productName: string):
// node.js `path.resolve()` logic because it will
// not pick up our `VSCODE_CWD` environment variable
// (https://github.com/microsoft/vscode/issues/120269)
if (!path.isAbsolute(userDataPath)) {
if (!isAbsolute(userDataPath)) {
pathsToResolve.unshift(cwd);
}
return path.resolve(...pathsToResolve);
return resolve(...pathsToResolve);
}
function doGetUserDataPath(cliArgs: NativeParsedArgs, productName: string): string {
@ -42,13 +42,13 @@ function doGetUserDataPath(cliArgs: NativeParsedArgs, productName: string): stri
// 1. Support portable mode
const portablePath = process.env['VSCODE_PORTABLE'];
if (portablePath) {
return path.join(portablePath, 'user-data');
return join(portablePath, 'user-data');
}
// 2. Support global VSCODE_APPDATA environment variable
let appDataPath = process.env['VSCODE_APPDATA'];
if (appDataPath) {
return path.join(appDataPath, productName);
return join(appDataPath, productName);
}
// With Electron>=13 --user-data-dir switch will be propagated to
@ -70,18 +70,18 @@ function doGetUserDataPath(cliArgs: NativeParsedArgs, productName: string): stri
throw new Error('Windows: Unexpected undefined %USERPROFILE% environment variable');
}
appDataPath = path.join(userProfile, 'AppData', 'Roaming');
appDataPath = join(userProfile, 'AppData', 'Roaming');
}
break;
case 'darwin':
appDataPath = path.join(os.homedir(), 'Library', 'Application Support');
appDataPath = join(homedir(), 'Library', 'Application Support');
break;
case 'linux':
appDataPath = process.env['XDG_CONFIG_HOME'] || path.join(os.homedir(), '.config');
appDataPath = process.env['XDG_CONFIG_HOME'] || join(homedir(), '.config');
break;
default:
throw new Error('Platform not supported');
}
return path.join(appDataPath, productName);
return join(appDataPath, productName);
}

View File

@ -6,7 +6,7 @@
import * as fs from 'fs';
import * as os from 'os';
import * as cp from 'child_process';
import * as path from 'path';
import { join } from '../../../base/common/path.js';
let hasWSLFeaturePromise: Promise<boolean> | undefined;
@ -59,7 +59,7 @@ function getSystem32Path(subPath: string): string | undefined {
const systemRoot = process.env['SystemRoot'];
if (systemRoot) {
const is32ProcessOn64Windows = process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432');
return path.join(systemRoot, is32ProcessOn64Windows ? 'Sysnative' : 'System32', subPath);
return join(systemRoot, is32ProcessOn64Windows ? 'Sysnative' : 'System32', subPath);
}
return undefined;
}

View File

@ -27,7 +27,7 @@ import { ShellIntegrationAddon } from '../common/xterm/shellIntegrationAddon.js'
import { formatMessageForTerminal } from '../common/terminalStrings.js';
import { IPtyHostProcessReplayEvent } from '../common/capabilities/capabilities.js';
import { IProductService } from '../../product/common/productService.js';
import { join } from 'path';
import { join } from '../../../base/common/path.js';
import { memoize } from '../../../base/common/decorators.js';
import * as performance from '../../../base/common/performance.js';
import pkg from '@xterm/headless';

View File

@ -6,7 +6,7 @@
import * as fs from 'fs';
import * as cp from 'child_process';
import { Codicon } from '../../../base/common/codicons.js';
import { basename, delimiter, normalize } from '../../../base/common/path.js';
import { basename, delimiter, normalize, dirname, resolve } from '../../../base/common/path.js';
import { isLinux, isWindows } from '../../../base/common/platform.js';
import { findExecutable } from '../../../base/node/processes.js';
import { isString } from '../../../base/common/types.js';
@ -18,7 +18,6 @@ import { ILogService } from '../../log/common/log.js';
import { ITerminalEnvironment, ITerminalExecutable, ITerminalProfile, ITerminalProfileSource, ITerminalUnsafePath, ProfileSource, TerminalIcon, TerminalSettingId } from '../common/terminal.js';
import { getWindowsBuildNumber } from './terminalEnvironment.js';
import { ThemeIcon } from '../../../base/common/themables.js';
import { dirname, resolve } from 'path';
const enum Constants {
UnixShellsPath = '/etc/shells'

View File

@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { createReadStream, promises } from 'fs';
import * as path from 'path';
import * as http from 'http';
import * as url from 'url';
import * as cookie from 'cookie';
@ -14,7 +13,7 @@ import { getMediaMime } from '../../base/common/mime.js';
import { isLinux } from '../../base/common/platform.js';
import { ILogService, LogLevel } from '../../platform/log/common/log.js';
import { IServerEnvironmentService } from './serverEnvironmentService.js';
import { extname, dirname, join, normalize, posix } from '../../base/common/path.js';
import { extname, dirname, join, normalize, posix, resolve } from '../../base/common/path.js';
import { FileAccess, connectionTokenCookieName, connectionTokenQueryName, Schemas, builtinExtensionsPath } from '../../base/common/network.js';
import { generateUuid } from '../../base/common/uuid.js';
import { IProductService } from '../../platform/product/common/productService.js';
@ -323,7 +322,7 @@ export class WebClientServer {
const callbackRoute = posix.join(basePath, this._productPath, CALLBACK_PATH);
const webExtensionRoute = posix.join(basePath, this._productPath, WEB_EXTENSION_PATH);
const resolveWorkspaceURI = (defaultLocation?: string) => defaultLocation && URI.file(path.resolve(defaultLocation)).with({ scheme: Schemas.vscodeRemote, authority: remoteAuthority });
const resolveWorkspaceURI = (defaultLocation?: string) => defaultLocation && URI.file(resolve(defaultLocation)).with({ scheme: Schemas.vscodeRemote, authority: remoteAuthority });
const filePath = FileAccess.asFileUri(`vs/code/browser/workbench/workbench${this._environmentService.isBuilt ? '' : '-dev'}.html`).fsPath;
const authSessionInfo = !this._environmentService.isBuilt && this._environmentService.args['github-auth'] ? {

View File

@ -6,7 +6,7 @@
import assert from 'assert';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { join } from '../../../base/common/path.js';
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../base/test/common/utils.js';
import { getRandomTestPath } from '../../../base/test/node/testUtils.js';
import { parseServerConnectionToken, ServerConnectionToken, ServerConnectionTokenParseError, ServerConnectionTokenType } from '../../node/serverConnectionToken.js';
@ -51,7 +51,7 @@ suite('parseServerConnectionToken', () => {
this.timeout(10000);
const testDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'server-connection-token');
fs.mkdirSync(testDir, { recursive: true });
const filename = path.join(testDir, 'connection-token-file');
const filename = join(testDir, 'connection-token-file');
const connectionToken = `12345-123-abc`;
fs.writeFileSync(filename, connectionToken);
const result = await parseServerConnectionToken({ 'connection-token-file': filename } as ServerParsedArgs, async () => 'defaultTokenValue');

View File

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as fs from 'fs';
import * as path from 'path';
import { extname, join } from '../../../../../base/common/path.js';
import assert from 'assert';
import { DisposableStore, IDisposable } from '../../../../../base/common/lifecycle.js';
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
@ -128,10 +128,10 @@ suite('Auto-Reindentation - TypeScript/JavaScript', () => {
const directoriesToRecurseOn: string[] = [];
for (const file of files) {
if (file.isDirectory()) {
directoriesToRecurseOn.push(path.join(directory, file.name));
directoriesToRecurseOn.push(join(directory, file.name));
} else {
const filePathName = path.join(directory, file.name);
const fileExtension = path.extname(filePathName);
const filePathName = join(directory, file.name);
const fileExtension = extname(filePathName);
if (fileExtension !== '.ts') {
continue;
}