From dd8d6704265981aaa338a81eebca92d385eae09d Mon Sep 17 00:00:00 2001 From: Bharat Middha <5100938+bmiddha@users.noreply.github.com> Date: Wed, 19 Aug 2026 14:20:03 -0700 Subject: [PATCH 1/5] refactor: convert TS private fields to #private Convert eligible TS 'private' class property declarations to ECMAScript #private fields across apps/rush, apps/rush-mcp-server, apps/lockfile-explorer, apps/playwright-browser-tunnel, apps/zipsync, apps/rundown, apps/trace-import, apps/cpu-profile-summarizer, apps/rush-serve-dashboard, libraries/rush-terminal-renderer, libraries/rush-daemon, libraries/rush-daemon-transport, libraries/rushell, rush-plugins, repo-scripts/repo-toolbox, and vscode-extensions. Strips one conventional leading underscore from each converted field name. Rewrote an unsupported destructuring assignment in RedisCobuildLockProvider (const { _terminal: terminal } = this;) to plain property access so it could be converted. Retained rush-plugins/rush-buildxl-graph-plugin's test-only 'declare private _configHash' field as TS-private: that mock relies on Object.setPrototypeOf to backfill a field on a plain object, which true ECMAScript private fields cannot support. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8ebd5bf2-c44b-42d5-be25-e7936d4b0a14 --- apps/cpu-profile-summarizer/src/start.ts | 12 +- .../cli/explorer/ExplorerCommandLineParser.ts | 12 +- .../src/cli/lint/actions/CheckAction.ts | 42 ++-- .../src/cli/lint/actions/InitAction.ts | 10 +- .../src/graph/PnpmfileRunner.ts | 50 ++--- .../src/utils/PackageUpdateChecker.ts | 32 +-- .../src/HttpServer.ts | 38 ++-- .../src/PlaywrightBrowserTunnel.ts | 202 +++++++++--------- apps/rundown/src/Rundown.ts | 10 +- apps/rundown/src/cli/InspectAction.ts | 6 +- apps/rundown/src/launcher.ts | 18 +- .../pluginFramework/RushMcpPluginLoader.ts | 16 +- .../pluginFramework/RushMcpPluginSession.ts | 8 +- apps/rush-mcp-server/src/server.ts | 26 +-- apps/rush-mcp-server/src/tools/base.tool.ts | 6 +- .../src/tools/migrate-project.tool.ts | 6 +- .../src/modules/ansiSgrParser.ts | 36 ++-- apps/rush/src/MinimalRushConfiguration.ts | 12 +- apps/rush/src/RushVersionSelector.ts | 12 +- .../src/TraceImportCommandLineParser.ts | 26 +-- .../src/cli/ZipSyncCommandLineParser.ts | 70 +++--- .../src/DaemonFrameConnection.ts | 40 ++-- .../src/DaemonListener.ts | 12 +- .../rush-daemon/src/DaemonControlSession.ts | 32 +-- libraries/rush-daemon/src/RequestScheduler.ts | 42 ++-- libraries/rush-daemon/src/RushDaemonHost.ts | 24 +-- .../src/DaemonRendererHost.ts | 34 +-- .../src/HostEventRouter.ts | 22 +- .../src/LegacyCollatedRenderer.ts | 8 +- .../src/OperationStreamRegistry.ts | 46 ++-- .../src/TerminalSinkWritable.ts | 6 +- .../src/test/LegacyPipelineReplica.ts | 44 ++-- .../src/test/TestTerminal.ts | 6 +- libraries/rushell/src/Parser.ts | 22 +- libraries/rushell/src/Tokenizer.ts | 46 ++-- .../actions/BumpDecoupledLocalDependencies.ts | 6 +- .../cli/actions/CollectProjectFilesAction.ts | 18 +- .../src/cli/actions/ReadmeAction.ts | 12 +- .../src/AmazonS3BuildCacheProvider.ts | 46 ++-- .../src/AmazonS3Client.ts | 56 ++--- .../src/AzureAuthenticationBase.ts | 8 +- .../src/AzureStorageBuildCacheProvider.ts | 26 +-- .../src/RushAzureInteractiveAuthPlugin.ts | 6 +- .../src/BridgeCachePlugin.ts | 26 +-- .../src/DropBuildGraphPlugin.ts | 6 +- .../src/GraphProcessor.ts | 16 +- .../src/HttpBuildCacheProvider.ts | 104 ++++----- .../rush-litewatch-plugin/src/WatchManager.ts | 18 +- .../rush-litewatch-plugin/src/WatchProject.ts | 28 +-- .../src/test/WatchManager.test.ts | 8 +- .../src/RedisCobuildLockProvider.ts | 60 +++--- .../src/RushRedisCobuildPlugin.ts | 6 +- .../src/RushProjectServeConfigFile.ts | 6 +- .../rush-serve-plugin/src/RushServePlugin.ts | 30 +-- .../tryEnableBuildStatusWebSocketServer.ts | 6 +- .../src/logic/RushCommandWebViewPanel.ts | 28 +-- .../src/logic/RushWorkspace.ts | 20 +- .../src/providers/RushCommandsProvider.ts | 20 +- .../src/providers/RushProjectsProvider.ts | 16 +- .../VScodeOutputChannelTerminalProvider.ts | 6 +- 60 files changed, 808 insertions(+), 808 deletions(-) diff --git a/apps/cpu-profile-summarizer/src/start.ts b/apps/cpu-profile-summarizer/src/start.ts index 8360ef05e9f..d7a3474d066 100644 --- a/apps/cpu-profile-summarizer/src/start.ts +++ b/apps/cpu-profile-summarizer/src/start.ts @@ -119,8 +119,8 @@ function writeSummaryToTsv(tsvPath: string, summary: IProfileSummary): void { } class CpuProfileSummarizerCommandLineParser extends CommandLineParser { - private readonly _inputParameter: CommandLineStringListParameter; - private readonly _outputParameter: IRequiredCommandLineStringParameter; + readonly #inputParameter: CommandLineStringListParameter; + readonly #outputParameter: IRequiredCommandLineStringParameter; public constructor() { super({ @@ -130,7 +130,7 @@ class CpuProfileSummarizerCommandLineParser extends CommandLineParser { 'For example, those generated by running `node --cpu-prof`.' }); - this._inputParameter = this.defineStringListParameter({ + this.#inputParameter = this.defineStringListParameter({ parameterLongName: '--input', parameterShortName: '-i', description: 'The directory containing .cpuprofile files to summarize', @@ -138,7 +138,7 @@ class CpuProfileSummarizerCommandLineParser extends CommandLineParser { required: true }); - this._outputParameter = this.defineStringParameter({ + this.#outputParameter = this.defineStringParameter({ parameterLongName: '--output', parameterShortName: '-o', description: 'The output file to write the summary to', @@ -148,8 +148,8 @@ class CpuProfileSummarizerCommandLineParser extends CommandLineParser { } protected override async onExecuteAsync(): Promise { - const input: readonly string[] = this._inputParameter.values; - const output: string = this._outputParameter.value; + const input: readonly string[] = this.#inputParameter.values; + const output: string = this.#outputParameter.value; if (input.length === 0) { throw new Error('No input directories provided'); diff --git a/apps/lockfile-explorer/src/cli/explorer/ExplorerCommandLineParser.ts b/apps/lockfile-explorer/src/cli/explorer/ExplorerCommandLineParser.ts index fab4cb5765b..84c811b6206 100644 --- a/apps/lockfile-explorer/src/cli/explorer/ExplorerCommandLineParser.ts +++ b/apps/lockfile-explorer/src/cli/explorer/ExplorerCommandLineParser.ts @@ -51,8 +51,8 @@ function printUpdateNotification( export class ExplorerCommandLineParser extends CommandLineParser { public readonly globalTerminal: ITerminal; - private readonly _debugParameter: CommandLineFlagParameter; - private readonly _subspaceParameter: IRequiredCommandLineStringParameter; + readonly #debugParameter: CommandLineFlagParameter; + readonly #subspaceParameter: IRequiredCommandLineStringParameter; public constructor(terminal: ITerminal) { super({ @@ -61,13 +61,13 @@ export class ExplorerCommandLineParser extends CommandLineParser { 'Lockfile Explorer is a desktop app for investigating and solving version conflicts in a PNPM workspace.' }); - this._debugParameter = this.defineFlagParameter({ + this.#debugParameter = this.defineFlagParameter({ parameterLongName: '--debug', parameterShortName: '-d', description: 'Show the full call stack if an error occurs while executing the tool' }); - this._subspaceParameter = this.defineStringParameter({ + this.#subspaceParameter = this.defineStringParameter({ parameterLongName: '--subspace', argumentName: 'SUBSPACE_NAME', description: 'Specifies an individual Rush subspace to check.', @@ -78,7 +78,7 @@ export class ExplorerCommandLineParser extends CommandLineParser { } public get isDebug(): boolean { - return this._debugParameter.value; + return this.#debugParameter.value; } protected override async onExecuteAsync(): Promise { @@ -106,7 +106,7 @@ export class ExplorerCommandLineParser extends CommandLineParser { const appState: IAppState = init({ appVersion: LFX_VERSION, debugMode: this.isDebug, - subspaceName: this._subspaceParameter.value + subspaceName: this.#subspaceParameter.value }); const lfxWorkspace: IJsonLfxWorkspace = appState.lfxWorkspace; diff --git a/apps/lockfile-explorer/src/cli/lint/actions/CheckAction.ts b/apps/lockfile-explorer/src/cli/lint/actions/CheckAction.ts index a7b7347788f..bcb8d673dbd 100644 --- a/apps/lockfile-explorer/src/cli/lint/actions/CheckAction.ts +++ b/apps/lockfile-explorer/src/cli/lint/actions/CheckAction.ts @@ -38,11 +38,11 @@ export interface ILintIssue { } export class CheckAction extends CommandLineAction { - private readonly _terminal: ITerminal; + readonly #terminal: ITerminal; - private _rushConfiguration!: RushConfiguration; - private _checkedProjects: Set; - private _docMap: Map; + #rushConfiguration!: RushConfiguration; + #checkedProjects: Set; + #docMap: Map; public constructor(terminal: ITerminal) { super({ @@ -54,9 +54,9 @@ export class CheckAction extends CommandLineAction { ', reporting any problems found in your PNPM workspace.' }); - this._terminal = terminal; - this._checkedProjects = new Set(); - this._docMap = new Map(); + this.#terminal = terminal; + this.#checkedProjects = new Set(); + this.#docMap = new Map(); } private async _checkVersionCompatibilityAsync( @@ -100,18 +100,18 @@ export class CheckAction extends CommandLineAction { project: RushConfigurationProject, requiredVersions: Record ): Promise { - this._terminal.writeLine(`Checking project "${project.packageName}"`); + this.#terminal.writeLine(`Checking project "${project.packageName}"`); const projectFolder: string = project.projectFolder; const subspace: Subspace = project.subspace; const shrinkwrapFilename: string = subspace.getCommittedShrinkwrapFilePath(); let doc: lockfileTypes.LockfileObject; - if (this._docMap.has(shrinkwrapFilename)) { - doc = this._docMap.get(shrinkwrapFilename)!; + if (this.#docMap.has(shrinkwrapFilename)) { + doc = this.#docMap.get(shrinkwrapFilename)!; } else { const pnpmLockfileText: string = await FileSystem.readFileAsync(shrinkwrapFilename); doc = yaml.load(pnpmLockfileText) as lockfileTypes.LockfileObject; - this._docMap.set(shrinkwrapFilename, doc); + this.#docMap.set(shrinkwrapFilename, doc); } const { importers, lockfileVersion, packages } = doc; const shrinkwrapFileMajorVersion: number = getShrinkwrapFileMajorVersion(lockfileVersion); @@ -136,9 +136,9 @@ export class CheckAction extends CommandLineAction { ) as pnpmTypes.DepPath; if (fullDependencyPath.includes('link:')) { const dependencyProject: RushConfigurationProject | undefined = - this._rushConfiguration.getProjectByName(dependencyName); - if (dependencyProject && !this._checkedProjects?.has(dependencyProject)) { - this._checkedProjects!.add(project); + this.#rushConfiguration.getProjectByName(dependencyName); + if (dependencyProject && !this.#checkedProjects?.has(dependencyProject)) { + this.#checkedProjects!.add(project); await this._searchAndValidateDependenciesAsync(dependencyProject, requiredVersions); } } else { @@ -162,13 +162,13 @@ export class CheckAction extends CommandLineAction { ): Promise { try { const project: RushConfigurationProject | undefined = - this._rushConfiguration?.getProjectByName(projectName); + this.#rushConfiguration?.getProjectByName(projectName); if (!project) { throw new Error( `Specified project "${projectName}" does not exist in ${LOCKFILE_LINT_JSON_FILENAME}` ); } - this._checkedProjects.add(project); + this.#checkedProjects.add(project); await this._searchAndValidateDependenciesAsync(project, requiredVersions); return undefined; } catch (e) { @@ -183,10 +183,10 @@ export class CheckAction extends CommandLineAction { 'The "lockfile-explorer check" must be executed in a folder that is under a Rush workspace folder' ); } - this._rushConfiguration = rushConfiguration!; + this.#rushConfiguration = rushConfiguration!; const lintingFile: string = path.resolve( - this._rushConfiguration.commonFolder, + this.#rushConfiguration.commonFolder, 'config', LOCKFILE_EXPLORER_FOLDERNAME, LOCKFILE_LINT_JSON_FILENAME @@ -219,7 +219,7 @@ export class CheckAction extends CommandLineAction { { concurrency: 50 } ); if (issues.length > 0) { - this._terminal.writeLine(); + this.#terminal.writeLine(); // Deterministic order for (const issue of issues.sort((a, b): number => { @@ -233,13 +233,13 @@ export class CheckAction extends CommandLineAction { } return a.message.localeCompare(b.message); })) { - this._terminal.writeLine( + this.#terminal.writeLine( Colorize.red('PROBLEM: ') + Colorize.cyan(`[${issue.rule}] `) + issue.message + '\n' ); } throw new AlreadyReportedError(); } - this._terminal.writeLine(Colorize.green('SUCCESS: ') + 'All checks passed.'); + this.#terminal.writeLine(Colorize.green('SUCCESS: ') + 'All checks passed.'); } } diff --git a/apps/lockfile-explorer/src/cli/lint/actions/InitAction.ts b/apps/lockfile-explorer/src/cli/lint/actions/InitAction.ts index 834f7761f55..f45a0587c1d 100644 --- a/apps/lockfile-explorer/src/cli/lint/actions/InitAction.ts +++ b/apps/lockfile-explorer/src/cli/lint/actions/InitAction.ts @@ -11,7 +11,7 @@ import { FileSystem } from '@rushstack/node-core-library'; import { LOCKFILE_EXPLORER_FOLDERNAME, LOCKFILE_LINT_JSON_FILENAME } from '../../../constants/common'; export class InitAction extends CommandLineAction { - private readonly _terminal: ITerminal; + readonly #terminal: ITerminal; public constructor(terminal: ITerminal) { super({ @@ -21,7 +21,7 @@ export class InitAction extends CommandLineAction { `This command initializes a new ${LOCKFILE_LINT_JSON_FILENAME} config file.` + ` The created template file includes source code comments that document the settings.` }); - this._terminal = terminal; + this.#terminal = terminal; } protected override async onExecuteAsync(): Promise { @@ -43,12 +43,12 @@ export class InitAction extends CommandLineAction { ); if (await FileSystem.existsAsync(outputFilePath)) { - this._terminal.writeError('The output file already exists:'); - this._terminal.writeLine('\n ' + outputFilePath + '\n'); + this.#terminal.writeError('The output file already exists:'); + this.#terminal.writeLine('\n ' + outputFilePath + '\n'); throw new Error('Unable to write output file'); } - this._terminal.writeLine(Colorize.green('Writing file: ') + outputFilePath); + this.#terminal.writeLine(Colorize.green('Writing file: ') + outputFilePath); await FileSystem.copyFileAsync({ sourcePath: inputFilePath, destinationPath: outputFilePath diff --git a/apps/lockfile-explorer/src/graph/PnpmfileRunner.ts b/apps/lockfile-explorer/src/graph/PnpmfileRunner.ts index 10c09e7d40b..3f7b8ef8fdb 100644 --- a/apps/lockfile-explorer/src/graph/PnpmfileRunner.ts +++ b/apps/lockfile-explorer/src/graph/PnpmfileRunner.ts @@ -18,27 +18,27 @@ interface IPromise { * package.json files. Calling `disposeAsync()` will free the loaded modules. */ export class PnpmfileRunner { - private _worker: Worker; - private _nextId: number = 1000; - private _promisesById: Map = new Map(); - private _disposed: boolean = false; + #worker: Worker; + #nextId: number = 1000; + #promisesById: Map = new Map(); + #disposed: boolean = false; public logger: ((message: string) => void) | undefined = undefined; public constructor(pnpmfilePath: string) { - this._worker = new Worker(path.join(`${__dirname}/pnpmfileRunnerWorkerThread.js`), { + this.#worker = new Worker(path.join(`${__dirname}/pnpmfileRunnerWorkerThread.js`), { workerData: { pnpmfilePath } }); - this._worker.on('message', (message: ResponseMessage) => { + this.#worker.on('message', (message: ResponseMessage) => { const id: number = message.id; - const promise: IPromise | undefined = this._promisesById.get(id); + const promise: IPromise | undefined = this.#promisesById.get(id); if (!promise) { return; } if (message.kind === 'return') { - this._promisesById.delete(id); + this.#promisesById.delete(id); // TODO: Validate the user's readPackage() return value const result: IPackageJson = message.result as IPackageJson; promise.resolve(result); @@ -50,28 +50,28 @@ export class PnpmfileRunner { console.log('.pnpmfile.cjs: ' + message.log); } } else { - this._promisesById.delete(id); + this.#promisesById.delete(id); promise.reject(new Error(message.error || 'An unknown error occurred')); } }); - this._worker.on('error', (err) => { - for (const promise of this._promisesById.values()) { + this.#worker.on('error', (err) => { + for (const promise of this.#promisesById.values()) { promise.reject(err); } - this._promisesById.clear(); + this.#promisesById.clear(); }); - this._worker.on('exit', (code) => { - if (!this._disposed) { + this.#worker.on('exit', (code) => { + if (!this.#disposed) { const error: Error = new Error( `PnpmfileRunner worker thread terminated unexpectedly with exit code ${code}` ); console.error(error); - for (const promise of this._promisesById.values()) { + for (const promise of this.#promisesById.values()) { promise.reject(error); } - this._promisesById.clear(); + this.#promisesById.clear(); } }); } @@ -83,26 +83,26 @@ export class PnpmfileRunner { packageJson: IPackageJson, packageJsonFullPath: string ): Promise { - if (this._disposed) { + if (this.#disposed) { return Promise.reject(new Error('The operation failed because PnpmfileRunner has been disposed')); } - const id: number = this._nextId++; + const id: number = this.#nextId++; return new Promise((resolve, reject) => { - this._promisesById.set(id, { resolve, reject }); - this._worker.postMessage({ id, packageJson, packageJsonFullPath } satisfies IRequestMessage); + this.#promisesById.set(id, { resolve, reject }); + this.#worker.postMessage({ id, packageJson, packageJsonFullPath } satisfies IRequestMessage); }); } public async disposeAsync(): Promise { - if (this._disposed) { + if (this.#disposed) { return; } - for (const pending of this._promisesById.values()) { + for (const pending of this.#promisesById.values()) { pending.reject(new Error('Aborted because PnpmfileRunner was disposed')); } - this._promisesById.clear(); - this._disposed = true; - await this._worker.terminate(); + this.#promisesById.clear(); + this.#disposed = true; + await this.#worker.terminate(); } } diff --git a/apps/lockfile-explorer/src/utils/PackageUpdateChecker.ts b/apps/lockfile-explorer/src/utils/PackageUpdateChecker.ts index cf353b347d2..290e5b9fcb2 100644 --- a/apps/lockfile-explorer/src/utils/PackageUpdateChecker.ts +++ b/apps/lockfile-explorer/src/utils/PackageUpdateChecker.ts @@ -140,11 +140,11 @@ async function _writeCacheAsync( * @internal */ export class PackageUpdateChecker { - private readonly _packageName: string; - private readonly _currentVersion: string; - private readonly _skip: boolean; - private readonly _forceCheck: boolean; - private readonly _cacheExpiryMs: number; + readonly #packageName: string; + readonly #currentVersion: string; + readonly #skip: boolean; + readonly #forceCheck: boolean; + readonly #cacheExpiryMs: number; public constructor(options: IPackageUpdateCheckerOptions) { const { @@ -154,11 +154,11 @@ export class PackageUpdateChecker { forceCheck = false, cacheExpiryMs = DEFAULT_CACHE_EXPIRY_MS } = options; - this._packageName = packageName; - this._currentVersion = currentVersion; - this._skip = skip; - this._forceCheck = forceCheck; - this._cacheExpiryMs = cacheExpiryMs; + this.#packageName = packageName; + this.#currentVersion = currentVersion; + this.#skip = skip; + this.#forceCheck = forceCheck; + this.#cacheExpiryMs = cacheExpiryMs; } /** @@ -166,19 +166,19 @@ export class PackageUpdateChecker { * was skipped or the registry could not be reached. */ public async tryGetUpdateAsync(): Promise { - if (this._skip) { + if (this.#skip) { return undefined; } const cacheFilePath: string = this._getCacheFilePath(); let latestVersion: string | undefined; - if (!this._forceCheck) { + if (!this.#forceCheck) { const cached: IUpdateCheckCache | undefined = await _readCacheAsync(cacheFilePath); if (cached !== undefined) { const { checkedAt, latestVersion: latestVersionFromCache } = cached; const ageMs: number = Date.now() - checkedAt; - if (ageMs < this._cacheExpiryMs) { + if (ageMs < this.#cacheExpiryMs) { latestVersion = latestVersionFromCache; } } @@ -186,7 +186,7 @@ export class PackageUpdateChecker { if (latestVersion === undefined) { // Cache is missing or stale — fetch from the registry. - latestVersion = await _tryFetchLatestVersionAsync(this._packageName); + latestVersion = await _tryFetchLatestVersionAsync(this.#packageName); if (latestVersion === undefined) { return undefined; } @@ -196,13 +196,13 @@ export class PackageUpdateChecker { return { latestVersion, - isOutdated: semver.gt(latestVersion, this._currentVersion) + isOutdated: semver.gt(latestVersion, this.#currentVersion) }; } private _getCacheFilePath(): string { // Replace characters that are unsafe in file names (e.g. the "/" in scoped package names). - const sanitizedName: string = this._packageName.replace(/[^a-zA-Z0-9._-]/g, '_'); + const sanitizedName: string = this.#packageName.replace(/[^a-zA-Z0-9._-]/g, '_'); return `${CACHE_FOLDER}/${sanitizedName}.json`; } } diff --git a/apps/playwright-browser-tunnel/src/HttpServer.ts b/apps/playwright-browser-tunnel/src/HttpServer.ts index ced852a5f98..7942d79bfbe 100644 --- a/apps/playwright-browser-tunnel/src/HttpServer.ts +++ b/apps/playwright-browser-tunnel/src/HttpServer.ts @@ -28,22 +28,22 @@ function formatAddress(addressInfo: AddressInfo): string { * browserName and launchOptions. */ export class HttpServer { - private readonly _server: http.Server; - private readonly _wsServer: WebSocketServer; // local proxy websocket server accepting browser clients - private _listeningAddress: string | undefined; - private _logger: ITerminal; + readonly #server: http.Server; + readonly #wsServer: WebSocketServer; // local proxy websocket server accepting browser clients + #listeningAddress: string | undefined; + #logger: ITerminal; public constructor(logger: ITerminal) { - this._logger = logger; + this.#logger = logger; // We'll create an HTTP server and attach a WebSocketServer in noServer mode so we can // manually parse the URL and extract query parameters before upgrading. - this._server = http.createServer(); - this._wsServer = new WebSocketServer({ noServer: true }); + this.#server = http.createServer(); + this.#wsServer = new WebSocketServer({ noServer: true }); - this._server.on('upgrade', (request, socket, head) => { + this.#server.on('upgrade', (request, socket, head) => { // Accept all upgrades on the root path. We parse query string for browserName + launchOptions. - this._wsServer.handleUpgrade(request, socket, head, (ws: WebSocket) => { - this._wsServer.emit('connection', ws, request); + this.#wsServer.handleUpgrade(request, socket, head, (ws: WebSocket) => { + this.#wsServer.emit('connection', ws, request); }); }); } @@ -52,8 +52,8 @@ export class HttpServer { return await new Promise((resolve) => { // Bind to 'localhost' which resolves to IPv4 (127.0.0.1) or IPv6 (::1) // depending on system configuration and DNS resolution - this._server.listen(0, LOCALHOST, () => { - const addressInfo: AddressInfo | string | null = this._server.address(); + this.#server.listen(0, LOCALHOST, () => { + const addressInfo: AddressInfo | string | null = this.#server.address(); if (!addressInfo) { throw new Error('Server address is null - server may not be bound properly'); } @@ -61,27 +61,27 @@ export class HttpServer { throw new Error(`Server address is a pipe/socket path (${addressInfo}), expected an IP address`); } const formattedAddress: string = formatAddress(addressInfo); - this._listeningAddress = formattedAddress; + this.#listeningAddress = formattedAddress; // This MUST be printed to terminal so VS Code can auto-port forward - this._logger.writeLine(`Local proxy HttpServer listening at ws://${formattedAddress}`); + this.#logger.writeLine(`Local proxy HttpServer listening at ws://${formattedAddress}`); resolve(new URL(`ws://${formattedAddress}`)); }); }); } public get endpoint(): string { - if (this._listeningAddress === undefined) { + if (this.#listeningAddress === undefined) { throw new Error('HttpServer not listening yet'); } - return `ws://${this._listeningAddress}`; + return `ws://${this.#listeningAddress}`; } public get wsServer(): WebSocketServer { - return this._wsServer; + return this.#wsServer; } public [Symbol.dispose](): void { - this._wsServer.close(); - this._server.close(); + this.#wsServer.close(); + this.#server.close(); } } diff --git a/apps/playwright-browser-tunnel/src/PlaywrightBrowserTunnel.ts b/apps/playwright-browser-tunnel/src/PlaywrightBrowserTunnel.ts index 1fa0627b531..d6b98c2512c 100644 --- a/apps/playwright-browser-tunnel/src/PlaywrightBrowserTunnel.ts +++ b/apps/playwright-browser-tunnel/src/PlaywrightBrowserTunnel.ts @@ -88,20 +88,20 @@ interface IBrowserServerProxy { * @beta */ export class PlaywrightTunnel { - private readonly _terminal: ITerminal; - private readonly _onStatusChange: (status: TunnelStatus) => void; - private readonly _onBeforeLaunch?: (handshake: IHandshake) => Promise | boolean; - private readonly _playwrightBrowsersInstalled: Set = new Set(); - private readonly _wsEndpoint: string | undefined; - private readonly _listenPort: number | undefined; - private readonly _playwrightInstallPath: string; - private _status: TunnelStatus = 'stopped'; - private _initWsPromise?: Promise; - private _keepRunning: boolean = false; - private _ws?: WebSocket; - private _mode: TunnelMode; - private _pendingConnectionAttempt?: Promise; - private _pollInterval?: NodeJS.Timeout; + readonly #terminal: ITerminal; + readonly #onStatusChange: (status: TunnelStatus) => void; + readonly #onBeforeLaunch?: (handshake: IHandshake) => Promise | boolean; + readonly #playwrightBrowsersInstalled: Set = new Set(); + readonly #wsEndpoint: string | undefined; + readonly #listenPort: number | undefined; + readonly #playwrightInstallPath: string; + #status: TunnelStatus = 'stopped'; + #initWsPromise?: Promise; + #keepRunning: boolean = false; + #ws?: WebSocket; + #mode: TunnelMode; + #pendingConnectionAttempt?: Promise; + #pollInterval?: NodeJS.Timeout; public constructor(options: IPlaywrightTunnelOptions) { const { mode, terminal, onStatusChange, playwrightInstallPath, onBeforeLaunch } = options; @@ -111,55 +111,55 @@ export class PlaywrightTunnel { if (!options.wsEndpoint) { throw new Error('wsEndpoint is required for poll-connection mode'); } - this._wsEndpoint = options.wsEndpoint; - this._listenPort = undefined; + this.#wsEndpoint = options.wsEndpoint; + this.#listenPort = undefined; break; case 'wait-for-incoming-connection': if (options.listenPort === undefined) { throw new Error('listenPort is required for wait-for-incoming-connection mode'); } - this._wsEndpoint = undefined; - this._listenPort = options.listenPort; + this.#wsEndpoint = undefined; + this.#listenPort = options.listenPort; break; default: throw new Error(`Invalid mode: ${mode}`); } - this._mode = mode; - this._terminal = terminal; - this._onStatusChange = onStatusChange; - this._onBeforeLaunch = onBeforeLaunch; - this._playwrightInstallPath = playwrightInstallPath; + this.#mode = mode; + this.#terminal = terminal; + this.#onStatusChange = onStatusChange; + this.#onBeforeLaunch = onBeforeLaunch; + this.#playwrightInstallPath = playwrightInstallPath; } public get status(): TunnelStatus { - return this._status; + return this.#status; } // eslint-disable-next-line @typescript-eslint/naming-convention private set status(newStatus: TunnelStatus) { - this._status = newStatus; - this._onStatusChange(newStatus); + this.#status = newStatus; + this.#onStatusChange(newStatus); } public async waitForCloseAsync(): Promise { - const terminal: ITerminal = this._terminal; - const initWsPromise: Promise | undefined = this._initWsPromise; + const terminal: ITerminal = this.#terminal; + const initWsPromise: Promise | undefined = this.#initWsPromise; if (initWsPromise) { const ws: WebSocket = await initWsPromise; await once(ws, 'close'); terminal.writeDebugLine('WebSocket connection closed. resolving init promise.'); - this._initWsPromise = undefined; + this.#initWsPromise = undefined; } } public async startAsync(options: { keepRunning?: boolean } = {}): Promise { - this._keepRunning = options.keepRunning ?? true; - const terminal: ITerminal = this._terminal; - terminal.writeLine(`keepRunning: ${this._keepRunning}`); - while (this._keepRunning) { - if (!this._initWsPromise) { - this._initWsPromise = this._initPlaywrightBrowserTunnelAsync(); + this.#keepRunning = options.keepRunning ?? true; + const terminal: ITerminal = this.#terminal; + terminal.writeLine(`keepRunning: ${this.#keepRunning}`); + while (this.#keepRunning) { + if (!this.#initWsPromise) { + this.#initWsPromise = this._initPlaywrightBrowserTunnelAsync(); } else { terminal.writeLine(`Tunnel is already running with status: ${this.status}`); } @@ -168,29 +168,29 @@ export class PlaywrightTunnel { } public async stopAsync(): Promise { - this._keepRunning = false; - if (this._pollInterval) { - clearInterval(this._pollInterval); - this._pollInterval = undefined; + this.#keepRunning = false; + if (this.#pollInterval) { + clearInterval(this.#pollInterval); + this.#pollInterval = undefined; } - await this._initWsPromise?.finally(() => { - this._ws?.close(WebSocketCloseCode.NORMAL_CLOSURE, 'Tunnel stopped'); + await this.#initWsPromise?.finally(() => { + this.#ws?.close(WebSocketCloseCode.NORMAL_CLOSURE, 'Tunnel stopped'); }); } public async [Symbol.asyncDispose](): Promise { - this._terminal.writeLine('Disposing WebSocket connection.'); + this.#terminal.writeLine('Disposing WebSocket connection.'); await this.stopAsync(); } public async cleanTempFilesAsync(): Promise { - const tmpPath: string = this._playwrightInstallPath; - this._terminal.writeLine(`Cleaning up temporary files in ${tmpPath}`); + const tmpPath: string = this.#playwrightInstallPath; + this.#terminal.writeLine(`Cleaning up temporary files in ${tmpPath}`); try { await FileSystem.ensureEmptyFolderAsync(tmpPath); - this._terminal.writeLine(`Temporary files cleaned up.`); + this.#terminal.writeLine(`Temporary files cleaned up.`); } catch (error) { - this._terminal.writeLine(`Failed to clean up temporary files: ${getNormalizedErrorString(error)}`); + this.#terminal.writeLine(`Failed to clean up temporary files: ${getNormalizedErrorString(error)}`); } } @@ -198,9 +198,9 @@ export class PlaywrightTunnel { // public async uninstallPlaywrightBrowsersAsync(): Promise {} private async _runCommandAsync(command: string, args: string[]): Promise { - const tmpPath: string = this._playwrightInstallPath; + const tmpPath: string = this.#playwrightInstallPath; await FileSystem.ensureFolderAsync(tmpPath); - this._terminal.writeLine(`Running command: ${command} ${args.join(' ')} in ${tmpPath}`); + this.#terminal.writeLine(`Running command: ${command} ${args.join(' ')} in ${tmpPath}`); const cp: ChildProcess = Executable.spawn(command, args, { stdio: [ @@ -213,13 +213,13 @@ export class PlaywrightTunnel { cp.stdout?.pipe( new TerminalStreamWritable({ - terminal: this._terminal, + terminal: this.#terminal, severity: TerminalProviderSeverity.log }) ); cp.stderr?.pipe( new TerminalStreamWritable({ - terminal: this._terminal, + terminal: this.#terminal, severity: TerminalProviderSeverity.error }) ); @@ -230,7 +230,7 @@ export class PlaywrightTunnel { private async _installPlaywrightCoreAsync({ playwrightVersion }: Pick): Promise { - this._terminal.writeLine(`Installing playwright-core version ${playwrightVersion}`); + this.#terminal.writeLine(`Installing playwright-core version ${playwrightVersion}`); await this._runCommandAsync('npm', [ 'install', `playwright-core-${playwrightVersion}@npm:playwright-core@${playwrightVersion}` @@ -242,7 +242,7 @@ export class PlaywrightTunnel { browserName }: Pick): Promise { await this._installPlaywrightCoreAsync({ playwrightVersion }); - this._terminal.writeLine(`Executing playwright-core version ${playwrightVersion}`); + this.#terminal.writeLine(`Executing playwright-core version ${playwrightVersion}`); await this._runCommandAsync('node', [ `node_modules/playwright-core-${playwrightVersion}/cli.js`, 'install', @@ -251,14 +251,14 @@ export class PlaywrightTunnel { } private async _tryConnectAsync(): Promise { - const wsEndpoint: string | undefined = this._wsEndpoint; + const wsEndpoint: string | undefined = this.#wsEndpoint; if (!wsEndpoint) { throw new Error('WebSocket endpoint is not defined'); } return await new Promise((resolve, reject) => { const ws: WebSocket = new WebSocket(wsEndpoint); ws.on('open', () => { - this._terminal.writeLine(`WebSocket connection opened`); + this.#terminal.writeLine(`WebSocket connection opened`); resolve(ws); }); ws.once('error', (error) => { @@ -270,48 +270,48 @@ export class PlaywrightTunnel { // TODO: Only supporting one test at a time. // Need to support multiple simultaneous connections for parallel tests. private async _pollConnectionAsync(): Promise { - this._terminal.writeLine(`Waiting for WebSocket connection`); + this.#terminal.writeLine(`Waiting for WebSocket connection`); return await new Promise((resolve, reject) => { - this._pollInterval = setInterval(() => { - if (this._pendingConnectionAttempt) { + this.#pollInterval = setInterval(() => { + if (this.#pendingConnectionAttempt) { return; // Skip if a connection attempt is already in progress } const connectionPromise: Promise = this._tryConnectAsync(); - this._pendingConnectionAttempt = connectionPromise; + this.#pendingConnectionAttempt = connectionPromise; connectionPromise .then((ws: WebSocket) => { - clearInterval(this._pollInterval); - this._pollInterval = undefined; + clearInterval(this.#pollInterval); + this.#pollInterval = undefined; ws.removeAllListeners(); - this._pendingConnectionAttempt = undefined; + this.#pendingConnectionAttempt = undefined; resolve(ws); }) .catch(() => { // no-op - will retry on next interval - this._pendingConnectionAttempt = undefined; + this.#pendingConnectionAttempt = undefined; }); }, 500); }); } private async _waitForIncomingConnectionAsync(): Promise { - this._terminal.writeLine('Waiting for incoming WebSocket connection'); + this.#terminal.writeLine('Waiting for incoming WebSocket connection'); return await new Promise((resolve, reject) => { - const server: WebSocketServer = new WebSocket.Server({ port: this._listenPort }); + const server: WebSocketServer = new WebSocket.Server({ port: this.#listenPort }); const cleanup = (): void => { server.removeAllListeners(); }; server.once('connection', (ws) => { - this._terminal.writeLine('Incoming WebSocket connection established'); + this.#terminal.writeLine('Incoming WebSocket connection established'); // Stop listening immediately so the port is released cleanup(); server.close((closeError?: Error) => { if (closeError) { - this._terminal.writeLine( + this.#terminal.writeLine( `Failed to close WebSocket server: ${ closeError instanceof Error ? closeError.message : closeError }` @@ -322,7 +322,7 @@ export class PlaywrightTunnel { }); server.once('error', (error) => { - this._terminal.writeLine(`WebSocket server error: ${getNormalizedErrorString(error)}`); + this.#terminal.writeLine(`WebSocket server error: ${getNormalizedErrorString(error)}`); cleanup(); // Try to close (best-effort), then reject @@ -339,17 +339,17 @@ export class PlaywrightTunnel { browserName }: Pick): Promise { const browserKey: string = `${playwrightVersion}-${browserName}`; - this._terminal.writeLine(`Checking for installed playwright browsers. Installed browsers: ${browserKey}`); - if (!this._playwrightBrowsersInstalled.has(browserKey)) { - this._terminal.writeLine( + this.#terminal.writeLine(`Checking for installed playwright browsers. Installed browsers: ${browserKey}`); + if (!this.#playwrightBrowsersInstalled.has(browserKey)) { + this.#terminal.writeLine( `Playwright browser not found. Installing playwright-core version ${playwrightVersion}` ); await this._installPlaywrightBrowsersAsync({ playwrightVersion, browserName }); - this._playwrightBrowsersInstalled.add(browserKey); + this.#playwrightBrowsersInstalled.add(browserKey); } - this._terminal.writeLine(`Using playwright-core version ${playwrightVersion} for browser server`); - return await import(`${this._playwrightInstallPath}/node_modules/playwright-core-${playwrightVersion}`); + this.#terminal.writeLine(`Using playwright-core version ${playwrightVersion} for browser server`); + return await import(`${this.#playwrightInstallPath}/node_modules/playwright-core-${playwrightVersion}`); } private async _getPlaywrightBrowserServerProxyAsync({ @@ -357,7 +357,7 @@ export class PlaywrightTunnel { playwrightVersion, launchOptions }: Pick): Promise { - const terminal: ITerminal = this._terminal; + const terminal: ITerminal = this.#terminal; // Validate launch options against security allowlist terminal.writeLine('Validating launch options against security allowlist...'); @@ -448,9 +448,9 @@ export class PlaywrightTunnel { // ws1 is the tunnel websocket, ws2 is the browser server websocket private async _setupForwardingAsync(ws1: WebSocket, ws2: WebSocket): Promise { - this._terminal.writeLine('Setting up message forwarding between ws1 and ws2'); - this._terminal.writeLine(` ws1 (tunnel) readyState: ${getWebSocketReadyStateString(ws1.readyState)}`); - this._terminal.writeLine(` ws2 (browser) readyState: ${getWebSocketReadyStateString(ws2.readyState)}`); + this.#terminal.writeLine('Setting up message forwarding between ws1 and ws2'); + this.#terminal.writeLine(` ws1 (tunnel) readyState: ${getWebSocketReadyStateString(ws1.readyState)}`); + this.#terminal.writeLine(` ws2 (browser) readyState: ${getWebSocketReadyStateString(ws2.readyState)}`); const messageCount: { ws1ToWs2: number; ws2ToWs1: number } = { ws1ToWs2: 0, ws2ToWs1: 0 }; @@ -459,7 +459,7 @@ export class PlaywrightTunnel { if (ws2.readyState === WebSocket.OPEN) { ws2.send(data); } else { - this._terminal.writeLine( + this.#terminal.writeLine( `ws2 not open (state: ${getWebSocketReadyStateString(ws2.readyState)}). Dropping message #${messageCount.ws1ToWs2}` ); } @@ -469,7 +469,7 @@ export class PlaywrightTunnel { if (ws1.readyState === WebSocket.OPEN) { ws1.send(data); } else { - this._terminal.writeLine( + this.#terminal.writeLine( `ws1 not open (state: ${getWebSocketReadyStateString(ws1.readyState)}). Dropping message #${messageCount.ws2ToWs1}` ); } @@ -478,39 +478,39 @@ export class PlaywrightTunnel { ws1.once('close', (code: number, reason: Buffer) => { const reasonStr: string = reason.toString() || 'no reason provided'; const codeDescription: string = getWebSocketCloseReason(code); - this._terminal.writeLine( + this.#terminal.writeLine( `ws1 (tunnel) closed - code: ${code} (${codeDescription}), reason: ${reasonStr}` ); - this._terminal.writeLine( + this.#terminal.writeLine( ` Messages forwarded: ws1->ws2: ${messageCount.ws1ToWs2}, ws2->ws1: ${messageCount.ws2ToWs1}` ); if (ws2.readyState === WebSocket.OPEN) { - this._terminal.writeLine(' Closing ws2 (browser) in response'); + this.#terminal.writeLine(' Closing ws2 (browser) in response'); ws2.close(WebSocketCloseCode.NORMAL_CLOSURE, 'Tunnel closed'); } }); ws2.once('close', (code: number, reason: Buffer) => { const reasonStr: string = reason.toString() || 'no reason provided'; const codeDescription: string = getWebSocketCloseReason(code); - this._terminal.writeLine( + this.#terminal.writeLine( `ws2 (browser) closed - code: ${code} (${codeDescription}), reason: ${reasonStr}` ); - this._terminal.writeLine( + this.#terminal.writeLine( ` Messages forwarded: ws1->ws2: ${messageCount.ws1ToWs2}, ws2->ws1: ${messageCount.ws2ToWs1}` ); if (ws1.readyState === WebSocket.OPEN) { - this._terminal.writeLine(' Closing ws1 (tunnel) in response'); + this.#terminal.writeLine(' Closing ws1 (tunnel) in response'); ws1.close(WebSocketCloseCode.NORMAL_CLOSURE, 'Browser closed'); } }); ws1.once('error', (error) => { - this._terminal.writeErrorLine(`ws1 (tunnel) WebSocket error: ${getNormalizedErrorString(error)}`); - this._terminal.writeErrorLine(` ws1 readyState: ${getWebSocketReadyStateString(ws1.readyState)}`); + this.#terminal.writeErrorLine(`ws1 (tunnel) WebSocket error: ${getNormalizedErrorString(error)}`); + this.#terminal.writeErrorLine(` ws1 readyState: ${getWebSocketReadyStateString(ws1.readyState)}`); }); ws2.once('error', (error) => { - this._terminal.writeErrorLine(`ws2 (browser) WebSocket error: ${getNormalizedErrorString(error)}`); - this._terminal.writeErrorLine(` ws2 readyState: ${getWebSocketReadyStateString(ws2.readyState)}`); + this.#terminal.writeErrorLine(`ws2 (browser) WebSocket error: ${getNormalizedErrorString(error)}`); + this.#terminal.writeErrorLine(` ws2 readyState: ${getWebSocketReadyStateString(ws2.readyState)}`); }); } @@ -526,39 +526,39 @@ export class PlaywrightTunnel { this.status = 'waiting-for-connection'; const ws: WebSocket = - this._mode === 'poll-connection' + this.#mode === 'poll-connection' ? await this._pollConnectionAsync() : await this._waitForIncomingConnectionAsync(); ws.on('open', () => { - this._terminal.writeLine(`WebSocket connection established`); + this.#terminal.writeLine(`WebSocket connection established`); handshake = undefined; }); ws.on('error', (error) => { - this._terminal.writeLine(`WebSocket error occurred: ${getNormalizedErrorString(error)}`); + this.#terminal.writeLine(`WebSocket error occurred: ${getNormalizedErrorString(error)}`); }); ws.on('close', async (code: number, reason: Buffer) => { const reasonStr: string = reason.toString() || 'no reason provided'; const codeDescription: string = getWebSocketCloseReason(code); - this._initWsPromise = undefined; + this.#initWsPromise = undefined; this.status = 'stopped'; - this._terminal.writeLine( + this.#terminal.writeLine( `WebSocket connection closed - code: ${code} (${codeDescription}), reason: ${reasonStr}` ); - this._terminal.writeLine(` handshake received: ${handshake !== undefined}`); - this._terminal.writeLine(` browserServer active: ${browserServer !== undefined}`); + this.#terminal.writeLine(` handshake received: ${handshake !== undefined}`); + this.#terminal.writeLine(` browserServer active: ${browserServer !== undefined}`); if (browserServer) { - this._terminal.writeLine(' Closing browser server...'); + this.#terminal.writeLine(' Closing browser server...'); await browserServer.close(); - this._terminal.writeLine(' Browser server closed'); + this.#terminal.writeLine(' Browser server closed'); } }); return await new Promise((resolve, reject) => { const onMessageHandler = async (data: RawData): Promise => { - const terminal: ITerminal = this._terminal; + const terminal: ITerminal = this.#terminal; if (!handshake) { try { const rawHandshakeString: string = data.toString(); @@ -567,9 +567,9 @@ export class PlaywrightTunnel { handshake = this._validateHandshake(rawHandshake); // Call the onBeforeLaunch callback if provided - if (this._onBeforeLaunch) { + if (this.#onBeforeLaunch) { terminal.writeLine('Requesting user approval before launching browser server...'); - const shouldProceed: boolean = await this._onBeforeLaunch(handshake); + const shouldProceed: boolean = await this.#onBeforeLaunch(handshake); if (!shouldProceed) { terminal.writeLine('Browser server launch cancelled by user.'); ws.off('message', onMessageHandler); diff --git a/apps/rundown/src/Rundown.ts b/apps/rundown/src/Rundown.ts index 9a4dd720817..144ba088516 100644 --- a/apps/rundown/src/Rundown.ts +++ b/apps/rundown/src/Rundown.ts @@ -12,7 +12,7 @@ import type { IpcMessage } from './LauncherTypes'; export class Rundown { // Map from required path --> caller path - private _importedModuleMap: Map = new Map(); + #importedModuleMap: Map = new Map(); public async invokeAsync( scriptPath: string, @@ -46,7 +46,7 @@ export class Rundown { console.log('Writing report file: ' + reportPath); const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); - const importedPaths: string[] = [...this._importedModuleMap.keys()]; + const importedPaths: string[] = [...this.#importedModuleMap.keys()]; const importedPackageFolders: Set = new Set(); for (const importedPath of importedPaths) { @@ -75,7 +75,7 @@ export class Rundown { const reportPath: string = 'rundown-inspect.log'; console.log('Writing report file: ' + reportPath); - const importedPaths: string[] = [...this._importedModuleMap.keys()]; + const importedPaths: string[] = [...this.#importedModuleMap.keys()]; importedPaths.sort(); let data: string = ''; @@ -87,7 +87,7 @@ export class Rundown { let current: string = importedPath; const visited: Set = new Set(); for (;;) { - const callerPath: string | undefined = this._importedModuleMap.get(current); + const callerPath: string | undefined = this.#importedModuleMap.get(current); if (!callerPath) { break; } @@ -122,7 +122,7 @@ export class Rundown { switch (message.id) { case 'trace': for (const record of message.records) { - this._importedModuleMap.set(record.importedModule, record.callingModule); + this.#importedModuleMap.set(record.importedModule, record.callingModule); } break; case 'done': diff --git a/apps/rundown/src/cli/InspectAction.ts b/apps/rundown/src/cli/InspectAction.ts index 9c14086c55e..4d31e3c402c 100644 --- a/apps/rundown/src/cli/InspectAction.ts +++ b/apps/rundown/src/cli/InspectAction.ts @@ -7,7 +7,7 @@ import { BaseReportAction } from './BaseReportAction'; import { Rundown } from '../Rundown'; export class InspectAction extends BaseReportAction { - private readonly _traceParameter: CommandLineFlagParameter; + readonly #traceParameter: CommandLineFlagParameter; public constructor() { super({ @@ -18,7 +18,7 @@ export class InspectAction extends BaseReportAction { ' to inspect performance regressions.' }); - this._traceParameter = this.defineFlagParameter({ + this.#traceParameter = this.defineFlagParameter({ parameterLongName: '--trace-imports', parameterShortName: '-t', description: 'Reports the call chain for each module path, showing how it was imported' @@ -33,6 +33,6 @@ export class InspectAction extends BaseReportAction { this.quietParameter.value, this.ignoreExitCodeParameter.value ); - rundown.writeInspectReport(this._traceParameter.value); + rundown.writeInspectReport(this.#traceParameter.value); } } diff --git a/apps/rundown/src/launcher.ts b/apps/rundown/src/launcher.ts index 63738d1bea3..18e335cb722 100644 --- a/apps/rundown/src/launcher.ts +++ b/apps/rundown/src/launcher.ts @@ -14,9 +14,9 @@ class Launcher { public action: LauncherAction = LauncherAction.Inspect; public targetScriptPathArg: string = ''; public reportPath: string = ''; - private _importedModules: Set = new Set(); - private _importedModulePaths: Set = new Set(); - private _ipcTraceRecordsBatch: IIpcTraceRecord[] = []; + #importedModules: Set = new Set(); + #importedModulePaths: Set = new Set(); + #ipcTraceRecordsBatch: IIpcTraceRecord[] = []; public transformArgs(argv: ReadonlyArray): string[] { let nodeArg: string; @@ -32,9 +32,9 @@ class Launcher { } private _sendIpcTraceBatch(): void { - if (this._ipcTraceRecordsBatch.length > 0) { - const batch: IIpcTraceRecord[] = [...this._ipcTraceRecordsBatch]; - this._ipcTraceRecordsBatch.length = 0; + if (this.#ipcTraceRecordsBatch.length > 0) { + const batch: IIpcTraceRecord[] = [...this.#ipcTraceRecordsBatch]; + this.#ipcTraceRecordsBatch.length = 0; process.send!({ id: 'trace', @@ -46,9 +46,9 @@ class Launcher { public installHook(): void { const realRequire: typeof moduleApi.Module.prototype.require = moduleApi.Module.prototype.require; - const importedModules: Set = this._importedModules; // for closure - const importedModulePaths: Set = this._importedModulePaths; // for closure - const ipcTraceRecordsBatch: IIpcTraceRecord[] = this._ipcTraceRecordsBatch; // for closure + const importedModules: Set = this.#importedModules; // for closure + const importedModulePaths: Set = this.#importedModulePaths; // for closure + const ipcTraceRecordsBatch: IIpcTraceRecord[] = this.#ipcTraceRecordsBatch; // for closure const sendIpcTraceBatch: () => void = this._sendIpcTraceBatch.bind(this); // for closure function hookedRequire(this: NodeModule, moduleName: string): unknown { diff --git a/apps/rush-mcp-server/src/pluginFramework/RushMcpPluginLoader.ts b/apps/rush-mcp-server/src/pluginFramework/RushMcpPluginLoader.ts index a760a847b0d..e0599ad3bb2 100644 --- a/apps/rush-mcp-server/src/pluginFramework/RushMcpPluginLoader.ts +++ b/apps/rush-mcp-server/src/pluginFramework/RushMcpPluginLoader.ts @@ -71,17 +71,17 @@ const _rushMcpJsonSchema: JsonSchema = JsonSchema.fromLoadedObject(rushMcpJsonSc const _rushMcpPluginSchemaObject: JsonSchema = JsonSchema.fromLoadedObject(rushMcpPluginSchemaObject); export class RushMcpPluginLoader { - private readonly _rushWorkspacePath: string; - private readonly _mcpServer: McpServer; + readonly #rushWorkspacePath: string; + readonly #mcpServer: McpServer; public constructor(rushWorkspacePath: string, mcpServer: McpServer) { - this._rushWorkspacePath = rushWorkspacePath; - this._mcpServer = mcpServer; + this.#rushWorkspacePath = rushWorkspacePath; + this.#mcpServer = mcpServer; } public async loadAsync(): Promise { const rushMcpFilePath: string = path.join( - this._rushWorkspacePath, + this.#rushWorkspacePath, 'common/config/rush-mcp/rush-mcp.json' ); @@ -90,7 +90,7 @@ export class RushMcpPluginLoader { } const rushConfiguration: RushConfiguration = RushConfiguration.loadFromDefaultLocation({ - startingFolder: this._rushWorkspacePath + startingFolder: this.#rushWorkspacePath }); const jsonRushMcpConfig: IJsonRushMcpConfig = await JsonFile.loadAndValidateAsync( @@ -144,7 +144,7 @@ export class RushMcpPluginLoader { ); const mcpPluginSchema: JsonSchema = await JsonSchema.fromFile(mcpPluginSchemaFilePath); const rushMcpPluginOptionsFilePath: string = path.resolve( - this._rushWorkspacePath, + this.#rushWorkspacePath, `common/config/rush-mcp/${jsonManifest.pluginName}.json` ); // Example: /path/to/my-repo/common/config/rush-mcp/rush-mcp-example-plugin.json @@ -166,7 +166,7 @@ export class RushMcpPluginLoader { throw new Error(`Unable to load plugin entry point at ${fullEntryPointPath}:\n` + _formatError(e)); } - const session: RushMcpPluginSessionInternal = new RushMcpPluginSessionInternal(this._mcpServer); + const session: RushMcpPluginSessionInternal = new RushMcpPluginSessionInternal(this.#mcpServer); let plugin: IRushMcpPlugin; try { diff --git a/apps/rush-mcp-server/src/pluginFramework/RushMcpPluginSession.ts b/apps/rush-mcp-server/src/pluginFramework/RushMcpPluginSession.ts index aa46003a8cf..0599f96a82d 100644 --- a/apps/rush-mcp-server/src/pluginFramework/RushMcpPluginSession.ts +++ b/apps/rush-mcp-server/src/pluginFramework/RushMcpPluginSession.ts @@ -28,23 +28,23 @@ export abstract class RushMcpPluginSession { } export class RushMcpPluginSessionInternal extends RushMcpPluginSession { - private readonly _mcpServer: McpServer; + readonly #mcpServer: McpServer; public constructor(mcpServer: McpServer) { super(); - this._mcpServer = mcpServer; + this.#mcpServer = mcpServer; } public override registerTool(options: IRegisterToolOptions, tool: IRushMcpTool): void { if (options.description) { - this._mcpServer.tool( + this.#mcpServer.tool( options.toolName, options.description, tool.schema.shape, tool.executeAsync.bind(tool) ); } else { - this._mcpServer.tool(options.toolName, tool.schema.shape, tool.executeAsync.bind(tool)); + this.#mcpServer.tool(options.toolName, tool.schema.shape, tool.executeAsync.bind(tool)); } } } diff --git a/apps/rush-mcp-server/src/server.ts b/apps/rush-mcp-server/src/server.ts index 5eceb116012..ea308253c8f 100644 --- a/apps/rush-mcp-server/src/server.ts +++ b/apps/rush-mcp-server/src/server.ts @@ -14,9 +14,9 @@ import { import { RushMcpPluginLoader } from './pluginFramework/RushMcpPluginLoader'; export class RushMCPServer extends McpServer { - private _rushWorkspacePath: string; - private _tools: BaseTool[] = []; - private _pluginLoader: RushMcpPluginLoader; + #rushWorkspacePath: string; + #tools: BaseTool[] = []; + #pluginLoader: RushMcpPluginLoader; public constructor(rushWorkspacePath: string) { super({ @@ -24,29 +24,29 @@ export class RushMCPServer extends McpServer { version: '1.0.0' }); - this._rushWorkspacePath = rushWorkspacePath; - this._pluginLoader = new RushMcpPluginLoader(this._rushWorkspacePath, this); + this.#rushWorkspacePath = rushWorkspacePath; + this.#pluginLoader = new RushMcpPluginLoader(this.#rushWorkspacePath, this); } public async startAsync(): Promise { this._initializeTools(); this._registerTools(); - await this._pluginLoader.loadAsync(); + await this.#pluginLoader.loadAsync(); } private _initializeTools(): void { - this._tools.push(new RushConflictResolverTool()); - this._tools.push(new RushMigrateProjectTool(this._rushWorkspacePath)); - this._tools.push(new RushCommandValidatorTool()); - this._tools.push(new RushWorkspaceDetailsTool()); - this._tools.push(new RushProjectDetailsTool()); + this.#tools.push(new RushConflictResolverTool()); + this.#tools.push(new RushMigrateProjectTool(this.#rushWorkspacePath)); + this.#tools.push(new RushCommandValidatorTool()); + this.#tools.push(new RushWorkspaceDetailsTool()); + this.#tools.push(new RushProjectDetailsTool()); } private _registerTools(): void { - process.chdir(this._rushWorkspacePath); + process.chdir(this.#rushWorkspacePath); - for (const tool of this._tools) { + for (const tool of this.#tools) { tool.register(this); } } diff --git a/apps/rush-mcp-server/src/tools/base.tool.ts b/apps/rush-mcp-server/src/tools/base.tool.ts index dc9b4d67bdb..b491af3975d 100644 --- a/apps/rush-mcp-server/src/tools/base.tool.ts +++ b/apps/rush-mcp-server/src/tools/base.tool.ts @@ -28,10 +28,10 @@ export interface IBaseToolOptions { } export abstract class BaseTool { - private _options: IBaseToolOptions; + #options: IBaseToolOptions; protected constructor(options: IBaseToolOptions) { - this._options = options; + this.#options = options; } protected abstract executeAsync(...args: Parameters>): ReturnType>; @@ -39,7 +39,7 @@ export abstract class BaseTool { public register(server: McpServer): void { // TODO: remove ts-ignore // @ts-ignore - server.tool(this._options.name, this._options.description, this._options.schema, async (...args) => { + server.tool(this.#options.name, this.#options.description, this.#options.schema, async (...args) => { try { const result: CallToolResult = await this.executeAsync(...(args as Parameters>)); return result; diff --git a/apps/rush-mcp-server/src/tools/migrate-project.tool.ts b/apps/rush-mcp-server/src/tools/migrate-project.tool.ts index d4069a1d79c..904d67dadc3 100644 --- a/apps/rush-mcp-server/src/tools/migrate-project.tool.ts +++ b/apps/rush-mcp-server/src/tools/migrate-project.tool.ts @@ -15,7 +15,7 @@ import { BaseTool, type CallToolResult } from './base.tool'; import { getRushConfiguration } from '../utilities/common'; export class RushMigrateProjectTool extends BaseTool { - private _rushWorkspacePath: string; + #rushWorkspacePath: string; public constructor(rushWorkspacePath: string) { super({ @@ -28,7 +28,7 @@ export class RushMigrateProjectTool extends BaseTool { } }); - this._rushWorkspacePath = rushWorkspacePath; + this.#rushWorkspacePath = rushWorkspacePath; } private async _modifyAndSaveSubspaceJsonFileAsync( @@ -81,7 +81,7 @@ export class RushMigrateProjectTool extends BaseTool { }; } - const rootPath: string = this._rushWorkspacePath; + const rootPath: string = this.#rushWorkspacePath; const sourceProjectSubspaceName: string = project.subspace.subspaceName; const sourceProjectPath: string = project.projectFolder; const destinationPath: string = path.resolve(rootPath, targetProjectPath); diff --git a/apps/rush-serve-dashboard/src/modules/ansiSgrParser.ts b/apps/rush-serve-dashboard/src/modules/ansiSgrParser.ts index 68ac598e6cd..da64c920f51 100644 --- a/apps/rush-serve-dashboard/src/modules/ansiSgrParser.ts +++ b/apps/rush-serve-dashboard/src/modules/ansiSgrParser.ts @@ -15,7 +15,7 @@ interface IAnsiState { } export class AnsiSgrParser { - private readonly _state: IAnsiState = { + readonly #state: IAnsiState = { bold: false, underline: false, inverse: false, @@ -30,7 +30,7 @@ export class AnsiSgrParser { const pushSegmentIfText = (text: string): void => { if (!text) return; - const style: string = this._ansiStateToStyle(this._state); + const style: string = this._ansiStateToStyle(this.#state); segments.push({ text, style }); }; @@ -85,33 +85,33 @@ export class AnsiSgrParser { for (const p of params) { if (p === 0) { - this._state.bold = false; - this._state.underline = false; - this._state.inverse = false; - this._state.fg = undefined; - this._state.bg = undefined; + this.#state.bold = false; + this.#state.underline = false; + this.#state.inverse = false; + this.#state.fg = undefined; + this.#state.bg = undefined; } else if (p === 1) { - this._state.bold = true; + this.#state.bold = true; } else if (p === 4) { - this._state.underline = true; + this.#state.underline = true; } else if (p === 7) { - this._state.inverse = true; + this.#state.inverse = true; } else if (p === 22) { - this._state.bold = false; + this.#state.bold = false; } else if (p === 24) { - this._state.underline = false; + this.#state.underline = false; } else if (p >= 30 && p <= 37) { - this._state.fg = this._sgrColorToCss(p - 30, false); + this.#state.fg = this._sgrColorToCss(p - 30, false); } else if (p === 39) { - this._state.fg = undefined; + this.#state.fg = undefined; } else if (p >= 40 && p <= 47) { - this._state.bg = this._sgrColorToCss(p - 40, false); + this.#state.bg = this._sgrColorToCss(p - 40, false); } else if (p === 49) { - this._state.bg = undefined; + this.#state.bg = undefined; } else if (p >= 90 && p <= 97) { - this._state.fg = this._sgrColorToCss(p - 90, true); + this.#state.fg = this._sgrColorToCss(p - 90, true); } else if (p >= 100 && p <= 107) { - this._state.bg = this._sgrColorToCss(p - 100, true); + this.#state.bg = this._sgrColorToCss(p - 100, true); } } } diff --git a/apps/rush/src/MinimalRushConfiguration.ts b/apps/rush/src/MinimalRushConfiguration.ts index 0cc4436b964..1f6923f97eb 100644 --- a/apps/rush/src/MinimalRushConfiguration.ts +++ b/apps/rush/src/MinimalRushConfiguration.ts @@ -18,13 +18,13 @@ interface IMinimalRushConfigurationJson { * decide which version of Rush should be installed/used. */ export class MinimalRushConfiguration { - private _rushVersion: string; - private _commonRushConfigFolder: string; + #rushVersion: string; + #commonRushConfigFolder: string; private constructor(minimalRushConfigurationJson: IMinimalRushConfigurationJson, rushJsonFilename: string) { - this._rushVersion = + this.#rushVersion = minimalRushConfigurationJson.rushVersion || minimalRushConfigurationJson.rushMinimumVersion; - this._commonRushConfigFolder = path.join( + this.#commonRushConfigFolder = path.join( path.dirname(rushJsonFilename), RushConstants.commonFolderName, 'config', @@ -54,7 +54,7 @@ export class MinimalRushConfiguration { * a semver style version number like "4.0.0" */ public get rushVersion(): string { - return this._rushVersion; + return this.#rushVersion; } /** @@ -66,7 +66,7 @@ export class MinimalRushConfiguration { * Example: "C:\MyRepo\common\config\rush" */ public get commonRushConfigFolder(): string { - return this._commonRushConfigFolder; + return this.#commonRushConfigFolder; } } diff --git a/apps/rush/src/RushVersionSelector.ts b/apps/rush/src/RushVersionSelector.ts index 615aaa0e356..10e391fad3d 100644 --- a/apps/rush/src/RushVersionSelector.ts +++ b/apps/rush/src/RushVersionSelector.ts @@ -15,12 +15,12 @@ import type { MinimalRushConfiguration } from './MinimalRushConfiguration'; const MAX_INSTALL_ATTEMPTS: number = 3; export class RushVersionSelector { - private _rushGlobalFolder: _RushGlobalFolder; - private _currentPackageVersion: string; + #rushGlobalFolder: _RushGlobalFolder; + #currentPackageVersion: string; public constructor(currentPackageVersion: string) { - this._rushGlobalFolder = new _RushGlobalFolder(); - this._currentPackageVersion = currentPackageVersion; + this.#rushGlobalFolder = new _RushGlobalFolder(); + this.#currentPackageVersion = currentPackageVersion; } public async ensureRushVersionInstalledAsync( @@ -29,7 +29,7 @@ export class RushVersionSelector { executeOptions: ILaunchOptions ): Promise { const isLegacyRushVersion: boolean = semver.lt(version, '4.0.0'); - const expectedRushPath: string = path.join(this._rushGlobalFolder.nodeSpecificPath, `rush-${version}`); + const expectedRushPath: string = path.join(this.#rushGlobalFolder.nodeSpecificPath, `rush-${version}`); const installMarker: _FlagFile = new _FlagFile(expectedRushPath, 'last-install', { node: process.versions.node @@ -97,7 +97,7 @@ export class RushVersionSelector { }); const rushCliEntrypoint: typeof import('@microsoft/rush-lib') = require(rushLibEntrypoint); // For newer rush-lib, RushCommandSelector can test whether "rushx" is supported or not - RushCommandSelector.execute(this._currentPackageVersion, rushCliEntrypoint, executeOptions); + RushCommandSelector.execute(this.#currentPackageVersion, rushCliEntrypoint, executeOptions); } } } diff --git a/apps/trace-import/src/TraceImportCommandLineParser.ts b/apps/trace-import/src/TraceImportCommandLineParser.ts index f34cec4a90d..a5bd3099135 100644 --- a/apps/trace-import/src/TraceImportCommandLineParser.ts +++ b/apps/trace-import/src/TraceImportCommandLineParser.ts @@ -14,10 +14,10 @@ import { Colorize } from '@rushstack/terminal'; import { type ResolutionType, traceImport } from './traceImport'; export class TraceImportCommandLineParser extends CommandLineParser { - private readonly _debugParameter: CommandLineFlagParameter; - private readonly _pathParameter: IRequiredCommandLineStringParameter; - private readonly _baseFolderParameter: CommandLineStringParameter; - private readonly _resolutionTypeParameter: IRequiredCommandLineChoiceParameter; + readonly #debugParameter: CommandLineFlagParameter; + readonly #pathParameter: IRequiredCommandLineStringParameter; + readonly #baseFolderParameter: CommandLineStringParameter; + readonly #resolutionTypeParameter: IRequiredCommandLineChoiceParameter; public constructor() { super({ @@ -30,13 +30,13 @@ export class TraceImportCommandLineParser extends CommandLineParser { 'print the .d.ts file path that would be resolved by a TypeScript import statement.' }); - this._debugParameter = this.defineFlagParameter({ + this.#debugParameter = this.defineFlagParameter({ parameterLongName: '--debug', parameterShortName: '-d', description: 'Show the full call stack if an error occurs while executing the tool' }); - this._pathParameter = this.defineStringParameter({ + this.#pathParameter = this.defineStringParameter({ parameterLongName: '--path', parameterShortName: '-p', description: @@ -46,7 +46,7 @@ export class TraceImportCommandLineParser extends CommandLineParser { required: true }); - this._baseFolderParameter = this.defineStringParameter({ + this.#baseFolderParameter = this.defineStringParameter({ parameterLongName: '--base-folder', parameterShortName: '-b', description: @@ -55,7 +55,7 @@ export class TraceImportCommandLineParser extends CommandLineParser { argumentName: 'FOLDER_PATH' }); - this._resolutionTypeParameter = this.defineChoiceParameter({ + this.#resolutionTypeParameter = this.defineChoiceParameter({ parameterLongName: '--resolution-type', parameterShortName: '-t', description: @@ -67,17 +67,17 @@ export class TraceImportCommandLineParser extends CommandLineParser { } protected override async onExecuteAsync(): Promise { - if (this._debugParameter.value) { + if (this.#debugParameter.value) { InternalError.breakInDebugger = true; } try { traceImport({ - importPath: this._pathParameter.value, - baseFolder: this._baseFolderParameter.value, - resolutionType: this._resolutionTypeParameter.value + importPath: this.#pathParameter.value, + baseFolder: this.#baseFolderParameter.value, + resolutionType: this.#resolutionTypeParameter.value }); } catch (error) { - if (this._debugParameter.value) { + if (this.#debugParameter.value) { console.error('\n' + error.stack); } else { console.error('\n' + Colorize.red('ERROR: ' + error.message.trim())); diff --git a/apps/zipsync/src/cli/ZipSyncCommandLineParser.ts b/apps/zipsync/src/cli/ZipSyncCommandLineParser.ts index 594ad4c9ab6..0b7081bf149 100644 --- a/apps/zipsync/src/cli/ZipSyncCommandLineParser.ts +++ b/apps/zipsync/src/cli/ZipSyncCommandLineParser.ts @@ -15,15 +15,15 @@ import type { IZipSyncMode, ZipSyncOptionCompression } from '../zipSyncUtils'; import { pack, unpack } from '../index'; export class ZipSyncCommandLineParser extends CommandLineParser { - private readonly _debugParameter: CommandLineFlagParameter; - private readonly _verboseParameter: CommandLineFlagParameter; - private readonly _modeParameter: IRequiredCommandLineChoiceParameter; - private readonly _archivePathParameter: IRequiredCommandLineStringParameter; - private readonly _baseDirParameter: IRequiredCommandLineStringParameter; - private readonly _targetDirectoriesParameter: CommandLineStringListParameter; - private readonly _compressionParameter: IRequiredCommandLineChoiceParameter; - private readonly _terminal: ITerminal; - private readonly _terminalProvider: ConsoleTerminalProvider; + readonly #debugParameter: CommandLineFlagParameter; + readonly #verboseParameter: CommandLineFlagParameter; + readonly #modeParameter: IRequiredCommandLineChoiceParameter; + readonly #archivePathParameter: IRequiredCommandLineStringParameter; + readonly #baseDirParameter: IRequiredCommandLineStringParameter; + readonly #targetDirectoriesParameter: CommandLineStringListParameter; + readonly #compressionParameter: IRequiredCommandLineChoiceParameter; + readonly #terminal: ITerminal; + readonly #terminalProvider: ConsoleTerminalProvider; public constructor(terminalProvider: ConsoleTerminalProvider, terminal: ITerminal) { super({ @@ -31,22 +31,22 @@ export class ZipSyncCommandLineParser extends CommandLineParser { toolDescription: '' }); - this._terminal = terminal; - this._terminalProvider = terminalProvider; + this.#terminal = terminal; + this.#terminalProvider = terminalProvider; - this._debugParameter = this.defineFlagParameter({ + this.#debugParameter = this.defineFlagParameter({ parameterLongName: '--debug', parameterShortName: '-d', description: 'Show the full call stack if an error occurs while executing the tool' }); - this._verboseParameter = this.defineFlagParameter({ + this.#verboseParameter = this.defineFlagParameter({ parameterLongName: '--verbose', parameterShortName: '-v', description: 'Show verbose output' }); - this._modeParameter = this.defineChoiceParameter({ + this.#modeParameter = this.defineChoiceParameter({ parameterLongName: '--mode', parameterShortName: '-m', description: @@ -55,7 +55,7 @@ export class ZipSyncCommandLineParser extends CommandLineParser { required: true }); - this._archivePathParameter = this.defineStringParameter({ + this.#archivePathParameter = this.defineStringParameter({ parameterLongName: '--archive-path', parameterShortName: '-a', description: 'Zip file path', @@ -63,7 +63,7 @@ export class ZipSyncCommandLineParser extends CommandLineParser { required: true }); - this._targetDirectoriesParameter = this.defineStringListParameter({ + this.#targetDirectoriesParameter = this.defineStringListParameter({ parameterLongName: '--target-directory', parameterShortName: '-t', description: 'Target directories to pack or unpack', @@ -71,7 +71,7 @@ export class ZipSyncCommandLineParser extends CommandLineParser { required: true }); - this._baseDirParameter = this.defineStringParameter({ + this.#baseDirParameter = this.defineStringParameter({ parameterLongName: '--base-dir', parameterShortName: '-b', description: 'Base directory for relative paths within the archive', @@ -79,7 +79,7 @@ export class ZipSyncCommandLineParser extends CommandLineParser { required: true }); - this._compressionParameter = this.defineChoiceParameter({ + this.#compressionParameter = this.defineChoiceParameter({ parameterLongName: '--compression', parameterShortName: '-z', description: @@ -90,34 +90,34 @@ export class ZipSyncCommandLineParser extends CommandLineParser { } protected override async onExecuteAsync(): Promise { - if (this._debugParameter.value) { + if (this.#debugParameter.value) { // eslint-disable-next-line no-debugger debugger; - this._terminalProvider.debugEnabled = true; - this._terminalProvider.verboseEnabled = true; + this.#terminalProvider.debugEnabled = true; + this.#terminalProvider.verboseEnabled = true; } - if (this._verboseParameter.value) { - this._terminalProvider.verboseEnabled = true; + if (this.#verboseParameter.value) { + this.#terminalProvider.verboseEnabled = true; } try { - if (this._modeParameter.value === 'pack') { + if (this.#modeParameter.value === 'pack') { pack({ - terminal: this._terminal, - archivePath: this._archivePathParameter.value, - targetDirectories: this._targetDirectoriesParameter.values, - baseDir: this._baseDirParameter.value, - compression: this._compressionParameter.value + terminal: this.#terminal, + archivePath: this.#archivePathParameter.value, + targetDirectories: this.#targetDirectoriesParameter.values, + baseDir: this.#baseDirParameter.value, + compression: this.#compressionParameter.value }); - } else if (this._modeParameter.value === 'unpack') { + } else if (this.#modeParameter.value === 'unpack') { unpack({ - terminal: this._terminal, - archivePath: this._archivePathParameter.value, - targetDirectories: this._targetDirectoriesParameter.values, - baseDir: this._baseDirParameter.value + terminal: this.#terminal, + archivePath: this.#archivePathParameter.value, + targetDirectories: this.#targetDirectoriesParameter.values, + baseDir: this.#baseDirParameter.value }); } } catch (error) { - this._terminal.writeErrorLine('\n' + error.stack); + this.#terminal.writeErrorLine('\n' + error.stack); } } } diff --git a/libraries/rush-daemon-transport/src/DaemonFrameConnection.ts b/libraries/rush-daemon-transport/src/DaemonFrameConnection.ts index dce6c5a545d..d1c4c690011 100644 --- a/libraries/rush-daemon-transport/src/DaemonFrameConnection.ts +++ b/libraries/rush-daemon-transport/src/DaemonFrameConnection.ts @@ -16,14 +16,14 @@ import { DaemonTransportError, DaemonTransportErrorCode } from './DaemonTranspor * slow consumer loses nothing. * @beta */ export class DaemonFrameConnection { - private readonly _socket: net.Socket; - private readonly _decoder: DaemonFrameDecoder = new DaemonFrameDecoder(); - private _frameHandler: ((frame: IDaemonFrame) => void) | undefined; - private _closedHandler: ((error: Error | undefined) => void) | undefined; - private _closedError: Error | undefined; + readonly #socket: net.Socket; + readonly #decoder: DaemonFrameDecoder = new DaemonFrameDecoder(); + #frameHandler: ((frame: IDaemonFrame) => void) | undefined; + #closedHandler: ((error: Error | undefined) => void) | undefined; + #closedError: Error | undefined; public constructor(socket: net.Socket) { - this._socket = socket; + this.#socket = socket; socket.on('data', (chunk: Buffer) => this._onData(chunk)); socket.on('error', (error: Error) => this._onError(error)); socket.on('close', () => this._onClose()); @@ -31,33 +31,33 @@ export class DaemonFrameConnection { /** Registers the frame handler invoked for each decoded frame. */ public onFrame(handler: (frame: IDaemonFrame) => void): void { - this._frameHandler = handler; + this.#frameHandler = handler; } /** Registers the close handler, invoked at most once with the cause. */ public onClosed(handler: (error: Error | undefined) => void): void { - this._closedHandler = handler; + this.#closedHandler = handler; } /** Encodes and writes a frame, resolving when the socket has drained it. @throws {@link DaemonTransportError} when closed. */ public async sendFrameAsync(frame: IDaemonFrame): Promise { this._assertOpen(); - if (!this._socket.write(encodeDaemonFrame(frame))) { - await once(this._socket, 'drain'); + if (!this.#socket.write(encodeDaemonFrame(frame))) { + await once(this.#socket, 'drain'); } } /** Half-closes the writable side and releases the socket. */ public async closeAsync(): Promise { - this._socket.end(); - this._socket.destroySoon(); + this.#socket.end(); + this.#socket.destroySoon(); } /** The wrapped socket, for the internal raw-write test hook. @internal */ public get socket(): net.Socket { - return this._socket; + return this.#socket; } private _assertOpen(): void { - if (this._closedError !== undefined || this._socket.closed) { + if (this.#closedError !== undefined || this.#socket.closed) { throw new DaemonTransportError( DaemonTransportErrorCode.transportClosed, 'Cannot send a frame on a closed connection.' @@ -68,7 +68,7 @@ export class DaemonFrameConnection { private _onData(chunk: Buffer): void { let frames: IDaemonFrame[]; try { - frames = this._decoder.push(chunk); + frames = this.#decoder.push(chunk); } catch (error) { this._fail(error); return; @@ -79,7 +79,7 @@ export class DaemonFrameConnection { } private _dispatchFrame(frame: IDaemonFrame): void { try { - this._frameHandler?.(frame); + this.#frameHandler?.(frame); } catch (error) { this._fail(error); } @@ -87,14 +87,14 @@ export class DaemonFrameConnection { private _fail(error: unknown): void { const cause: Error = error instanceof Error ? error : new Error(String(error)); - this._closedError = this._closedError ?? cause; - this._socket.destroy(cause); + this.#closedError = this.#closedError ?? cause; + this.#socket.destroy(cause); } private _onError(error: Error): void { - this._closedError = this._closedError ?? error; + this.#closedError = this.#closedError ?? error; } private _onClose(): void { - this._closedHandler?.(this._closedError); + this.#closedHandler?.(this.#closedError); } } diff --git a/libraries/rush-daemon-transport/src/DaemonListener.ts b/libraries/rush-daemon-transport/src/DaemonListener.ts index f4b17aefb43..30e55b7d630 100644 --- a/libraries/rush-daemon-transport/src/DaemonListener.ts +++ b/libraries/rush-daemon-transport/src/DaemonListener.ts @@ -33,11 +33,11 @@ export interface IDaemonListenerOptions { * `daemonAlreadyRunning` transport error is thrown. * @beta */ export class DaemonFrameListener { - private readonly _server: net.Server; - private readonly _paths: IDaemonPaths; + readonly #server: net.Server; + readonly #paths: IDaemonPaths; private constructor(server: net.Server, paths: IDaemonPaths) { - this._server = server; - this._paths = paths; + this.#server = server; + this.#paths = paths; } /** Binds the socket/pipe path and writes the PID lockfile. */ public static async listenAsync( @@ -62,8 +62,8 @@ export class DaemonFrameListener { /** Stops accepting connections and releases the socket/pipe and lockfile. */ public async closeAsync(): Promise { - await new Promise((resolve: () => void) => this._server.close(() => resolve())); - removeDaemonArtifacts(this._paths.lockfilePath, this._paths.socketPath); + await new Promise((resolve: () => void) => this.#server.close(() => resolve())); + removeDaemonArtifacts(this.#paths.lockfilePath, this.#paths.socketPath); } } diff --git a/libraries/rush-daemon/src/DaemonControlSession.ts b/libraries/rush-daemon/src/DaemonControlSession.ts index 85c38211322..9d0fe45f996 100644 --- a/libraries/rush-daemon/src/DaemonControlSession.ts +++ b/libraries/rush-daemon/src/DaemonControlSession.ts @@ -27,20 +27,20 @@ export interface IDaemonControlSessionOptions { } export class DaemonControlSession { - private readonly _connection: DaemonFrameConnection; - private readonly _options: IDaemonControlSessionOptions; - private _handshakeComplete: boolean = false; - private _sendQueue: Promise = Promise.resolve(); + readonly #connection: DaemonFrameConnection; + readonly #options: IDaemonControlSessionOptions; + #handshakeComplete: boolean = false; + #sendQueue: Promise = Promise.resolve(); public constructor(connection: DaemonFrameConnection, options: IDaemonControlSessionOptions) { - this._connection = connection; - this._options = options; + this.#connection = connection; + this.#options = options; connection.onFrame((frame: IDaemonFrame) => this._onFrame(frame)); connection.onClosed((error: Error | undefined) => options.onClosed(this, error)); } public closeAsync(): Promise { - return this._connection.closeAsync(); + return this.#connection.closeAsync(); } private _onFrame(frame: IDaemonFrame): void { @@ -51,7 +51,7 @@ export class DaemonControlSession { ); } const message: DaemonControlMessage = decodeDaemonControlMessage(frame.payload); - if (!this._handshakeComplete) { + if (!this.#handshakeComplete) { this._handleHello(message); } else if (message.kind === 'ping') { this._send(this._createPong()); @@ -76,7 +76,7 @@ export class DaemonControlSession { randomUUID() ); if (outcome.accepted) { - this._handshakeComplete = true; + this.#handshakeComplete = true; this._send(outcome.ack); } else { const errorMessage: IDaemonErrorMessage = { @@ -91,9 +91,9 @@ export class DaemonControlSession { return { kind: 'pong', payload: { - daemonVersion: this._options.daemonVersion, + daemonVersion: this.#options.daemonVersion, protocolVersion: DAEMON_PROTOCOL_VERSION, - uptimeMs: Date.now() - this._options.startedAtMs + uptimeMs: Date.now() - this.#options.startedAtMs } }; } @@ -103,15 +103,15 @@ export class DaemonControlSession { kind: DaemonFrameType.controlJson, payload: encodeDaemonControlMessage(message) }; - this._sendQueue = this._sendQueue - .then(() => this._connection.sendFrameAsync(frame)) - .then(() => (closeAfterSend ? this._connection.closeAsync() : undefined)) + this.#sendQueue = this.#sendQueue + .then(() => this.#connection.sendFrameAsync(frame)) + .then(() => (closeAfterSend ? this.#connection.closeAsync() : undefined)) .catch((error: unknown) => this._handleSendErrorAsync(error)); } private async _handleSendErrorAsync(error: unknown): Promise { const normalizedError: Error = error instanceof Error ? error : new Error(String(error)); - this._options.onError(normalizedError); - await this._connection.closeAsync(); + this.#options.onError(normalizedError); + await this.#connection.closeAsync(); } } diff --git a/libraries/rush-daemon/src/RequestScheduler.ts b/libraries/rush-daemon/src/RequestScheduler.ts index 7548ac7819c..6f34310715d 100644 --- a/libraries/rush-daemon/src/RequestScheduler.ts +++ b/libraries/rush-daemon/src/RequestScheduler.ts @@ -101,22 +101,22 @@ interface IQueuedRequest { * @public */ export class RequestScheduler { - private readonly _queue: IQueuedRequest[] = []; - private _activeClass: RequestExclusivityClass | undefined; - private _activeRequestCount: number = 0; + readonly #queue: IQueuedRequest[] = []; + #activeClass: RequestExclusivityClass | undefined; + #activeRequestCount: number = 0; /** * The number of requests currently waiting for admission. */ public get queuedRequestCount(): number { - return this._queue.length; + return this.#queue.length; } /** * The number of requests that currently hold a lease. */ public get activeRequestCount(): number { - return this._activeRequestCount; + return this.#activeRequestCount; } /** @@ -135,7 +135,7 @@ export class RequestScheduler { ); } - if (this._queue.length === 0 && this._canAdmit(options.exclusivityClass)) { + if (this.#queue.length === 0 && this._canAdmit(options.exclusivityClass)) { return Promise.resolve(this._createLease(options.exclusivityClass)); } @@ -178,7 +178,7 @@ export class RequestScheduler { }; options.abortSignal.addEventListener('abort', request.abortListener, { once: true }); } - this._queue.push(request); + this.#queue.push(request); this._notifyQueuePositions(); this._drainQueue(); }); @@ -196,18 +196,18 @@ export class RequestScheduler { } private _canAdmit(exclusivityClass: RequestExclusivityClass): boolean { - if (this._activeRequestCount === 0) { + if (this.#activeRequestCount === 0) { return true; } return ( - exclusivityClass !== RequestExclusivityClass.Exclusive && exclusivityClass === this._activeClass + exclusivityClass !== RequestExclusivityClass.Exclusive && exclusivityClass === this.#activeClass ); } private _createLease(exclusivityClass: RequestExclusivityClass): IRequestLease { - this._activeClass = exclusivityClass; - this._activeRequestCount++; + this.#activeClass = exclusivityClass; + this.#activeRequestCount++; let released: boolean = false; return { @@ -218,9 +218,9 @@ export class RequestScheduler { } released = true; - this._activeRequestCount--; - if (this._activeRequestCount === 0) { - this._activeClass = undefined; + this.#activeRequestCount--; + if (this.#activeRequestCount === 0) { + this.#activeClass = undefined; } this._drainQueue(); } @@ -229,13 +229,13 @@ export class RequestScheduler { private _drainQueue(): void { let admittedRequest: boolean = false; - while (this._queue.length > 0) { - const request: IQueuedRequest = this._queue[0]; + while (this.#queue.length > 0) { + const request: IQueuedRequest = this.#queue[0]; if (!this._canAdmit(request.options.exclusivityClass)) { break; } - this._queue.shift(); + this.#queue.shift(); this._cleanupQueuedRequest(request); request.resolve(this._createLease(request.options.exclusivityClass)); admittedRequest = true; @@ -247,12 +247,12 @@ export class RequestScheduler { } private _rejectQueuedRequest(request: IQueuedRequest, error: Error): void { - const index: number = this._queue.indexOf(request); + const index: number = this.#queue.indexOf(request); if (index < 0) { return; } - this._queue.splice(index, 1); + this.#queue.splice(index, 1); this._cleanupQueuedRequest(request); request.reject(error); this._notifyQueuePositions(); @@ -271,9 +271,9 @@ export class RequestScheduler { } private _notifyQueuePositions(): void { - for (let index: number = 0; index < this._queue.length; index++) { + for (let index: number = 0; index < this.#queue.length; index++) { try { - this._queue[index].options.onQueuePositionChanged?.(index + 1); + this.#queue[index].options.onQueuePositionChanged?.(index + 1); } catch (error) { process.emitWarning(error instanceof Error ? error : String(error), { code: 'RUSH_DAEMON_QUEUE_POSITION_CALLBACK_ERROR' diff --git a/libraries/rush-daemon/src/RushDaemonHost.ts b/libraries/rush-daemon/src/RushDaemonHost.ts index f3a9cd42510..87501bd8941 100644 --- a/libraries/rush-daemon/src/RushDaemonHost.ts +++ b/libraries/rush-daemon/src/RushDaemonHost.ts @@ -40,11 +40,11 @@ export interface IRushDaemonHostOptions { * @beta */ export class RushDaemonHost { - private readonly _listener: DaemonFrameListener; - private readonly _sessions: Set; - private readonly _lifecycle: { closing: boolean }; + readonly #listener: DaemonFrameListener; + readonly #sessions: Set; + readonly #lifecycle: { closing: boolean }; public readonly paths: IDaemonPaths; - private _closePromise: Promise | undefined; + #closePromise: Promise | undefined; private constructor( listener: DaemonFrameListener, @@ -52,10 +52,10 @@ export class RushDaemonHost { sessions: Set, lifecycle: { closing: boolean } ) { - this._listener = listener; + this.#listener = listener; this.paths = paths; - this._sessions = sessions; - this._lifecycle = lifecycle; + this.#sessions = sessions; + this.#lifecycle = lifecycle; } /** Resolves only after the transport is bound and its lockfile has been written. */ @@ -96,13 +96,13 @@ export class RushDaemonHost { /** Closes active connections, stops listening, and removes transport artifacts. */ public closeAsync(): Promise { - this._closePromise ??= this._closeOnceAsync(); - return this._closePromise; + this.#closePromise ??= this._closeOnceAsync(); + return this.#closePromise; } private async _closeOnceAsync(): Promise { - this._lifecycle.closing = true; - await Promise.all(Array.from(this._sessions, (session: DaemonControlSession) => session.closeAsync())); - await this._listener.closeAsync(); + this.#lifecycle.closing = true; + await Promise.all(Array.from(this.#sessions, (session: DaemonControlSession) => session.closeAsync())); + await this.#listener.closeAsync(); } } diff --git a/libraries/rush-terminal-renderer/src/DaemonRendererHost.ts b/libraries/rush-terminal-renderer/src/DaemonRendererHost.ts index cf024c7c033..aba20f2e7e5 100644 --- a/libraries/rush-terminal-renderer/src/DaemonRendererHost.ts +++ b/libraries/rush-terminal-renderer/src/DaemonRendererHost.ts @@ -31,22 +31,22 @@ const CHUNK_DECODER: InstanceType = new TextDecoder('utf8', * @beta */ export class DaemonRendererHost { - private readonly _renderer: IDaemonRenderer; - private readonly _verbosity: DaemonVerbosity; - private readonly _streams: OperationStreamRegistry; - private readonly _router: HostEventRouter; - private readonly _terminal: IDaemonRendererTerminal; + readonly #renderer: IDaemonRenderer; + readonly #verbosity: DaemonVerbosity; + readonly #streams: OperationStreamRegistry; + readonly #router: HostEventRouter; + readonly #terminal: IDaemonRendererTerminal; public constructor(options: IDaemonRendererHostOptions) { - this._terminal = options.terminal; - this._verbosity = options.verbosity ?? DEFAULT_VERBOSITY; - this._renderer = options.renderer ?? new LegacyCollatedRenderer(); - this._streams = new OperationStreamRegistry({ + this.#terminal = options.terminal; + this.#verbosity = options.verbosity ?? DEFAULT_VERBOSITY; + this.#renderer = options.renderer ?? new LegacyCollatedRenderer(); + this.#streams = new OperationStreamRegistry({ destination: new TerminalSinkWritable(options.terminal), removeColors: shouldRemoveColors(options.colorLevel), - quiet: this._verbosity === QUIET_VERBOSITY + quiet: this.#verbosity === QUIET_VERBOSITY }); - this._router = new HostEventRouter(this._streams, this._renderer, this._verbosity); + this.#router = new HostEventRouter(this.#streams, this.#renderer, this.#verbosity); } /** @@ -54,22 +54,22 @@ export class DaemonRendererHost { * {@link DaemonRendererHost.handleEvent} call. */ public async initializeAsync(): Promise { - await this._renderer.initializeAsync({ terminal: this._terminal }); + await this.#renderer.initializeAsync({ terminal: this.#terminal }); } /** Feeds one decoded `0x05` event envelope into the host. */ public handleEvent(envelope: IDaemonEventEnvelope): void { - this._router.routeEvent(envelope); + this.#router.routeEvent(envelope); } /** Feeds one decoded `0x02`/`0x03` log chunk into the collator. */ public handleLogChunk(operationId: string, stream: 'stdout' | 'stderr', chunk: Uint8Array): void { - if (stream === 'stdout' && this._verbosity === QUIET_VERBOSITY) { + if (stream === 'stdout' && this.#verbosity === QUIET_VERBOSITY) { // Match the legacy quiet-mode DiscardStdoutTransform: per-client display // filtering, without mutating the shared stream. return; } - this._streams.writeChunk(operationId, { + this.#streams.writeChunk(operationId, { kind: toChunkKind(stream), text: CHUNK_DECODER.decode(chunk) }); @@ -77,7 +77,7 @@ export class DaemonRendererHost { /** Flushes and closes the renderer. */ public async closeAsync(): Promise { - await this._renderer.flushAsync(); - await this._renderer.closeAsync(); + await this.#renderer.flushAsync(); + await this.#renderer.closeAsync(); } } diff --git a/libraries/rush-terminal-renderer/src/HostEventRouter.ts b/libraries/rush-terminal-renderer/src/HostEventRouter.ts index a5a81ba1676..ec57ea77ed0 100644 --- a/libraries/rush-terminal-renderer/src/HostEventRouter.ts +++ b/libraries/rush-terminal-renderer/src/HostEventRouter.ts @@ -26,18 +26,18 @@ function readScopeOperationId(envelope: IDaemonEventEnvelope): string | undefine * @internal */ export class HostEventRouter { - private readonly _streams: OperationStreamRegistry; - private readonly _renderer: IDaemonRenderer; - private readonly _verbosity: DaemonVerbosity; + readonly #streams: OperationStreamRegistry; + readonly #renderer: IDaemonRenderer; + readonly #verbosity: DaemonVerbosity; public constructor( streams: OperationStreamRegistry, renderer: IDaemonRenderer, verbosity: DaemonVerbosity ) { - this._streams = streams; - this._renderer = renderer; - this._verbosity = verbosity; + this.#streams = streams; + this.#renderer = renderer; + this.#verbosity = verbosity; } /** Routes one decoded `0x05` event envelope. */ @@ -46,8 +46,8 @@ export class HostEventRouter { if (this._routeScopedActivity(envelope)) { return; } - if (shouldSerializeDaemonEvent(this._verbosity, envelope)) { - this._renderer.report(envelope); + if (shouldSerializeDaemonEvent(this.#verbosity, envelope)) { + this.#renderer.report(envelope); } } @@ -62,7 +62,7 @@ export class HostEventRouter { private _trackRegistered(payload: IDaemonOperationRegisteredPayload): void { if (!payload.silent) { - this._streams.registerOperation(); + this.#streams.registerOperation(); } } @@ -70,7 +70,7 @@ export class HostEventRouter { if (payload.name === RUSHD_OPERATION_STREAM_CLOSED) { const data: IDaemonOperationStreamClosedPayload = payload.data as IDaemonOperationStreamClosedPayload; - this._streams.closeOperation(data.operationId); + this.#streams.closeOperation(data.operationId); } } @@ -91,7 +91,7 @@ export class HostEventRouter { const text: unknown = (activity as { text?: unknown }).text; const stream: unknown = (activity as { stream?: unknown }).stream; if (typeof text === 'string') { - this._streams.writeChunk(operationId, { + this.#streams.writeChunk(operationId, { kind: stream === 'stderr' ? TerminalChunkKind.Stderr : TerminalChunkKind.Stdout, text: `${text}\n` }); diff --git a/libraries/rush-terminal-renderer/src/LegacyCollatedRenderer.ts b/libraries/rush-terminal-renderer/src/LegacyCollatedRenderer.ts index 85b86607524..9275e93c25b 100644 --- a/libraries/rush-terminal-renderer/src/LegacyCollatedRenderer.ts +++ b/libraries/rush-terminal-renderer/src/LegacyCollatedRenderer.ts @@ -32,11 +32,11 @@ function isActivityPayload(payload: unknown): payload is IDaemonActivityPayload */ export class LegacyCollatedRenderer implements IDaemonRenderer { public readonly name: string = RENDERER_NAME; - private _terminal: IDaemonRendererTerminal | undefined; + #terminal: IDaemonRendererTerminal | undefined; /** {@inheritDoc IDaemonRenderer.initializeAsync} */ public async initializeAsync(context: IDaemonRendererContext): Promise { - this._terminal = context.terminal; + this.#terminal = context.terminal; } /** {@inheritDoc IDaemonRenderer.report} */ @@ -51,7 +51,7 @@ export class LegacyCollatedRenderer implements IDaemonRenderer { // Emit the client's OS newline, matching the newline normalization the // collated pipeline applies (TextRewriterTransform OsDefault) so global // status lines and collated blocks are consistent on every platform. - this._terminal?.write(`${text}${EOL}`, 'stdout'); + this.#terminal?.write(`${text}${EOL}`, 'stdout'); } /** {@inheritDoc IDaemonRenderer.flushAsync} */ @@ -61,6 +61,6 @@ export class LegacyCollatedRenderer implements IDaemonRenderer { /** {@inheritDoc IDaemonRenderer.closeAsync} */ public async closeAsync(): Promise { - this._terminal = undefined; + this.#terminal = undefined; } } diff --git a/libraries/rush-terminal-renderer/src/OperationStreamRegistry.ts b/libraries/rush-terminal-renderer/src/OperationStreamRegistry.ts index d761d07a556..a77b59c2eed 100644 --- a/libraries/rush-terminal-renderer/src/OperationStreamRegistry.ts +++ b/libraries/rush-terminal-renderer/src/OperationStreamRegistry.ts @@ -27,25 +27,25 @@ export interface IOperationStreamRegistryOptions { * @beta */ export class OperationStreamRegistry { - private readonly _collator: StreamCollator; - private readonly _collatedTerminal: CollatedTerminal; - private readonly _writers: Map; - private readonly _quiet: boolean; - private _completedOperations: number; - private _totalOperations: number; + readonly #collator: StreamCollator; + readonly #collatedTerminal: CollatedTerminal; + readonly #writers: Map; + readonly #quiet: boolean; + #completedOperations: number; + #totalOperations: number; public constructor(options: IOperationStreamRegistryOptions) { - this._writers = new Map(); - this._quiet = options.quiet; - this._completedOperations = 0; - this._totalOperations = 0; + this.#writers = new Map(); + this.#quiet = options.quiet; + this.#completedOperations = 0; + this.#totalOperations = 0; const transform: TextRewriterTransform = new TextRewriterTransform({ destination: options.destination, normalizeNewlines: NewlineKind.OsDefault, removeColors: options.removeColors }); - this._collatedTerminal = new CollatedTerminal(transform); - this._collator = new StreamCollator({ + this.#collatedTerminal = new CollatedTerminal(transform); + this.#collator = new StreamCollator({ destination: transform, onWriterActive: (writer: CollatedWriter | undefined) => this._onWriterActive(writer) }); @@ -53,22 +53,22 @@ export class OperationStreamRegistry { /** Increments the total-operation count shown in headers. */ public registerOperation(): void { - this._totalOperations += 1; + this.#totalOperations += 1; } /** Writes one raw chunk to the operation's collated stream. */ public writeChunk(operationId: string, chunk: ITerminalChunk): void { - let writer: CollatedWriter | undefined = this._writers.get(operationId); + let writer: CollatedWriter | undefined = this.#writers.get(operationId); if (writer === undefined) { - writer = this._collator.registerTask(operationId); - this._writers.set(operationId, writer); + writer = this.#collator.registerTask(operationId); + this.#writers.set(operationId, writer); } writer.writeChunk(chunk); } /** Closes the operation's stream, flushing its collated output. */ public closeOperation(operationId: string): void { - const writer: CollatedWriter | undefined = this._writers.get(operationId); + const writer: CollatedWriter | undefined = this.#writers.get(operationId); if (writer !== undefined && writer.isOpen) { writer.close(); } @@ -78,15 +78,15 @@ export class OperationStreamRegistry { if (writer === undefined) { return; } - this._completedOperations += 1; + this.#completedOperations += 1; const header: string = formatDaemonOperationHeader( writer.taskName, - this._completedOperations, - this._totalOperations + this.#completedOperations, + this.#totalOperations ); - this._collatedTerminal.writeStdoutLine(`\n${header}`); - if (!this._quiet) { - this._collatedTerminal.writeStdoutLine(''); + this.#collatedTerminal.writeStdoutLine(`\n${header}`); + if (!this.#quiet) { + this.#collatedTerminal.writeStdoutLine(''); } } } diff --git a/libraries/rush-terminal-renderer/src/TerminalSinkWritable.ts b/libraries/rush-terminal-renderer/src/TerminalSinkWritable.ts index 6ff84cdd5d4..73ecb3f0324 100644 --- a/libraries/rush-terminal-renderer/src/TerminalSinkWritable.ts +++ b/libraries/rush-terminal-renderer/src/TerminalSinkWritable.ts @@ -12,15 +12,15 @@ import type { IDaemonRendererTerminal } from './DaemonRendererTerminal'; * @beta */ export class TerminalSinkWritable extends TerminalWritable { - private readonly _terminal: IDaemonRendererTerminal; + readonly #terminal: IDaemonRendererTerminal; public constructor(terminal: IDaemonRendererTerminal) { super({ preventAutoclose: true }); - this._terminal = terminal; + this.#terminal = terminal; } /** {@inheritDoc @rushstack/terminal#TerminalWritable.onWriteChunk} */ public onWriteChunk(chunk: ITerminalChunk): void { - this._terminal.write(chunk.text, chunk.kind === TerminalChunkKind.Stderr ? 'stderr' : 'stdout'); + this.#terminal.write(chunk.text, chunk.kind === TerminalChunkKind.Stderr ? 'stderr' : 'stdout'); } } diff --git a/libraries/rush-terminal-renderer/src/test/LegacyPipelineReplica.ts b/libraries/rush-terminal-renderer/src/test/LegacyPipelineReplica.ts index 38318c06c56..72c13d0324c 100644 --- a/libraries/rush-terminal-renderer/src/test/LegacyPipelineReplica.ts +++ b/libraries/rush-terminal-renderer/src/test/LegacyPipelineReplica.ts @@ -28,25 +28,25 @@ const LEGACY_MIN_MIDDLE: number = 0; /** Replicates the legacy in-process collated output pipeline. */ export class LegacyPipelineReplica { - private readonly _collator: StreamCollator; - private readonly _terminal: CollatedTerminal; - private readonly _writers: Map; - private readonly _quiet: boolean; - private readonly _total: number; - private _completed: number; + readonly #collator: StreamCollator; + readonly #terminal: CollatedTerminal; + readonly #writers: Map; + readonly #quiet: boolean; + readonly #total: number; + #completed: number; public constructor(destination: TerminalWritable, totalOperations: number, quiet: boolean) { - this._writers = new Map(); - this._quiet = quiet; - this._total = totalOperations; - this._completed = INITIAL_COUNT; + this.#writers = new Map(); + this.#quiet = quiet; + this.#total = totalOperations; + this.#completed = INITIAL_COUNT; const transform: TextRewriterTransform = new TextRewriterTransform({ destination, normalizeNewlines: NewlineKind.OsDefault, removeColors: true }); - this._terminal = new CollatedTerminal(transform); - this._collator = new StreamCollator({ + this.#terminal = new CollatedTerminal(transform); + this.#collator = new StreamCollator({ destination: transform, onWriterActive: (writer: CollatedWriter | undefined) => this._legacyOnWriterActive(writer) }); @@ -57,20 +57,20 @@ export class LegacyPipelineReplica { if (this._isDiscarded(chunk)) { return; } - let writer: CollatedWriter | undefined = this._writers.get(operationId); + let writer: CollatedWriter | undefined = this.#writers.get(operationId); if (writer === undefined) { - writer = this._collator.registerTask(operationId); - this._writers.set(operationId, writer); + writer = this.#collator.registerTask(operationId); + this.#writers.set(operationId, writer); } writer.writeChunk(chunk); } private _isDiscarded(chunk: ITerminalChunk): boolean { - return this._quiet && chunk.kind === TerminalChunkKind.Stdout; + return this.#quiet && chunk.kind === TerminalChunkKind.Stdout; } public closeOperation(operationId: string): void { - const writer: CollatedWriter | undefined = this._writers.get(operationId); + const writer: CollatedWriter | undefined = this.#writers.get(operationId); if (writer !== undefined && writer.isOpen) { writer.close(); } @@ -80,11 +80,11 @@ export class LegacyPipelineReplica { if (!writer) { return; } - this._completed += 1; + this.#completed += 1; const leftPart: string = Colorize.gray('==[') + ' ' + Colorize.cyan(writer.taskName) + ' '; const leftPartLength: number = LEGACY_LEFT_BRACKET_CHARS + writer.taskName.length + LEGACY_NAME_PADDING; - const completedOfTotal: string = `${this._completed} of ${this._total}`; + const completedOfTotal: string = `${this.#completed} of ${this.#total}`; const rightPart: string = ' ' + Colorize.white(completedOfTotal) + ' ' + Colorize.gray(']=='); const rightPartLength: number = LEGACY_COUNT_PADDING + completedOfTotal.length + LEGACY_RIGHT_BRACKET_CHARS; const middleLength: number = Math.max( @@ -92,9 +92,9 @@ export class LegacyPipelineReplica { LEGACY_MIN_MIDDLE ); const middlePart: string = Colorize.gray(']' + '='.repeat(middleLength) + '['); - this._terminal.writeStdoutLine('\n' + leftPart + middlePart + rightPart); - if (!this._quiet) { - this._terminal.writeStdoutLine(''); + this.#terminal.writeStdoutLine('\n' + leftPart + middlePart + rightPart); + if (!this.#quiet) { + this.#terminal.writeStdoutLine(''); } } } diff --git a/libraries/rush-terminal-renderer/src/test/TestTerminal.ts b/libraries/rush-terminal-renderer/src/test/TestTerminal.ts index ebf6cadf4b8..7f5da3d39f1 100644 --- a/libraries/rush-terminal-renderer/src/test/TestTerminal.ts +++ b/libraries/rush-terminal-renderer/src/test/TestTerminal.ts @@ -41,10 +41,10 @@ export class CollectingWritable extends TerminalWritable { export class TestTerminal implements IDaemonRendererTerminal { public readonly columns: number = DEFAULT_TEST_COLUMNS; public readonly isTTY: boolean = false; - private readonly _writes: [DaemonRenderStream, string][] = []; + readonly #writes: [DaemonRenderStream, string][] = []; public write(text: string, stream: DaemonRenderStream): void { - this._writes.push([stream, text]); + this.#writes.push([stream, text]); } /** All stdout text written so far, concatenated. */ @@ -58,7 +58,7 @@ export class TestTerminal implements IDaemonRendererTerminal { } private _collect(stream: DaemonRenderStream): string { - return this._writes + return this.#writes .filter(([s]: [DaemonRenderStream, string]) => s === stream) .map(([, text]: [DaemonRenderStream, string]) => text) .join(''); diff --git a/libraries/rushell/src/Parser.ts b/libraries/rushell/src/Parser.ts index c72f3f47914..45e8f6dc88e 100644 --- a/libraries/rushell/src/Parser.ts +++ b/libraries/rushell/src/Parser.ts @@ -6,12 +6,12 @@ import { type Tokenizer, type Token, TokenKind } from './Tokenizer'; import { type AstNode, AstScript, AstCommand, AstCompoundWord, AstText } from './AstNode'; export class Parser { - private readonly _tokenizer: Tokenizer; - private _peekedToken: Token | undefined; + readonly #tokenizer: Tokenizer; + #peekedToken: Token | undefined; public constructor(tokenizer: Tokenizer) { - this._tokenizer = tokenizer; - this._peekedToken = undefined; + this.#tokenizer = tokenizer; + this.#peekedToken = undefined; } public parse(): AstScript { @@ -108,19 +108,19 @@ export class Parser { } private _readToken(): Token { - if (this._peekedToken) { - const token: Token = this._peekedToken; - this._peekedToken = undefined; + if (this.#peekedToken) { + const token: Token = this.#peekedToken; + this.#peekedToken = undefined; return token; } else { - return this._tokenizer.readToken(); + return this.#tokenizer.readToken(); } } private _peekToken(): Token { - if (!this._peekedToken) { - this._peekedToken = this._tokenizer.readToken(); + if (!this.#peekedToken) { + this.#peekedToken = this.#tokenizer.readToken(); } - return this._peekedToken; + return this.#peekedToken; } } diff --git a/libraries/rushell/src/Tokenizer.ts b/libraries/rushell/src/Tokenizer.ts index 269f4937785..da4a97382e1 100644 --- a/libraries/rushell/src/Tokenizer.ts +++ b/libraries/rushell/src/Tokenizer.ts @@ -63,7 +63,7 @@ const variableCharacterRegExp: RegExp = /[a-z0-9_]/i; export class Tokenizer { public readonly input: TextRange; - private _currentIndex: number; + #currentIndex: number; public constructor(input: TextRange | string) { if (typeof input === 'string') { @@ -71,17 +71,17 @@ export class Tokenizer { } else { this.input = input; } - this._currentIndex = this.input.pos; + this.#currentIndex = this.input.pos; } public get currentIndex(): number { - return this._currentIndex; + return this.#currentIndex; } public readToken(): Token { const input: TextRange = this.input; - const startIndex: number = this._currentIndex; + const startIndex: number = this.#currentIndex; const firstChar: string | undefined = this._peekCharacter(); // Reached end of input yet? @@ -97,7 +97,7 @@ export class Tokenizer { this._readCharacter(); } - return new Token(TokenKind.Spaces, input.getNewRange(startIndex, this._currentIndex)); + return new Token(TokenKind.Spaces, input.getNewRange(startIndex, this.#currentIndex)); } // Is it a newline? @@ -106,10 +106,10 @@ export class Tokenizer { if (this._peekCharacter() === '\n') { this._readCharacter(); } - return new Token(TokenKind.NewLine, input.getNewRange(startIndex, this._currentIndex)); + return new Token(TokenKind.NewLine, input.getNewRange(startIndex, this.#currentIndex)); } else if (firstChar === '\n') { this._readCharacter(); - return new Token(TokenKind.NewLine, input.getNewRange(startIndex, this._currentIndex)); + return new Token(TokenKind.NewLine, input.getNewRange(startIndex, this.#currentIndex)); } // Is it a double-quoted string? @@ -122,13 +122,13 @@ export class Tokenizer { if (c === undefined) { throw new ParseError( 'The double-quoted string is missing the ending quote', - input.getNewRange(startIndex, this._currentIndex) + input.getNewRange(startIndex, this.#currentIndex) ); } if (c === '\r' || c === '\n') { throw new ParseError( 'Newlines are not supported inside strings', - input.getNewRange(this._currentIndex, this._currentIndex + 1) + input.getNewRange(this.#currentIndex, this.#currentIndex + 1) ); } @@ -145,7 +145,7 @@ export class Tokenizer { if (this._peekCharacter() === undefined) { throw new ParseError( 'A backslash must be followed by another character', - input.getNewRange(this._currentIndex, this._currentIndex + 1) + input.getNewRange(this.#currentIndex, this.#currentIndex + 1) ); } // Add the escaped character @@ -158,7 +158,7 @@ export class Tokenizer { } this._readCharacter(); // consume the closing quote - return new Token(TokenKind.DoubleQuotedText, input.getNewRange(startIndex, this._currentIndex), text); + return new Token(TokenKind.DoubleQuotedText, input.getNewRange(startIndex, this.#currentIndex), text); } // Is it a text token? @@ -171,7 +171,7 @@ export class Tokenizer { if (this._peekCharacter() === undefined) { throw new ParseError( 'A backslash must be followed by another character', - input.getNewRange(this._currentIndex, this._currentIndex + 1) + input.getNewRange(this.#currentIndex, this.#currentIndex + 1) ); } // Add the escaped character @@ -183,7 +183,7 @@ export class Tokenizer { c = this._peekCharacter(); } while (c && textCharacterRegExp.test(c)); - return new Token(TokenKind.Text, input.getNewRange(startIndex, this._currentIndex), text); + return new Token(TokenKind.Text, input.getNewRange(startIndex, this.#currentIndex), text); } // Is it a dollar variable? The valid environment variable names are [A-Z_][A-Z0-9_]* @@ -194,7 +194,7 @@ export class Tokenizer { if (!startVariableCharacterRegExp.test(name)) { throw new ParseError( 'The "$" symbol must be followed by a letter or underscore', - input.getNewRange(startIndex, this._currentIndex) + input.getNewRange(startIndex, this.#currentIndex) ); } @@ -203,7 +203,7 @@ export class Tokenizer { name += this._readCharacter(); c = this._peekCharacter(); } - return new Token(TokenKind.DollarVariable, input.getNewRange(startIndex, this._currentIndex), name); + return new Token(TokenKind.DollarVariable, input.getNewRange(startIndex, this.#currentIndex), name); } // Is it the "&&" token? @@ -211,13 +211,13 @@ export class Tokenizer { if (this._peekCharacterAfter() === '&') { this._readCharacter(); this._readCharacter(); - return new Token(TokenKind.AndIf, input.getNewRange(startIndex, this._currentIndex)); + return new Token(TokenKind.AndIf, input.getNewRange(startIndex, this.#currentIndex)); } } // Otherwise treat it as an "other" character this._readCharacter(); - return new Token(TokenKind.OtherCharacter, input.getNewRange(startIndex, this._currentIndex)); + return new Token(TokenKind.OtherCharacter, input.getNewRange(startIndex, this.#currentIndex)); } public readTokens(): Token[] { @@ -235,10 +235,10 @@ export class Tokenizer { * @returns a string of length 1, or undefined if the end of input is reached */ private _readCharacter(): string | undefined { - if (this._currentIndex >= this.input.end) { + if (this.#currentIndex >= this.input.end) { return undefined; } - return this.input.buffer[this._currentIndex++]; + return this.input.buffer[this.#currentIndex++]; } /** @@ -246,10 +246,10 @@ export class Tokenizer { * @returns a string of length 1, or undefined if the end of input is reached */ private _peekCharacter(): string | undefined { - if (this._currentIndex >= this.input.end) { + if (this.#currentIndex >= this.input.end) { return undefined; } - return this.input.buffer[this._currentIndex]; + return this.input.buffer[this.#currentIndex]; } /** @@ -257,10 +257,10 @@ export class Tokenizer { * @returns a string of length 1, or undefined if the end of input is reached */ private _peekCharacterAfter(): string | undefined { - if (this._currentIndex + 1 >= this.input.end) { + if (this.#currentIndex + 1 >= this.input.end) { return undefined; } - return this.input.buffer[this._currentIndex + 1]; + return this.input.buffer[this.#currentIndex + 1]; } } diff --git a/repo-scripts/repo-toolbox/src/cli/actions/BumpDecoupledLocalDependencies.ts b/repo-scripts/repo-toolbox/src/cli/actions/BumpDecoupledLocalDependencies.ts index dd0b2ac40b0..c109fdc282f 100644 --- a/repo-scripts/repo-toolbox/src/cli/actions/BumpDecoupledLocalDependencies.ts +++ b/repo-scripts/repo-toolbox/src/cli/actions/BumpDecoupledLocalDependencies.ts @@ -38,7 +38,7 @@ interface IProjectLike { } export class BumpDecoupledLocalDependencies extends CommandLineAction { - private readonly _terminal: ITerminal; + readonly #terminal: ITerminal; public constructor(terminal: ITerminal) { super({ @@ -47,11 +47,11 @@ export class BumpDecoupledLocalDependencies extends CommandLineAction { documentation: '' }); - this._terminal = terminal; + this.#terminal = terminal; } protected override async onExecuteAsync(): Promise { - const terminal: ITerminal = this._terminal; + const terminal: ITerminal = this.#terminal; const rushConfiguration: RushConfiguration = RushConfiguration.loadFromDefaultLocation({ startingFolder: process.cwd() }); diff --git a/repo-scripts/repo-toolbox/src/cli/actions/CollectProjectFilesAction.ts b/repo-scripts/repo-toolbox/src/cli/actions/CollectProjectFilesAction.ts index 3ca761c423c..b8c57854af6 100644 --- a/repo-scripts/repo-toolbox/src/cli/actions/CollectProjectFilesAction.ts +++ b/repo-scripts/repo-toolbox/src/cli/actions/CollectProjectFilesAction.ts @@ -46,10 +46,10 @@ async function* _getFolderItemsRecursiveAsync( } export class CollectProjectFilesAction extends CommandLineAction { - private readonly _outputPathParameter: IRequiredCommandLineStringParameter; - private readonly _subfolderParameter: IRequiredCommandLineStringParameter; + readonly #outputPathParameter: IRequiredCommandLineStringParameter; + readonly #subfolderParameter: IRequiredCommandLineStringParameter; - private readonly _terminal: ITerminal; + readonly #terminal: ITerminal; public constructor(terminal: ITerminal) { super({ @@ -60,16 +60,16 @@ export class CollectProjectFilesAction extends CommandLineAction { ' deduplicates by relative path and content, and writes them to the output directory.' }); - this._terminal = terminal; + this.#terminal = terminal; - this._subfolderParameter = this.defineStringParameter({ + this.#subfolderParameter = this.defineStringParameter({ parameterLongName: '--subfolder', description: 'The subfolder within each project to collect files from (e.g. "temp/json-schemas").', argumentName: 'SUBFOLDER', required: true }); - this._outputPathParameter = this.defineStringParameter({ + this.#outputPathParameter = this.defineStringParameter({ parameterLongName: '--output-path', description: 'Path to the output directory for the collected files.', argumentName: 'PATH', @@ -78,11 +78,11 @@ export class CollectProjectFilesAction extends CommandLineAction { } protected override async onExecuteAsync(): Promise { - const terminal: ITerminal = this._terminal; + const terminal: ITerminal = this.#terminal; const rushConfiguration: RushConfiguration = RushConfiguration.loadFromDefaultLocation(); - const subfolder: string = this._subfolderParameter.value; - const outputPath: string = path.resolve(this._outputPathParameter.value); + const subfolder: string = this.#subfolderParameter.value; + const outputPath: string = path.resolve(this.#outputPathParameter.value); const contentByAbsolutePathByRelativePath: Map> = new Map(); diff --git a/repo-scripts/repo-toolbox/src/cli/actions/ReadmeAction.ts b/repo-scripts/repo-toolbox/src/cli/actions/ReadmeAction.ts index 13cf6bdf913..da437d1f15f 100644 --- a/repo-scripts/repo-toolbox/src/cli/actions/ReadmeAction.ts +++ b/repo-scripts/repo-toolbox/src/cli/actions/ReadmeAction.ts @@ -14,9 +14,9 @@ const GENERATED_PROJECT_SUMMARY_END_COMMENT_TEXT: string = '