diff --git a/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts b/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts index 8ab77d46808..fb15b8008f8 100644 --- a/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts +++ b/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts @@ -63,18 +63,18 @@ export interface IApiExtractorTaskConfiguration { } export default class ApiExtractorPlugin implements IHeftTaskPlugin { - private _apiExtractor: typeof TApiExtractor | undefined; - private _apiExtractorConfigurationFilePath: string | undefined | typeof UNINITIALIZED = UNINITIALIZED; - private _printedWatchWarning: boolean = false; + #apiExtractor: typeof TApiExtractor | undefined; + #apiExtractorConfigurationFilePath: string | undefined | typeof UNINITIALIZED = UNINITIALIZED; + #printedWatchWarning: boolean = false; public apply(taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void { const runAsync = async ( runOptions: IHeftTaskRunHookOptions & Partial ): Promise => { const result: IApiExtractorConfigurationResult | undefined = - await this._getApiExtractorConfigurationAsync(taskSession, heftConfiguration); + await this.#getApiExtractorConfigurationAsync(taskSession, heftConfiguration); if (result) { - await this._runApiExtractorAsync( + await this.#runApiExtractorAsync( taskSession, heftConfiguration, runOptions, @@ -88,19 +88,19 @@ export default class ApiExtractorPlugin implements IHeftTaskPlugin { taskSession.hooks.runIncremental.tapPromise(PLUGIN_NAME, runAsync); } - private async _getApiExtractorConfigurationFilePathAsync( + async #getApiExtractorConfigurationFilePathAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration ): Promise { - if (this._apiExtractorConfigurationFilePath === UNINITIALIZED) { - this._apiExtractorConfigurationFilePath = + if (this.#apiExtractorConfigurationFilePath === UNINITIALIZED) { + this.#apiExtractorConfigurationFilePath = await heftConfiguration.rigConfig.tryResolveConfigFilePathAsync(EXTRACTOR_CONFIG_RELATIVE_PATH); - if (this._apiExtractorConfigurationFilePath === undefined) { - this._apiExtractorConfigurationFilePath = + if (this.#apiExtractorConfigurationFilePath === undefined) { + this.#apiExtractorConfigurationFilePath = await heftConfiguration.rigConfig.tryResolveConfigFilePathAsync( LEGACY_EXTRACTOR_CONFIG_RELATIVE_PATH ); - if (this._apiExtractorConfigurationFilePath !== undefined) { + if (this.#apiExtractorConfigurationFilePath !== undefined) { taskSession.logger.emitWarning( new Error( `The "${LEGACY_EXTRACTOR_CONFIG_RELATIVE_PATH}" configuration file path is not supported ` + @@ -110,10 +110,10 @@ export default class ApiExtractorPlugin implements IHeftTaskPlugin { } } } - return this._apiExtractorConfigurationFilePath; + return this.#apiExtractorConfigurationFilePath; } - private async _getApiExtractorConfigurationAsync( + async #getApiExtractorConfigurationAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, ignoreMissingEntryPoint?: boolean @@ -122,14 +122,14 @@ export default class ApiExtractorPlugin implements IHeftTaskPlugin { // including support for rig.json. However, Heft does not load the @microsoft/api-extractor package at all // unless it sees a config/api-extractor.json file. Thus we need to do our own lookup here. const apiExtractorConfigurationFilePath: string | undefined = - await this._getApiExtractorConfigurationFilePathAsync(taskSession, heftConfiguration); + await this.#getApiExtractorConfigurationFilePathAsync(taskSession, heftConfiguration); if (!apiExtractorConfigurationFilePath) { return undefined; } // Since the config file exists, we can assume that API Extractor is available. Attempt to resolve // and import the package. If the resolution fails, a helpful error is thrown. - const apiExtractorPackage: typeof TApiExtractor = await this._getApiExtractorPackageAsync( + const apiExtractorPackage: typeof TApiExtractor = await this.#getApiExtractorPackageAsync( taskSession, heftConfiguration ); @@ -149,21 +149,21 @@ export default class ApiExtractorPlugin implements IHeftTaskPlugin { return { apiExtractorPackage, apiExtractorConfiguration }; } - private async _getApiExtractorPackageAsync( + async #getApiExtractorPackageAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration ): Promise { - if (!this._apiExtractor) { + if (!this.#apiExtractor) { const apiExtractorPackagePath: string = await heftConfiguration.rigPackageResolver.resolvePackageAsync( '@microsoft/api-extractor', taskSession.logger.terminal ); - this._apiExtractor = (await import(apiExtractorPackagePath)) as typeof TApiExtractor; + this.#apiExtractor = (await import(apiExtractorPackagePath)) as typeof TApiExtractor; } - return this._apiExtractor; + return this.#apiExtractor; } - private async _runApiExtractorAsync( + async #runApiExtractorAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, runOptions: IHeftTaskRunHookOptions & Partial, @@ -181,8 +181,8 @@ export default class ApiExtractorPlugin implements IHeftTaskPlugin { if (runOptions.requestRun) { if (!runInWatchMode) { - if (!this._printedWatchWarning) { - this._printedWatchWarning = true; + if (!this.#printedWatchWarning) { + this.#printedWatchWarning = true; taskSession.logger.terminal.writeWarningLine( "API Extractor isn't currently enabled in watch mode." ); diff --git a/heft-plugins/heft-jest-plugin/src/HeftJestReporter.ts b/heft-plugins/heft-jest-plugin/src/HeftJestReporter.ts index 3f4e7089c3c..7d32a4c9ca8 100644 --- a/heft-plugins/heft-jest-plugin/src/HeftJestReporter.ts +++ b/heft-plugins/heft-jest-plugin/src/HeftJestReporter.ts @@ -35,21 +35,21 @@ export interface IHeftJestReporterOptions { * https://github.com/facebook/jest/blob/main/packages/jest-reporters/src/default_reporter.ts */ export default class HeftJestReporter implements Reporter { - private _terminal: ITerminal; - private _buildFolderPath: string; - private _debugMode: boolean; + #terminal: ITerminal; + #buildFolderPath: string; + #debugMode: boolean; public constructor(jestConfig: Config.GlobalConfig, options: IHeftJestReporterOptions) { - this._terminal = options.logger.terminal; - this._buildFolderPath = options.heftConfiguration.buildFolderPath; - this._debugMode = options.debugMode; + this.#terminal = options.logger.terminal; + this.#buildFolderPath = options.heftConfiguration.buildFolderPath; + this.#debugMode = options.debugMode; } // eslint-disable-next-line @typescript-eslint/naming-convention public async onTestStart(test: Test): Promise { - this._terminal.writeLine( + this.#terminal.writeLine( Colorize.whiteBackground(Colorize.black('START')), - ` ${this._getTestPath(test.path)}` + ` ${this.#getTestPath(test.path)}` ); } @@ -59,7 +59,7 @@ export default class HeftJestReporter implements Reporter { testResult: TestResult, aggregatedResult: AggregatedResult ): Promise { - this._writeConsoleOutput(testResult); + this.#writeConsoleOutput(testResult); const { numPassingTests, numFailingTests, @@ -80,39 +80,39 @@ export default class HeftJestReporter implements Reporter { const memUsage: string = memoryUsage ? `, ${Math.floor(memoryUsage / 1000000)}MB heap size` : ''; const message: string = - ` ${this._getTestPath(test.path)} ` + + ` ${this.#getTestPath(test.path)} ` + `(duration: ${duration}, ${numPassingTests} passed, ${numFailingTests} failed${memUsage})`; if (numFailingTests > 0) { - this._terminal.writeLine(Colorize.redBackground(Colorize.black('FAIL')), message); + this.#terminal.writeLine(Colorize.redBackground(Colorize.black('FAIL')), message); } else if (testExecError) { - this._terminal.writeLine( + this.#terminal.writeLine( Colorize.redBackground(Colorize.black(`FAIL (${testExecError.type})`)), message ); } else { - this._terminal.writeLine(Colorize.greenBackground(Colorize.black('PASS')), message); + this.#terminal.writeLine(Colorize.greenBackground(Colorize.black('PASS')), message); } if (failureMessage) { - this._terminal.writeErrorLine(failureMessage); + this.#terminal.writeErrorLine(failureMessage); } if (updatedSnapshots) { - this._terminal.writeErrorLine( - `Updated ${this._formatWithPlural(updatedSnapshots, 'snapshot', 'snapshots')}` + this.#terminal.writeErrorLine( + `Updated ${this.#formatWithPlural(updatedSnapshots, 'snapshot', 'snapshots')}` ); } if (addedSnapshots) { - this._terminal.writeErrorLine( - `Added ${this._formatWithPlural(addedSnapshots, 'snapshot', 'snapshots')}` + this.#terminal.writeErrorLine( + `Added ${this.#formatWithPlural(addedSnapshots, 'snapshot', 'snapshots')}` ); } if (uncheckedSnapshots) { - this._terminal.writeWarningLine( - `${this._formatWithPlural(uncheckedSnapshots, 'snapshot was', 'snapshots were')} not checked` + this.#terminal.writeWarningLine( + `${this.#formatWithPlural(uncheckedSnapshots, 'snapshot was', 'snapshots were')} not checked` ); } } @@ -122,30 +122,30 @@ export default class HeftJestReporter implements Reporter { // a build failure and searching its log output for errors. To reduce confusion, we add a prefix // like "|console.error|" to each output line, to clearly distinguish test logging from regular // task output. You can suppress test logging entirely using the "--silent" CLI parameter. - private _writeConsoleOutput(testResult: TestResult): void { + #writeConsoleOutput(testResult: TestResult): void { if (testResult.console) { for (const logEntry of testResult.console) { switch (logEntry.type) { case 'debug': - this._writeConsoleOutputWithLabel('console.debug', logEntry.message); + this.#writeConsoleOutputWithLabel('console.debug', logEntry.message); break; case 'log': - this._writeConsoleOutputWithLabel('console.log', logEntry.message); + this.#writeConsoleOutputWithLabel('console.log', logEntry.message); break; case 'warn': - this._writeConsoleOutputWithLabel('console.warn', logEntry.message); + this.#writeConsoleOutputWithLabel('console.warn', logEntry.message); break; case 'error': - this._writeConsoleOutputWithLabel('console.error', logEntry.message); + this.#writeConsoleOutputWithLabel('console.error', logEntry.message); break; case 'info': - this._writeConsoleOutputWithLabel('console.info', logEntry.message); + this.#writeConsoleOutputWithLabel('console.info', logEntry.message); break; case 'groupCollapsed': - if (this._debugMode) { + if (this.#debugMode) { // The "groupCollapsed" name is too long - this._writeConsoleOutputWithLabel('collapsed', logEntry.message); + this.#writeConsoleOutputWithLabel('collapsed', logEntry.message); } break; @@ -155,8 +155,8 @@ export default class HeftJestReporter implements Reporter { case 'dirxml': case 'group': case 'time': - if (this._debugMode) { - this._writeConsoleOutputWithLabel( + if (this.#debugMode) { + this.#writeConsoleOutputWithLabel( logEntry.type, `(${logEntry.type}) ${logEntry.message}`, true @@ -172,7 +172,7 @@ export default class HeftJestReporter implements Reporter { } } - private _writeConsoleOutputWithLabel(label: string, message: string, debug?: boolean): void { + #writeConsoleOutputWithLabel(label: string, message: string, debug?: boolean): void { if (message === '') { return; } @@ -185,7 +185,7 @@ export default class HeftJestReporter implements Reporter { const prefix: string = debug ? Colorize.yellow(paddedLabel) : Colorize.cyan(paddedLabel); for (const line of lines) { - this._terminal.writeLine(prefix, ' ' + line); + this.#terminal.writeLine(prefix, ' ' + line); } } @@ -196,9 +196,9 @@ export default class HeftJestReporter implements Reporter { ): Promise { // Jest prints some text that changes the console's color without a newline, so we reset the console's color here // and print a newline. - this._terminal.writeLine('\u001b[0m'); - this._terminal.writeLine( - `Run start. ${this._formatWithPlural(aggregatedResult.numTotalTestSuites, 'test suite', 'test suites')}` + this.#terminal.writeLine('\u001b[0m'); + this.#terminal.writeLine( + `Run start. ${this.#formatWithPlural(aggregatedResult.numTotalTestSuites, 'test suite', 'test suites')}` ); } @@ -212,37 +212,37 @@ export default class HeftJestReporter implements Reporter { snapshot: { uncheckedKeysByFile: uncheckedSnapshotsByFile } } = results; - this._terminal.writeLine(); - this._terminal.writeLine('Tests finished:'); + this.#terminal.writeLine(); + this.#terminal.writeLine('Tests finished:'); const successesText: string = ` Successes: ${numPassedTests}`; - this._terminal.writeLine(numPassedTests > 0 ? Colorize.green(successesText) : successesText); + this.#terminal.writeLine(numPassedTests > 0 ? Colorize.green(successesText) : successesText); const failText: string = ` Failures: ${numFailedTests}`; - this._terminal.writeLine(numFailedTests > 0 ? Colorize.red(failText) : failText); + this.#terminal.writeLine(numFailedTests > 0 ? Colorize.red(failText) : failText); if (numRuntimeErrorTestSuites) { - this._terminal.writeLine(Colorize.red(` Failed test suites: ${numRuntimeErrorTestSuites}`)); + this.#terminal.writeLine(Colorize.red(` Failed test suites: ${numRuntimeErrorTestSuites}`)); } if (uncheckedSnapshotsByFile.length > 0) { - this._terminal.writeWarningLine( + this.#terminal.writeWarningLine( ` Test suites with unchecked snapshots: ${uncheckedSnapshotsByFile.length}` ); } - this._terminal.writeLine(` Total: ${numTotalTests}`); + this.#terminal.writeLine(` Total: ${numTotalTests}`); } public getLastError(): void { // This reporter doesn't have any errors to throw } - private _getTestPath(fullTestPath: string): string { - return path.relative(this._buildFolderPath, fullTestPath); + #getTestPath(fullTestPath: string): string { + return path.relative(this.#buildFolderPath, fullTestPath); } - private _formatWithPlural(num: number, singular: string, plural: string): string { + #formatWithPlural(num: number, singular: string, plural: string): string { return `${num} ${num === 1 ? singular : plural}`; } } diff --git a/heft-plugins/heft-jest-plugin/src/JestPlugin.ts b/heft-plugins/heft-jest-plugin/src/JestPlugin.ts index 6ad53a10a48..32eefb41729 100644 --- a/heft-plugins/heft-jest-plugin/src/JestPlugin.ts +++ b/heft-plugins/heft-jest-plugin/src/JestPlugin.ts @@ -142,21 +142,21 @@ interface IPendingTestRun { * @internal */ export default class JestPlugin implements IHeftTaskPlugin { - private _jestPromise: Promise | undefined; - private _pendingTestRuns: Set = new Set(); - private _executing: boolean = false; + #jestPromise: Promise | undefined; + #pendingTestRuns: Set = new Set(); + #executing: boolean = false; - private _jestOutputStream: TerminalWritableStream | undefined; - private _changedFiles: Set = new Set(); - private _requestRun!: () => void; - private _nodeEnvSet: boolean | undefined; + #jestOutputStream: TerminalWritableStream | undefined; + #changedFiles: Set = new Set(); + #requestRun!: () => void; + #nodeEnvSet: boolean | undefined; - private _resolveFirstRunQueued!: () => void; - private _firstRunQueuedPromise: Promise; + #resolveFirstRunQueued!: () => void; + #firstRunQueuedPromise: Promise; public constructor() { - this._firstRunQueuedPromise = new Promise((resolve) => { - this._resolveFirstRunQueued = resolve; + this.#firstRunQueuedPromise = new Promise((resolve) => { + this.#resolveFirstRunQueued = resolve; }); } @@ -228,13 +228,13 @@ export default class JestPlugin implements IHeftTaskPlugin { }; taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { - await this._runJestAsync(taskSession, heftConfiguration, options); + await this.#runJestAsync(taskSession, heftConfiguration, options); }); taskSession.hooks.runIncremental.tapPromise( PLUGIN_NAME, async (runIncrementalOptions: IHeftTaskRunIncrementalHookOptions) => { - await this._runJestWatchAsync( + await this.#runJestWatchAsync( taskSession, heftConfiguration, options, @@ -247,7 +247,7 @@ export default class JestPlugin implements IHeftTaskPlugin { /** * Runs Jest using the provided options. */ - private async _runJestAsync( + async #runJestAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, options: IJestPluginOptions @@ -255,13 +255,13 @@ export default class JestPlugin implements IHeftTaskPlugin { const logger: IScopedLogger = taskSession.logger; const terminal: ITerminal = logger.terminal; - this._setNodeEnvIfRequested(options, logger); + this.#setNodeEnvIfRequested(options, logger); const { getVersion, runCLI } = await import(`@jest/core`); terminal.writeLine(`Using Jest version ${getVersion()}`); const buildFolderPath: string = heftConfiguration.buildFolderPath; - const jestArgv: Config.Argv | undefined = await this._createJestArgvAsync( + const jestArgv: Config.Argv | undefined = await this.#createJestArgvAsync( taskSession, heftConfiguration, options, @@ -279,7 +279,7 @@ export default class JestPlugin implements IHeftTaskPlugin { results: jestResults } = await runCLI(jestArgv, [buildFolderPath]); - this._resetNodeEnv(); + this.#resetNodeEnv(); if (jestResults.numFailedTests > 0) { logger.emitError( @@ -301,7 +301,7 @@ export default class JestPlugin implements IHeftTaskPlugin { /** * Runs Jest using the provided options. */ - private async _runJestWatchAsync( + async #runJestWatchAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, options: IJestPluginOptions, @@ -310,10 +310,10 @@ export default class JestPlugin implements IHeftTaskPlugin { const logger: IScopedLogger = taskSession.logger; const terminal: ITerminal = logger.terminal; - const pendingTestRuns: Set = this._pendingTestRuns; - this._requestRun = requestRun; + const pendingTestRuns: Set = this.#pendingTestRuns; + this.#requestRun = requestRun; - if (!this._jestPromise) { + if (!this.#jestPromise) { // Monkey-patch Jest's watch mode so that we can orchestrate it. const jestCoreDir: string = path.dirname(require.resolve('@jest/core')); @@ -349,7 +349,7 @@ export default class JestPlugin implements IHeftTaskPlugin { }); const wrappedStdOut: TerminalWritableStream = new TerminalWritableStream(terminal); - this._jestOutputStream = wrappedStdOut; + this.#jestOutputStream = wrappedStdOut; // Shim watch so that we can intercept the output stream const watchModulePath: string = path.resolve(jestCoreDir, 'watch.js'); @@ -381,7 +381,7 @@ export default class JestPlugin implements IHeftTaskPlugin { hasteMap.on('change', ({ eventsQueue }: { eventsQueue: { filePath: string }[] }) => { for (const file of eventsQueue) { // Record all changed files for the next test run - host._changedFiles.add(file.filePath); + host.#changedFiles.add(file.filePath); } }); }); @@ -389,7 +389,7 @@ export default class JestPlugin implements IHeftTaskPlugin { return originalWatch( initialGlobalConfig, contexts, - host._jestOutputStream as unknown as NodeJS.WriteStream, + host.#jestOutputStream as unknown as NodeJS.WriteStream, hasteMapInstances, stdin, hooks, @@ -418,23 +418,23 @@ export default class JestPlugin implements IHeftTaskPlugin { throw new Error(`Patched Jest expected JestPlugin on globalConfig`); } - if (!host._executing) { - host._requestRun(); + if (!host.#executing) { + host.#requestRun(); } return new Promise((resolve: () => void, reject: (err: Error) => void) => { - host._pendingTestRuns.add(async (): Promise => { + host.#pendingTestRuns.add(async (): Promise => { let result: AggregatedResult | undefined; const { onComplete } = params; - const findRelatedTests: boolean = params.globalConfig.onlyChanged && host._changedFiles.size > 0; + const findRelatedTests: boolean = params.globalConfig.onlyChanged && host.#changedFiles.size > 0; const globalConfig: IRunJestParams['globalConfig'] = Object.freeze({ ...params.globalConfig, // Use the knowledge of changed files to implement the "onlyChanged" behavior via // findRelatedTests and the list of changed files findRelatedTests, - nonFlagArgs: findRelatedTests ? Array.from(host._changedFiles) : [], + nonFlagArgs: findRelatedTests ? Array.from(host.#changedFiles) : [], // This property can only be true when the files are tracked directly by Git // Since we run tests on compiled files, this is not the case. onlyChanged: false @@ -457,7 +457,7 @@ export default class JestPlugin implements IHeftTaskPlugin { return result; }); - host._resolveFirstRunQueued(); + host.#resolveFirstRunQueued(); }); }; @@ -471,29 +471,29 @@ export default class JestPlugin implements IHeftTaskPlugin { terminal.writeLine(`Using Jest version ${getVersion()}`); const buildFolderPath: string = heftConfiguration.buildFolderPath; - const jestArgv: Config.Argv | undefined = await this._createJestArgvAsync( + const jestArgv: Config.Argv | undefined = await this.#createJestArgvAsync( taskSession, heftConfiguration, options, true ); if (!jestArgv) { - this._jestPromise = Promise.resolve(); + this.#jestPromise = Promise.resolve(); return; } - this._jestPromise = runCLI(jestArgv, [buildFolderPath]); + this.#jestPromise = runCLI(jestArgv, [buildFolderPath]); } // Wait for the initial run to be queued. - await this._firstRunQueuedPromise; + await this.#firstRunQueuedPromise; // Explicitly wait an async tick for any file watchers await Promise.resolve(); if (pendingTestRuns.size > 0) { - this._setNodeEnvIfRequested(options, logger); + this.#setNodeEnvIfRequested(options, logger); - this._executing = true; + this.#executing = true; for (const pendingTestRun of pendingTestRuns) { pendingTestRuns.delete(pendingTestRun); const jestResults: AggregatedResult | undefined = await pendingTestRun(); @@ -518,21 +518,21 @@ export default class JestPlugin implements IHeftTaskPlugin { } } - this._resetNodeEnv(); + this.#resetNodeEnv(); if (!logger.hasErrors) { // If we ran tests and they succeeded, consider the files to no longer be changed. // This might be overly-permissive, but there isn't a great way to identify if the changes // are no longer relevant, unfortunately. - this._changedFiles.clear(); + this.#changedFiles.clear(); } - this._executing = false; + this.#executing = false; } else { terminal.writeLine(`No pending test runs.`); } } - private async _createJestArgvAsync( + async #createJestArgvAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, options: IJestPluginOptions, @@ -796,7 +796,7 @@ export default class JestPlugin implements IHeftTaskPlugin { return _jestConfigurationFileLoader; } - private _setNodeEnvIfRequested(options: IJestPluginOptions, logger: IScopedLogger): void { + #setNodeEnvIfRequested(options: IJestPluginOptions, logger: IScopedLogger): void { if (options.enableNodeEnvManagement) { if (process.env.NODE_ENV) { if (process.env.NODE_ENV !== 'test') { @@ -807,14 +807,14 @@ export default class JestPlugin implements IHeftTaskPlugin { } } else { process.env.NODE_ENV = 'test'; - this._nodeEnvSet = true; + this.#nodeEnvSet = true; } } } - private _resetNodeEnv(): void { + #resetNodeEnv(): void { // unset the NODE_ENV only if we have set it - if (this._nodeEnvSet) { + if (this.#nodeEnvSet) { delete process.env.NODE_ENV; } } diff --git a/heft-plugins/heft-jest-plugin/src/TerminalWritableStream.ts b/heft-plugins/heft-jest-plugin/src/TerminalWritableStream.ts index 285bd520478..75acf1f6040 100644 --- a/heft-plugins/heft-jest-plugin/src/TerminalWritableStream.ts +++ b/heft-plugins/heft-jest-plugin/src/TerminalWritableStream.ts @@ -12,7 +12,7 @@ import type { ITerminal } from '@rushstack/terminal'; const FILTER_REGEX: RegExp = /\x1B\[2J\x1B\[0f|\x1B\[2J\x1B\[3J\x1B\[H/g; export class TerminalWritableStream extends Writable { - private readonly _terminal: ITerminal; + readonly #terminal: ITerminal; public constructor(terminal: ITerminal) { super({ @@ -21,14 +21,14 @@ export class TerminalWritableStream extends Writable { defaultEncoding: 'utf-8' }); - this._terminal = terminal; + this.#terminal = terminal; } // eslint-disable-next-line @typescript-eslint/no-explicit-any public _write(chunk: any, encoding: string, callback: (error?: Error | undefined) => void): void { const stringified: string = typeof chunk === 'string' ? chunk : chunk.toString(encoding); const filtered: string = stringified.replace(FILTER_REGEX, ''); - this._terminal.write(filtered); + this.#terminal.write(filtered); callback(); } } diff --git a/heft-plugins/heft-lint-plugin/src/Eslint.ts b/heft-plugins/heft-lint-plugin/src/Eslint.ts index aea83cbee8d..81ca9c87ac9 100644 --- a/heft-plugins/heft-lint-plugin/src/Eslint.ts +++ b/heft-plugins/heft-lint-plugin/src/Eslint.ts @@ -83,18 +83,18 @@ const ESLINT_LEGACY_CONFIG_FILENAMES: Set = new Set([ ]); export class Eslint extends LinterBase { - private readonly _eslintPackage: typeof TEslint | typeof TEslintLegacy; - private readonly _eslintPackageVersion: semver.SemVer; - private readonly _linter: TEslint.ESLint | TEslintLegacy.ESLint; - private readonly _eslintTimings: Map = new Map(); - private readonly _currentFixMessages: (TEslint.Linter.LintMessage | TEslintLegacy.Linter.LintMessage)[] = + readonly #eslintPackage: typeof TEslint | typeof TEslintLegacy; + readonly #eslintPackageVersion: semver.SemVer; + readonly #linter: TEslint.ESLint | TEslintLegacy.ESLint; + readonly #eslintTimings: Map = new Map(); + readonly #currentFixMessages: (TEslint.Linter.LintMessage | TEslintLegacy.Linter.LintMessage)[] = []; - private readonly _fixMessagesByResult: Map< + readonly #fixMessagesByResult: Map< TEslint.ESLint.LintResult | TEslintLegacy.ESLint.LintResult, (TEslint.Linter.LintMessage | TEslintLegacy.Linter.LintMessage)[] > = new Map(); - private readonly _sarifLogPath: string | undefined; - private readonly _configHashMap: WeakMap = new WeakMap(); + readonly #sarifLogPath: string | undefined; + readonly #configHashMap: WeakMap = new WeakMap(); protected constructor(options: IEslintOptions) { super('eslint', options); @@ -108,16 +108,16 @@ export class Eslint extends LinterBase= 9 && + this.#eslintPackageVersion.major >= 9 && ESLINT_LEGACY_CONFIG_FILENAMES.has(linterConfigFileName) ) { throw new Error( @@ -127,7 +127,7 @@ export class Eslint extends LinterBase; @@ -137,10 +137,10 @@ export class Eslint extends LinterBase { - this._currentFixMessages.push(message); + this.#currentFixMessages.push(message); return true; }; - } else if (this._eslintPackageVersion.major <= 8) { + } else if (this.#eslintPackageVersion.major <= 8) { // The @typescript-eslint/parser package allows providing an existing TypeScript program to avoid needing // to reparse. However, fixers in ESLint run in multiple passes against the underlying code until the // fix fully succeeds. This conflicts with providing an existing program as the code no longer maps to @@ -161,7 +161,7 @@ export class Eslint extends LinterBase { - return `${this._eslintPackageVersion.version}_${process.version}`; + return `${this.#eslintPackageVersion.version}_${process.version}`; } protected override async getSourceFileHashAsync(sourceFile: IExtendedSourceFile): Promise { - const sourceFileEslintConfiguration: TEslint.Linter.Config = await this._linter.calculateConfigForFile( + const sourceFileEslintConfiguration: TEslint.Linter.Config = await this.#linter.calculateConfigForFile( sourceFile.fileName ); @@ -275,15 +275,15 @@ export class Eslint extends LinterBase { const lintResults: TEslint.ESLint.LintResult[] | TEslintLegacy.ESLint.LintResult[] = - await this._linter.lintText(sourceFile.text, { filePath: sourceFile.fileName }); + await this.#linter.lintText(sourceFile.text, { filePath: sourceFile.fileName }); // Map the fix messages to the results. This API should only return one result per file, so we can be sure // that the fix messages belong to the returned result. If we somehow receive multiple results, we will // drop the messages on the floor, but since they are only used for logging, this should not be a problem. const fixMessages: (TEslint.Linter.LintMessage | TEslintLegacy.Linter.LintMessage)[] = - this._currentFixMessages.splice(0); + this.#currentFixMessages.splice(0); if (lintResults.length === 1) { - this._fixMessagesByResult.set(lintResults[0], fixMessages); + this.#fixMessagesByResult.set(lintResults[0], fixMessages); } this._fixesPossible ||= @@ -297,7 +297,7 @@ export class Eslint extends LinterBase { let omittedRuleCount: number = 0; - const timings: [string, number][] = Array.from(this._eslintTimings).sort( + const timings: [string, number][] = Array.from(this.#eslintTimings).sort( (x: [string, number], y: [string, number]) => { return y[1] - x[1]; } @@ -314,25 +314,25 @@ export class Eslint extends LinterBase 0) { - await this._eslintPackage.ESLint.outputFixes(lintResults); + if (this._fix && this.#fixMessagesByResult.size > 0) { + await this.#eslintPackage.ESLint.outputFixes(lintResults); } for (const lintResult of lintResults) { // Report linter fixes to the logger. These will only be returned when the underlying failure was fixed const fixMessages: TEslint.Linter.LintMessage[] | TEslintLegacy.Linter.LintMessage[] | undefined = - this._fixMessagesByResult.get(lintResult); + this.#fixMessagesByResult.get(lintResult); if (fixMessages) { for (const fixMessage of fixMessages) { const formattedMessage: string = `[FIXED] ${getFormattedErrorMessage(fixMessage)}`; - const errorObject: FileError = this._getLintFileError(lintResult, fixMessage, formattedMessage); + const errorObject: FileError = this.#getLintFileError(lintResult, fixMessage, formattedMessage); this._scopedLogger.emitWarning(errorObject); } } // Report linter errors and warnings to the logger for (const lintMessage of lintResult.messages) { - const errorObject: FileError = this._getLintFileError(lintResult, lintMessage); + const errorObject: FileError = this.#getLintFileError(lintResult, lintMessage); switch (lintMessage.severity) { case EslintMessageSeverity.error: { this._scopedLogger.emitError(errorObject); @@ -347,15 +347,15 @@ export class Eslint extends LinterBase { - return await this._linter.isPathIgnored(filePath); + return await this.#linter.isPathIgnored(filePath); } protected override hasLintFailures( @@ -380,7 +380,7 @@ export class Eslint extends LinterBase { // These are initliazed by _initAsync - private _initPromise!: Promise; - private _eslintToolPath: string | undefined; - private _eslintConfigFilePath: string | undefined; - private _tslintToolPath: string | undefined; - private _tslintConfigFilePath: string | undefined; + #initPromise!: Promise; + #eslintToolPath: string | undefined; + #eslintConfigFilePath: string | undefined; + #tslintToolPath: string | undefined; + #tslintConfigFilePath: string | undefined; public apply( taskSession: IHeftTaskSession, @@ -126,7 +126,7 @@ export default class LintPlugin implements IHeftTaskPlugin { // If we are not in the typescript phase, we need to create a typescript program // from the tsconfig file if (!inTypescriptPhase) { - const tsProgram: IExtendedProgram = await this._createTypescriptProgramAsync( + const tsProgram: IExtendedProgram = await this.#createTypescriptProgramAsync( heftConfiguration, taskSession ); @@ -136,7 +136,7 @@ export default class LintPlugin implements IHeftTaskPlugin { // Run the linters to completion. Linters emit errors and warnings to the logger. for (const [tsProgram, changedFiles] of typescriptChangedFiles) { try { - await this._lintAsync({ + await this.#lintAsync({ taskSession, heftConfiguration, tsProgram, @@ -163,7 +163,7 @@ export default class LintPlugin implements IHeftTaskPlugin { }); } - private async _createTypescriptProgramAsync( + async #createTypescriptProgramAsync( heftConfiguration: HeftConfiguration, taskSession: IHeftTaskSession ): Promise { @@ -187,32 +187,32 @@ export default class LintPlugin implements IHeftTaskPlugin { return program; } - private async _ensureInitializedAsync( + async #ensureInitializedAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration ): Promise { // Make sure that we only ever init once by memoizing the init promise - if (!this._initPromise) { - this._initPromise = this._initInnerAsync(heftConfiguration, taskSession.logger); + if (!this.#initPromise) { + this.#initPromise = this.#initInnerAsync(heftConfiguration, taskSession.logger); } - await this._initPromise; + await this.#initPromise; } - private async _initInnerAsync(heftConfiguration: HeftConfiguration, logger: IScopedLogger): Promise { + async #initInnerAsync(heftConfiguration: HeftConfiguration, logger: IScopedLogger): Promise { // Locate the tslint linter if enabled - this._tslintConfigFilePath = await Tslint.resolveTslintConfigFilePathAsync(heftConfiguration); - if (this._tslintConfigFilePath) { - this._tslintToolPath = await heftConfiguration.rigPackageResolver.resolvePackageAsync( + this.#tslintConfigFilePath = await Tslint.resolveTslintConfigFilePathAsync(heftConfiguration); + if (this.#tslintConfigFilePath) { + this.#tslintToolPath = await heftConfiguration.rigPackageResolver.resolvePackageAsync( 'tslint', logger.terminal ); } // Locate the eslint linter if enabled - this._eslintConfigFilePath = await Eslint.resolveEslintConfigFilePathAsync(heftConfiguration); - if (this._eslintConfigFilePath) { - logger.terminal.writeVerboseLine(`ESLint config file path: ${this._eslintConfigFilePath}`); - this._eslintToolPath = await heftConfiguration.rigPackageResolver.resolvePackageAsync( + this.#eslintConfigFilePath = await Eslint.resolveEslintConfigFilePathAsync(heftConfiguration); + if (this.#eslintConfigFilePath) { + logger.terminal.writeVerboseLine(`ESLint config file path: ${this.#eslintConfigFilePath}`); + this.#eslintToolPath = await heftConfiguration.rigPackageResolver.resolvePackageAsync( 'eslint', logger.terminal ); @@ -221,35 +221,35 @@ export default class LintPlugin implements IHeftTaskPlugin { } } - private async _lintAsync(options: ILintOptions): Promise { + async #lintAsync(options: ILintOptions): Promise { const { taskSession, heftConfiguration, tsProgram, changedFiles, fix, sarifLogPath } = options; // Ensure that we have initialized. This promise is cached, so calling init // multiple times will only init once. - await this._ensureInitializedAsync(taskSession, heftConfiguration); + await this.#ensureInitializedAsync(taskSession, heftConfiguration); const linters: LinterBase[] = []; - if (this._eslintConfigFilePath && this._eslintToolPath) { + if (this.#eslintConfigFilePath && this.#eslintToolPath) { const eslintLinter: Eslint = await Eslint.initializeAsync({ tsProgram, fix, sarifLogPath, scopedLogger: taskSession.logger, - linterToolPath: this._eslintToolPath, - linterConfigFilePath: this._eslintConfigFilePath, + linterToolPath: this.#eslintToolPath, + linterConfigFilePath: this.#eslintConfigFilePath, buildFolderPath: heftConfiguration.buildFolderPath, buildMetadataFolderPath: taskSession.tempFolderPath }); linters.push(eslintLinter); } - if (this._tslintConfigFilePath && this._tslintToolPath) { + if (this.#tslintConfigFilePath && this.#tslintToolPath) { const tslintLinter: Tslint = await Tslint.initializeAsync({ tsProgram, fix, scopedLogger: taskSession.logger, - linterToolPath: this._tslintToolPath, - linterConfigFilePath: this._tslintConfigFilePath, + linterToolPath: this.#tslintToolPath, + linterConfigFilePath: this.#tslintConfigFilePath, buildFolderPath: heftConfiguration.buildFolderPath, buildMetadataFolderPath: taskSession.tempFolderPath }); @@ -257,10 +257,10 @@ export default class LintPlugin implements IHeftTaskPlugin { } // Now that we know we have initialized properly, run the linter(s) - await Promise.all(linters.map((linter) => this._runLinterAsync(linter, tsProgram, changedFiles))); + await Promise.all(linters.map((linter) => this.#runLinterAsync(linter, tsProgram, changedFiles))); } - private async _runLinterAsync( + async #runLinterAsync( linter: LinterBase, tsProgram: IExtendedProgram, changedFiles?: ReadonlySet | undefined diff --git a/heft-plugins/heft-lint-plugin/src/LinterBase.ts b/heft-plugins/heft-lint-plugin/src/LinterBase.ts index f6c473754c7..6e3404e5433 100644 --- a/heft-plugins/heft-lint-plugin/src/LinterBase.ts +++ b/heft-plugins/heft-lint-plugin/src/LinterBase.ts @@ -71,7 +71,7 @@ export abstract class LinterBase { protected _fixesPossible: boolean = false; - private readonly _linterName: string; + readonly #linterName: string; protected constructor(linterName: string, options: ILinterBaseOptions) { this._scopedLogger = options.scopedLogger; @@ -79,7 +79,7 @@ export abstract class LinterBase { this._buildFolderPath = options.buildFolderPath; this._buildMetadataFolderPath = options.buildMetadataFolderPath; this._linterConfigFilePath = options.linterConfigFilePath; - this._linterName = linterName; + this.#linterName = linterName; this._fix = options.fix || false; } @@ -131,7 +131,7 @@ export abstract class LinterBase { const linterCacheVersion: string = await this.getCacheVersionAsync(); const linterCacheFilePath: string = path.resolve( this._buildMetadataFolderPath, - `_${this._linterName}-${hashSuffix}.json` + `_${this.#linterName}-${hashSuffix}.json` ); let linterCacheData: ILinterCacheData | undefined; diff --git a/heft-plugins/heft-lint-plugin/src/Tslint.ts b/heft-plugins/heft-lint-plugin/src/Tslint.ts index 52a15677ad7..cff4ab79a71 100644 --- a/heft-plugins/heft-lint-plugin/src/Tslint.ts +++ b/heft-plugins/heft-lint-plugin/src/Tslint.ts @@ -26,32 +26,32 @@ function getFormattedErrorMessage(tslintFailure: TTslint.RuleFailure): string { const TSLINT_CONFIG_FILE_NAME: string = 'tslint.json'; export class Tslint extends LinterBase { - private readonly _tslintPackage: typeof TTslint; - private readonly _tslintConfiguration: TTslint.Configuration.IConfigurationFile; - private readonly _linter: IExtendedLinter; - private readonly _enabledRules: TTslint.IRule[]; - private readonly _ruleSeverityMap: Map; + readonly #tslintPackage: typeof TTslint; + readonly #tslintConfiguration: TTslint.Configuration.IConfigurationFile; + readonly #linter: IExtendedLinter; + readonly #enabledRules: TTslint.IRule[]; + readonly #ruleSeverityMap: Map; public constructor(options: ITslintOptions) { super('tslint', options); const { tslintPackage, tsProgram } = options; - this._tslintPackage = tslintPackage; - this._tslintConfiguration = options.tslintConfiguration; - this._linter = new tslintPackage.Linter( + this.#tslintPackage = tslintPackage; + this.#tslintConfiguration = options.tslintConfiguration; + this.#linter = new tslintPackage.Linter( { // This is not handled by the linter in the way that we use it, so we will manually apply // fixes later fix: false, - rulesDirectory: this._tslintConfiguration.rulesDirectory + rulesDirectory: this.#tslintConfiguration.rulesDirectory }, tsProgram ) as unknown as IExtendedLinter; - this._enabledRules = this._linter.getEnabledRules(this._tslintConfiguration, false); + this.#enabledRules = this.#linter.getEnabledRules(this.#tslintConfiguration, false); - this._ruleSeverityMap = new Map( - this._enabledRules.map((rule): [string, TTslint.RuleSeverity] => [ + this.#ruleSeverityMap = new Map( + this.#enabledRules.map((rule): [string, TTslint.RuleSeverity] => [ rule.getOptions().ruleName, rule.getOptions().ruleSeverity ]) @@ -131,7 +131,7 @@ export class Tslint extends LinterBase { } public printVersionHeader(): void { - this._terminal.writeLine(`Using TSLint version ${this._tslintPackage.Linter.VERSION}`); + this._terminal.writeLine(`Using TSLint version ${this.#tslintPackage.Linter.VERSION}`); } protected async getCacheVersionAsync(): Promise { @@ -139,7 +139,7 @@ export class Tslint extends LinterBase { this._linterConfigFilePath, this._terminal ); - const tslintConfigVersion: string = `${this._tslintPackage.Linter.VERSION}_${tslintConfigHash.digest( + const tslintConfigVersion: string = `${this.#tslintPackage.Linter.VERSION}_${tslintConfigHash.digest( 'hex' )}`; @@ -150,18 +150,18 @@ export class Tslint extends LinterBase { // Some of this code comes from here: // https://github.com/palantir/tslint/blob/24d29e421828348f616bf761adb3892bcdf51662/src/linter.ts#L161-L179 // Modified to only lint files that have changed and that we care about - let failures: TTslint.RuleFailure[] = this._linter.getAllFailures(sourceFile, this._enabledRules); + let failures: TTslint.RuleFailure[] = this.#linter.getAllFailures(sourceFile, this.#enabledRules); const hasFixableIssue: boolean = failures.some((f) => f.hasFix()); if (hasFixableIssue) { if (this._fix) { - failures = this._linter.applyAllFixes(this._enabledRules, failures, sourceFile, sourceFile.fileName); + failures = this.#linter.applyAllFixes(this.#enabledRules, failures, sourceFile, sourceFile.fileName); } else { this._fixesPossible = true; } } for (const failure of failures) { - const severity: TTslint.RuleSeverity | undefined = this._ruleSeverityMap.get(failure.getRuleName()); + const severity: TTslint.RuleSeverity | undefined = this.#ruleSeverityMap.get(failure.getRuleName()); if (severity === undefined) { throw new Error(`Severity for rule '${failure.getRuleName()}' not found`); } @@ -173,21 +173,21 @@ export class Tslint extends LinterBase { } protected async lintingFinishedAsync(failures: TTslint.RuleFailure[]): Promise { - this._linter.failures = failures; - const lintResult: TTslint.LintResult = this._linter.getResult(); + this.#linter.failures = failures; + const lintResult: TTslint.LintResult = this.#linter.getResult(); // Report linter fixes to the logger. These will only be returned when the underlying failure was fixed if (lintResult.fixes?.length) { for (const fixedTslintFailure of lintResult.fixes) { const formattedMessage: string = `[FIXED] ${getFormattedErrorMessage(fixedTslintFailure)}`; - const errorObject: FileError = this._getLintFileError(fixedTslintFailure, formattedMessage); + const errorObject: FileError = this.#getLintFileError(fixedTslintFailure, formattedMessage); this._scopedLogger.emitWarning(errorObject); } } // Report linter errors and warnings to the logger for (const tslintFailure of lintResult.failures) { - const errorObject: FileError = this._getLintFileError(tslintFailure); + const errorObject: FileError = this.#getLintFileError(tslintFailure); switch (tslintFailure.getRuleSeverity()) { case 'error': { this._scopedLogger.emitError(errorObject); @@ -203,14 +203,14 @@ export class Tslint extends LinterBase { } protected async isFileExcludedAsync(filePath: string): Promise { - return this._tslintPackage.Configuration.isFileExcluded(filePath, this._tslintConfiguration); + return this.#tslintPackage.Configuration.isFileExcluded(filePath, this.#tslintConfiguration); } protected hasLintFailures(lintResults: TTslint.RuleFailure[]): boolean { return lintResults.length > 0; } - private _getLintFileError(tslintFailure: TTslint.RuleFailure, message?: string): FileError { + #getLintFileError(tslintFailure: TTslint.RuleFailure, message?: string): FileError { if (!message) { message = getFormattedErrorMessage(tslintFailure); } diff --git a/heft-plugins/heft-rspack-plugin/src/DeferredWatchFileSystem.ts b/heft-plugins/heft-rspack-plugin/src/DeferredWatchFileSystem.ts index 1b7a437c21d..6b57c2d3fda 100644 --- a/heft-plugins/heft-rspack-plugin/src/DeferredWatchFileSystem.ts +++ b/heft-plugins/heft-rspack-plugin/src/DeferredWatchFileSystem.ts @@ -52,8 +52,8 @@ export class DeferredWatchFileSystem implements WatchFileSystem { public readonly watcherOptions: WatchOptions; public watcher: Watchpack | undefined; - private readonly _onChange: () => void; - private _state: IWatchState | undefined; + readonly #onChange: () => void; + #state: IWatchState | undefined; public constructor(inputFileSystem: InputFileSystem, onChange: () => void) { this.inputFileSystem = inputFileSystem; @@ -61,11 +61,11 @@ export class DeferredWatchFileSystem implements WatchFileSystem { aggregateTimeout: 0 }; this.watcher = new Watchpack(this.watcherOptions); - this._onChange = onChange; + this.#onChange = onChange; } public flush(): boolean { - const state: IWatchState | undefined = this._state; + const state: IWatchState | undefined = this.#state; if (!state) { return false; @@ -91,9 +91,9 @@ export class DeferredWatchFileSystem implements WatchFileSystem { } if (changes.size > 0 || removals.size > 0) { - this._purge(removals, changes); + this.#purge(removals, changes); - const { fileTimeInfoEntries, contextTimeInfoEntries } = this._fetchTimeInfo(); + const { fileTimeInfoEntries, contextTimeInfoEntries } = this.#fetchTimeInfo(); callback(null, fileTimeInfoEntries, contextTimeInfoEntries, changes, removals); @@ -121,7 +121,7 @@ export class DeferredWatchFileSystem implements WatchFileSystem { const changes: Set = new Set(); const removals: Set = new Set(); - this._state = { + this.#state = { changes, removals, @@ -138,7 +138,7 @@ export class DeferredWatchFileSystem implements WatchFileSystem { removals.add(removal); } - this._onChange(); + this.#onChange(); }); this.watcher.watch({ @@ -167,8 +167,8 @@ export class DeferredWatchFileSystem implements WatchFileSystem { getInfo: () => { const newRemovals: Set | undefined = this.watcher?.aggregatedRemovals; const newChanges: Set | undefined = this.watcher?.aggregatedChanges; - this._purge(newRemovals, newChanges); - const { fileTimeInfoEntries, contextTimeInfoEntries } = this._fetchTimeInfo(); + this.#purge(newRemovals, newChanges); + const { fileTimeInfoEntries, contextTimeInfoEntries } = this.#fetchTimeInfo(); return { changes: newChanges!, removals: newRemovals!, @@ -177,24 +177,24 @@ export class DeferredWatchFileSystem implements WatchFileSystem { }; }, getContextTimeInfoEntries: () => { - const { contextTimeInfoEntries } = this._fetchTimeInfo(); + const { contextTimeInfoEntries } = this.#fetchTimeInfo(); return contextTimeInfoEntries; }, getFileTimeInfoEntries: () => { - const { fileTimeInfoEntries } = this._fetchTimeInfo(); + const { fileTimeInfoEntries } = this.#fetchTimeInfo(); return fileTimeInfoEntries; } }; } - private _fetchTimeInfo(): ITimeInfoEntries { + #fetchTimeInfo(): ITimeInfoEntries { const fileTimeInfoEntries: IRawFileSystemMap = new Map(); const contextTimeInfoEntries: IRawFileSystemMap = new Map(); this.watcher?.collectTimeInfoEntries(fileTimeInfoEntries, contextTimeInfoEntries); return { fileTimeInfoEntries, contextTimeInfoEntries }; } - private _purge(removals: Set | undefined, changes: Set | undefined): void { + #purge(removals: Set | undefined, changes: Set | undefined): void { const fs: InputFileSystem = this.inputFileSystem; if (fs.purge) { if (removals) { @@ -213,10 +213,10 @@ export class DeferredWatchFileSystem implements WatchFileSystem { export class OverrideNodeWatchFSPlugin implements RspackPluginInstance { public readonly fileSystems: Set = new Set(); - private readonly _onChange: () => void; + readonly #onChange: () => void; public constructor(onChange: () => void) { - this._onChange = onChange; + this.#onChange = onChange; } public apply(compiler: Compiler): void { @@ -227,7 +227,7 @@ export class OverrideNodeWatchFSPlugin implements RspackPluginInstance { const watchFileSystem: DeferredWatchFileSystem = new DeferredWatchFileSystem( inputFileSystem, - this._onChange + this.#onChange ); this.fileSystems.add(watchFileSystem); compiler.watchFileSystem = watchFileSystem; diff --git a/heft-plugins/heft-rspack-plugin/src/RspackPlugin.ts b/heft-plugins/heft-rspack-plugin/src/RspackPlugin.ts index 67546a3e345..06ca57fae65 100644 --- a/heft-plugins/heft-rspack-plugin/src/RspackPlugin.ts +++ b/heft-plugins/heft-rspack-plugin/src/RspackPlugin.ts @@ -42,28 +42,28 @@ const WEBPACK_DEV_MIDDLEWARE_PACKAGE_NAME: 'webpack-dev-middleware' = 'webpack-d * @internal */ export default class RspackPlugin implements IHeftTaskPlugin { - private _accessor: IRspackPluginAccessor | undefined; - private _isServeMode: boolean = false; - private _rspack: RspackCoreImport | undefined; - private _rspackCompiler: TRspack.Compiler | TRspack.MultiCompiler | undefined; - private _rspackConfiguration: IRspackConfiguration | undefined | false = false; - private _rspackCompilationDonePromise: Promise | undefined; - private _rspackCompilationDonePromiseResolveFn: (() => void) | undefined; - private _watchFileSystems: Set | undefined; - - private _warnings: Error[] = []; - private _errors: Error[] = []; + #accessor: IRspackPluginAccessor | undefined; + #isServeMode: boolean = false; + #rspack: RspackCoreImport | undefined; + #rspackCompiler: TRspack.Compiler | TRspack.MultiCompiler | undefined; + #rspackConfiguration: IRspackConfiguration | undefined | false = false; + #rspackCompilationDonePromise: Promise | undefined; + #rspackCompilationDonePromiseResolveFn: (() => void) | undefined; + #watchFileSystems: Set | undefined; + + #warnings: Error[] = []; + #errors: Error[] = []; public get accessor(): IRspackPluginAccessor { - if (!this._accessor) { - this._accessor = { + if (!this.#accessor) { + this.#accessor = { hooks: _createAccessorHooks(), parameters: { - isServeMode: this._isServeMode + isServeMode: this.#isServeMode } }; } - return this._accessor; + return this.#accessor; } public apply( @@ -71,8 +71,8 @@ export default class RspackPlugin implements IHeftTaskPlugin { - await this._runRspackAsync(taskSession, heftConfiguration, options); + await this.#runRspackAsync(taskSession, heftConfiguration, options); }); taskSession.hooks.runIncremental.tapPromise( PLUGIN_NAME, async (runOptions: IHeftTaskRunIncrementalHookOptions) => { - await this._runRspackWatchAsync(taskSession, heftConfiguration, options, runOptions.requestRun); + await this.#runRspackWatchAsync(taskSession, heftConfiguration, options, runOptions.requestRun); } ); } - private async _getRspackConfigurationAsync( + async #getRspackConfigurationAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, options: IRspackPluginOptions, requestRun?: () => void ): Promise { - if (this._rspackConfiguration === false) { + if (this.#rspackConfiguration === false) { const rspackConfiguration: IRspackConfiguration | undefined = await tryLoadRspackConfigurationAsync( { taskSession, heftConfiguration, hooks: this.accessor.hooks, - serveMode: this._isServeMode, - loadRspackAsyncFn: this._loadRspackAsync.bind(this, taskSession, heftConfiguration) + serveMode: this.#isServeMode, + loadRspackAsyncFn: this.#loadRspackAsync.bind(this, taskSession, heftConfiguration) }, options ); if (rspackConfiguration && requestRun) { const overrideWatchFSPlugin: OverrideNodeWatchFSPlugin = new OverrideNodeWatchFSPlugin(requestRun); - this._watchFileSystems = overrideWatchFSPlugin.fileSystems; + this.#watchFileSystems = overrideWatchFSPlugin.fileSystems; for (const config of Array.isArray(rspackConfiguration) ? rspackConfiguration : [rspackConfiguration]) { @@ -126,61 +126,61 @@ export default class RspackPlugin implements IHeftTaskPlugin { - if (!this._rspack) { + if (!this.#rspack) { try { const rspackPackagePath: string = await heftConfiguration.rigPackageResolver.resolvePackageAsync( RSPACK_PACKAGE_NAME, taskSession.logger.terminal ); - this._rspack = await import(rspackPackagePath); + this.#rspack = await import(rspackPackagePath); taskSession.logger.terminal.writeDebugLine(`Using Rspack from rig package at "${rspackPackagePath}"`); } catch (e) { // Fallback to bundled version if not found in rig. - this._rspack = await import(RSPACK_PACKAGE_NAME); + this.#rspack = await import(RSPACK_PACKAGE_NAME); taskSession.logger.terminal.writeDebugLine(`Using Rspack from built-in "${RSPACK_PACKAGE_NAME}"`); } } - return this._rspack!; + return this.#rspack!; } - private async _getRspackCompilerAsync( + async #getRspackCompilerAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, rspackConfiguration: IRspackConfiguration ): Promise { - if (!this._rspackCompiler) { - const rspack: RspackCoreImport = await this._loadRspackAsync(taskSession, heftConfiguration); + if (!this.#rspackCompiler) { + const rspack: RspackCoreImport = await this.#loadRspackAsync(taskSession, heftConfiguration); taskSession.logger.terminal.writeLine(`Using Rspack version ${rspack.version}`); - this._rspackCompiler = Array.isArray(rspackConfiguration) + this.#rspackCompiler = Array.isArray(rspackConfiguration) ? rspack.default(rspackConfiguration) /* (rspack.Compilation[]) => MultiCompiler */ : rspack.default(rspackConfiguration); /* (rspack.Compilation) => Compiler */ } - return this._rspackCompiler; + return this.#rspackCompiler; } - private async _runRspackAsync( + async #runRspackAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, options: IRspackPluginOptions ): Promise { - this._validateEnvironmentVariable(taskSession); - if (taskSession.parameters.watch || this._isServeMode) { + this.#validateEnvironmentVariable(taskSession); + if (taskSession.parameters.watch || this.#isServeMode) { // Should never happen, but just in case throw new InternalError('Cannot run Rspack in compilation mode when watch mode is enabled'); } // Load the config and compiler, and return if there is no config found - const rspackConfiguration: IRspackConfiguration | undefined = await this._getRspackConfigurationAsync( + const rspackConfiguration: IRspackConfiguration | undefined = await this.#getRspackConfigurationAsync( taskSession, heftConfiguration, options @@ -188,7 +188,7 @@ export default class RspackPlugin implements IHeftTaskPlugin { // Save a handle to the original promise, since the this-scoped promise will be replaced whenever // the compilation completes. - let rspackCompilationDonePromise: Promise | undefined = this._rspackCompilationDonePromise; + let rspackCompilationDonePromise: Promise | undefined = this.#rspackCompilationDonePromise; let isInitial: boolean = false; - if (!this._rspackCompiler) { + if (!this.#rspackCompiler) { isInitial = true; - this._validateEnvironmentVariable(taskSession); + this.#validateEnvironmentVariable(taskSession); if (!taskSession.parameters.watch) { // Should never happen, but just in case throw new InternalError('Cannot run Rspack in watch mode when watch mode is not enabled'); } // Load the config and compiler, and return if there is no config found - const rspackConfiguration: IRspackConfiguration | undefined = await this._getRspackConfigurationAsync( + const rspackConfiguration: IRspackConfiguration | undefined = await this.#getRspackConfigurationAsync( taskSession, heftConfiguration, options, @@ -248,7 +248,7 @@ export default class RspackPlugin implements IHeftTaskPlugin void) => { - this._rspackCompilationDonePromiseResolveFn = resolve; + this.#rspackCompilationDonePromise = new Promise((resolve: () => void) => { + this.#rspackCompilationDonePromiseResolveFn = resolve; }); - rspackCompilationDonePromise = this._rspackCompilationDonePromise; + rspackCompilationDonePromise = this.#rspackCompilationDonePromise; compiler.hooks.done.tap(PLUGIN_NAME, (stats?: TRspack.Stats | TRspack.MultiStats) => { - this._rspackCompilationDonePromiseResolveFn!(); - this._rspackCompilationDonePromise = new Promise((resolve: () => void) => { - this._rspackCompilationDonePromiseResolveFn = resolve; + this.#rspackCompilationDonePromiseResolveFn!(); + this.#rspackCompilationDonePromise = new Promise((resolve: () => void) => { + this.#rspackCompilationDonePromiseResolveFn = resolve; }); if (stats) { - this._recordErrors(stats, heftConfiguration.buildFolderPath); + this.#recordErrors(stats, heftConfiguration.buildFolderPath); } }); // Determine how we will run the compiler. When serving, we will run the compiler // via the @rspack/dev-server. Otherwise, we will run the compiler directly. - if (this._isServeMode) { + if (this.#isServeMode) { const defaultDevServerOptions: TRspackDevServer.Configuration = { host: 'localhost', devMiddleware: { @@ -412,9 +412,9 @@ export default class RspackPlugin implements IHeftTaskPlugin record - private readonly _fileInfo: Map; - private readonly _resolutions: Map; + readonly #fileInfo: Map; + readonly #resolutions: Map; - private readonly _isFileModule: (filePath: string) => boolean; - private readonly _options: ISassProcessorOptions; - private readonly _realpathSync: (path: string) => string; - private readonly _scssOptions: Options<'async'>; + readonly #isFileModule: (filePath: string) => boolean; + readonly #options: ISassProcessorOptions; + readonly #realpathSync: (path: string) => string; + readonly #scssOptions: Options<'async'>; - private _configFilePath: string | undefined; + #configFilePath: string | undefined; public constructor(options: ISassProcessorOptions) { const { silenceDeprecations, excludeFiles } = options; @@ -228,14 +228,14 @@ export class SassProcessor { url, context ) => { - return await this._canonicalizeAsync(url, context); + return await this.#canonicalizeAsync(url, context); }; const loadAsync: (url: URL) => Promise = async (url) => { const absolutePath: string = heftUrlToPath(url.href); - const record: IFileRecord = this._getOrCreateRecord(absolutePath); + const record: IFileRecord = this.#getOrCreateRecord(absolutePath); if (record.content === undefined) { - const { content, version } = await this._readFileContentAsync(absolutePath); + const { content, version } = await this.#readFileContentAsync(absolutePath); record.version = version; record.content = content; } @@ -255,13 +255,13 @@ export class SassProcessor { this.inputFileGlob = `**/*+(${allFileExtensions.join('|')})`; this.sourceFolderPath = options.srcFolder; - this._configFilePath = undefined; - this._fileInfo = new Map(); - this._isFileModule = isFileModule; - this._resolutions = new Map(); - this._options = options; - this._realpathSync = new RealNodeModulePathResolver().realNodeModulePath; - this._scssOptions = { + this.#configFilePath = undefined; + this.#fileInfo = new Map(); + this.#isFileModule = isFileModule; + this.#resolutions = new Map(); + this.#options = options; + this.#realpathSync = new RealNodeModulePathResolver().realNodeModulePath; + this.#scssOptions = { style: 'expanded', // leave minification to clean-css importers: [ { @@ -276,37 +276,37 @@ export class SassProcessor { } public async loadCacheAsync(tempFolderPath: string): Promise { - const configHash: string = getContentsHash('sass.json', JSON.stringify(this._options)).slice(0, 8); + const configHash: string = getContentsHash('sass.json', JSON.stringify(this.#options)).slice(0, 8); - this._configFilePath = path.join(tempFolderPath, `sass_${configHash}.json`); + this.#configFilePath = path.join(tempFolderPath, `sass_${configHash}.json`); try { - const serializedConfig: string = await FileSystem.readFileAsync(this._configFilePath); - this._cache = serializedConfig; + const serializedConfig: string = await FileSystem.readFileAsync(this.#configFilePath); + this.#cache = serializedConfig; } catch (err) { if (!FileSystem.isNotExistError(err)) { - this._options.logger.terminal.writeVerboseLine(`Error reading cache file: ${err}`); + this.#options.logger.terminal.writeVerboseLine(`Error reading cache file: ${err}`); } } } public async compileFilesAsync(filepaths: Set): Promise { // Incremental resolve is complicated, so just clear it for now - this._resolutions.clear(); + this.#resolutions.clear(); // Expand affected files using dependency graph // If this is the initial compilation, the graph will be empty, so this will no-op' const affectedRecords: Set = new Set(); for (const file of filepaths) { - const record: IFileRecord = this._getOrCreateRecord(file); + const record: IFileRecord = this.#getOrCreateRecord(file); affectedRecords.add(record); } const { concurrency, logger: { terminal } - } = this._options; + } = this.#options; terminal.writeVerboseLine(`Checking for changes to ${filepaths.size} files...`); for (const record of affectedRecords) { @@ -319,7 +319,7 @@ export class SassProcessor { await Async.forEachAsync( affectedRecords, async (record: IFileRecord) => { - const contentAndVersion: IFileContentAndVersion = await this._readFileContentAsync( + const contentAndVersion: IFileContentAndVersion = await this.#readFileContentAsync( record.absolutePath ); const { version } = contentAndVersion; @@ -367,9 +367,9 @@ export class SassProcessor { affectedRecords, async (record, i) => { try { - await this._compileFileAsync(compilers[i % compilerCount], record, this._scssOptions); + await this.#compileFileAsync(compilers[i % compilerCount], record, this.#scssOptions); } catch (err) { - this._options.logger.emitError(err); + this.#options.logger.emitError(err); } }, { @@ -383,7 +383,7 @@ export class SassProcessor { // Find all newly-referenced files and update the incremental build state data. const newRecords: Set = new Set(); - for (const record of this._fileInfo.values()) { + for (const record of this.#fileInfo.values()) { if (!record.version) { newRecords.add(record); } @@ -392,7 +392,7 @@ export class SassProcessor { await Async.forEachAsync( newRecords, async (record: IFileRecord) => { - const { content, version } = await this._readFileContentAsync(record.absolutePath); + const { content, version } = await this.#readFileContentAsync(record.absolutePath); // eslint-disable-next-line require-atomic-updates record.content = content; // eslint-disable-next-line require-atomic-updates @@ -403,10 +403,10 @@ export class SassProcessor { } ); - if (this._configFilePath) { - const serializedConfig: string = this._cache; + if (this.#configFilePath) { + const serializedConfig: string = this.#cache; try { - await FileSystem.writeFileAsync(this._configFilePath, serializedConfig, { + await FileSystem.writeFileAsync(this.#configFilePath, serializedConfig, { ensureFolderExists: true }); } catch (err) { @@ -421,26 +421,26 @@ export class SassProcessor { * @param context - The context in which the canonicalization is being performed * @returns The canonical URL of the target file, or null if it does not resolve */ - private async _canonicalizeFileAsync(url: string, context: CanonicalizeContext): AsyncResolution { + async #canonicalizeFileAsync(url: string, context: CanonicalizeContext): AsyncResolution { // The logic between `this._resolutions.get()` and `this._resolutions.set()` must be 100% synchronous // Otherwise we could end up with multiple promises for the same URL - let resolution: SyncOrAsyncResolution | undefined = this._resolutions.get(url); + let resolution: SyncOrAsyncResolution | undefined = this.#resolutions.get(url); if (resolution === undefined) { - resolution = this._canonicalizeFileInnerAsync(url, context); - this._resolutions.set(url, resolution); + resolution = this.#canonicalizeFileInnerAsync(url, context); + this.#resolutions.set(url, resolution); } return await resolution; } - private async _canonicalizeFileInnerAsync(url: string, context: CanonicalizeContext): AsyncResolution { + async #canonicalizeFileInnerAsync(url: string, context: CanonicalizeContext): AsyncResolution { const absolutePath: string = heftUrlToPath(url); const lastSlash: number = url.lastIndexOf('/'); const basename: string = url.slice(lastSlash + 1); // Does this file exist? try { - const contentAndVersion: IFileContentAndVersion = await this._readFileContentAsync(absolutePath); - const record: IFileRecord = this._getOrCreateRecord(absolutePath); + const contentAndVersion: IFileContentAndVersion = await this.#readFileContentAsync(absolutePath); + const record: IFileRecord = this.#getOrCreateRecord(absolutePath); const { version } = contentAndVersion; if (version !== record.version) { record.content = contentAndVersion.content; @@ -464,7 +464,7 @@ export class SassProcessor { // Try again with the partial const dirname: string = url.slice(0, lastSlash); const partialUrl: string = `${dirname}/_${basename}`; - const result: SyncResolution = await this._canonicalizeFileAsync(partialUrl, context); + const result: SyncResolution = await this.#canonicalizeFileAsync(partialUrl, context); return result; } @@ -474,7 +474,7 @@ export class SassProcessor { * @param context - The context in which the canonicalization is being performed * @returns The canonical URL of the target file, or null if it does not resolve */ - private async _canonicalizePackageAsync(url: string, context: CanonicalizeContext): AsyncResolution { + async #canonicalizePackageAsync(url: string, context: CanonicalizeContext): AsyncResolution { // We rewrite any of the old form `~` imports to `pkg:` const { containingUrl } = context; if (!containingUrl) { @@ -484,12 +484,12 @@ export class SassProcessor { const cacheKey: string = `${containingUrl.href}\0${url}`; // The logic between `this._resolutions.get()` and `this._resolutions.set()` must be 100% synchronous // Otherwise we could end up with multiple promises for the same URL - let resolution: SyncOrAsyncResolution | undefined = this._resolutions.get(cacheKey); + let resolution: SyncOrAsyncResolution | undefined = this.#resolutions.get(cacheKey); if (resolution === undefined) { // Since the cache doesn't have an entry, get the promise for the resolution // and inject it into the cache before other callers have a chance to try - resolution = this._canonicalizePackageInnerAsync(url, context); - this._resolutions.set(cacheKey, resolution); + resolution = this.#canonicalizePackageInnerAsync(url, context); + this.#resolutions.set(cacheKey, resolution); } return await resolution; } @@ -500,7 +500,7 @@ export class SassProcessor { * @param context - The context in which the canonicalization is being performed * @returns The canonical URL of the target file, or null if it does not resolve */ - private async _canonicalizePackageInnerAsync(url: string, context: CanonicalizeContext): AsyncResolution { + async #canonicalizePackageInnerAsync(url: string, context: CanonicalizeContext): AsyncResolution { const containingUrl: string | undefined = context.containingUrl?.href; if (containingUrl === undefined) { throw new Error(`Cannot resolve ${url} without a containing URL`); @@ -522,12 +522,12 @@ export class SassProcessor { const resolvedPackagePath: string = await Import.resolvePackageAsync({ packageName, baseFolderPath, - getRealPath: this._realpathSync + getRealPath: this.#realpathSync }); const modulePath: string = nodeModulesQuery.slice(linkEnd); const resolvedPath: string = `${resolvedPackagePath}${modulePath}`; const heftUrl: string = pathToHeftUrl(resolvedPath).href; - return await this._canonicalizeHeftUrlAsync(heftUrl, context); + return await this.#canonicalizeHeftUrlAsync(heftUrl, context); } /** @@ -536,14 +536,14 @@ export class SassProcessor { * @param context - The context in which the canonicalization is being performed * @returns The canonical URL of the target file, or null if it does not resolve */ - private async _canonicalizeHeftUrlAsync(url: string, context: CanonicalizeContext): AsyncResolution { + async #canonicalizeHeftUrlAsync(url: string, context: CanonicalizeContext): AsyncResolution { // The logic between `this._resolutions.get()` and `this._resolutions.set()` must be 100% synchronous - let resolution: SyncOrAsyncResolution | undefined = this._resolutions.get(url); + let resolution: SyncOrAsyncResolution | undefined = this.#resolutions.get(url); if (resolution === undefined) { // Since the cache doesn't have an entry, get the promise for the resolution // and inject it into the cache before other callers have a chance to try - resolution = this._canonicalizeHeftInnerAsync(url, context); - this._resolutions.set(url, resolution); + resolution = this.#canonicalizeHeftInnerAsync(url, context); + this.#resolutions.set(url, resolution); } return await resolution; @@ -556,18 +556,18 @@ export class SassProcessor { * @param context - The context in which the canonicalization is being performed * @returns The canonical URL of the target file, or null if it does not resolve */ - private async _canonicalizeAsync(url: string, context: CanonicalizeContext): AsyncResolution { + async #canonicalizeAsync(url: string, context: CanonicalizeContext): AsyncResolution { if (url.startsWith('~')) { throw new Error(`Unexpected tilde in URL: ${url} in context: ${context.containingUrl?.href}`); } if (url.startsWith('pkg:')) { - return await this._canonicalizePackageAsync(url, context); + return await this.#canonicalizePackageAsync(url, context); } // Check the cache first, and exit early if previously resolved if (url.startsWith('heft:')) { - return await this._canonicalizeHeftUrlAsync(url, context); + return await this.#canonicalizeHeftUrlAsync(url, context); } const { containingUrl } = context; @@ -576,7 +576,7 @@ export class SassProcessor { } const resolvedUrl: string = new URL(url, containingUrl.toString()).toString(); - return await this._canonicalizeHeftUrlAsync(resolvedUrl, context); + return await this.#canonicalizeHeftUrlAsync(resolvedUrl, context); } /** @@ -585,10 +585,10 @@ export class SassProcessor { * @param context - The context in which the canonicalization is being performed * @returns The canonical URL of the target file, or null if it does not resolve */ - private async _canonicalizeHeftInnerAsync(url: string, context: CanonicalizeContext): AsyncResolution { + async #canonicalizeHeftInnerAsync(url: string, context: CanonicalizeContext): AsyncResolution { if (url.endsWith('.sass') || url.endsWith('.scss') || url.endsWith('.css')) { // Extension is already present, so only try the exact URL or the corresponding partial - return await this._canonicalizeFileAsync(url, context); + return await this.#canonicalizeFileAsync(url, context); } // Spec says prefer .sass, but we don't use that extension. @@ -601,7 +601,7 @@ export class SassProcessor { `${url}/index.sass`, `${url}/index.css` ]) { - const result: SyncResolution = await this._canonicalizeFileAsync(candidate, context); + const result: SyncResolution = await this.#canonicalizeFileAsync(candidate, context); if (result) { return result; } @@ -610,8 +610,8 @@ export class SassProcessor { return null; } - private get _cache(): string { - const serializedRecords: ISerializedFileRecord[] = Array.from(this._fileInfo.values(), (record) => { + get #cache(): string { + const serializedRecords: ISerializedFileRecord[] = Array.from(this.#fileInfo.values(), (record) => { return { relativePath: record.relativePath, version: record.version, @@ -627,12 +627,12 @@ export class SassProcessor { * Configures the state of this processor using the specified cache file content. * @param cacheFileContent - The contents of the cache file */ - private set _cache(cacheFileContent: string) { - this._fileInfo.clear(); + set #cache(cacheFileContent: string) { + this.#fileInfo.clear(); const serializedRecords: ISerializedFileRecord[] = JSON.parse(cacheFileContent); const records: IFileRecord[] = []; - const buildFolder: string = this._options.buildFolder; + const buildFolder: string = this.#options.buildFolder; for (const record of serializedRecords) { const { relativePath, version, cssVersion } = record; // relativePath may start with `../` or similar, so need to use a library join function. @@ -641,7 +641,7 @@ export class SassProcessor { const isPartial: boolean = isSassPartial(absolutePath); // SCSS partials are not modules, insofar as they cannot be imported directly. - const isModule: boolean = isPartial ? false : this._isFileModule(absolutePath); + const isModule: boolean = isPartial ? false : this.#isFileModule(absolutePath); const fileRecord: IFileRecord = { absolutePath, @@ -657,8 +657,8 @@ export class SassProcessor { dependencies: new Set() }; records.push(fileRecord); - this._fileInfo.set(absolutePath, fileRecord); - this._resolutions.set(absolutePath, url); + this.#fileInfo.set(absolutePath, fileRecord); + this.#resolutions.set(absolutePath, url); } for (let i: number = 0, len: number = serializedRecords.length; i < len; i++) { @@ -678,7 +678,7 @@ export class SassProcessor { * @param absolutePath - The absolute path to the file * @returns A promise for an object that can be used to access the text and hash of the file. */ - private async _readFileContentAsync(absolutePath: string): Promise { + async #readFileContentAsync(absolutePath: string): Promise { const content: Buffer = await FileSystem.readFileToBufferAsync(absolutePath); let version: string | undefined; let contentString: string | undefined; @@ -699,33 +699,33 @@ export class SassProcessor { * @param filePath - The file path to get or create a record for * @returns The tracking record for the specified file */ - private _getOrCreateRecord(filePath: string): IFileRecord { + #getOrCreateRecord(filePath: string): IFileRecord { filePath = path.resolve(filePath); - let record: IFileRecord | undefined = this._fileInfo.get(filePath); + let record: IFileRecord | undefined = this.#fileInfo.get(filePath); if (!record) { const isPartial: boolean = isSassPartial(filePath); - const isModule: boolean = isPartial ? false : this._isFileModule(filePath); + const isModule: boolean = isPartial ? false : this.#isFileModule(filePath); const url: URL = pathToHeftUrl(filePath); record = { absolutePath: filePath, url, isPartial, isModule, - index: this._fileInfo.size, - relativePath: Path.convertToSlashes(path.relative(this._options.buildFolder, filePath)), + index: this.#fileInfo.size, + relativePath: Path.convertToSlashes(path.relative(this.#options.buildFolder, filePath)), version: '', content: undefined, cssVersion: undefined, consumers: new Set(), dependencies: new Set() }; - this._resolutions.set(filePath, record.url); - this._fileInfo.set(filePath, record); + this.#resolutions.set(filePath, record.url); + this.#fileInfo.set(filePath, record); } return record; } - private async _compileFileAsync( + async #compileFileAsync( compiler: Pick, record: IFileRecord, scssOptions: Options<'async'> @@ -751,7 +751,7 @@ export class SassProcessor { absolutePath: span.url ? heftUrlToPath(span.url.href ?? span.url) : 'unknown', // This property should always be present line: span.start.line, column: span.start.column, - projectFolder: this._options.buildFolder + projectFolder: this.#options.buildFolder }); } @@ -759,7 +759,7 @@ export class SassProcessor { record.dependencies.clear(); for (const dependency of result.loadedUrls) { const dependencyPath: string = heftUrlToPath(dependency.href); - const dependencyRecord: IFileRecord = this._getOrCreateRecord(dependencyPath); + const dependencyRecord: IFileRecord = this.#getOrCreateRecord(dependencyPath); record.dependencies.add(dependencyRecord); dependencyRecord.consumers.add(record); } @@ -781,7 +781,7 @@ export class SassProcessor { postProcessCssAsync, preserveIcssExports, sourceMap - } = this._options; + } = this.#options; // Handle CSS modules let moduleMap: JsonObject | undefined; diff --git a/heft-plugins/heft-serverless-stack-plugin/src/ServerlessStackPlugin.ts b/heft-plugins/heft-serverless-stack-plugin/src/ServerlessStackPlugin.ts index 3dd5368e47a..5468fff3370 100644 --- a/heft-plugins/heft-serverless-stack-plugin/src/ServerlessStackPlugin.ts +++ b/heft-plugins/heft-serverless-stack-plugin/src/ServerlessStackPlugin.ts @@ -30,10 +30,10 @@ const WEBPACK5_PLUGIN_NAME: typeof Webpack5PluginName = 'webpack5-plugin'; const SST_CLI_PACKAGE_NAME: string = '@serverless-stack/cli'; export default class ServerlessStackPlugin implements IHeftTaskPlugin { - private _logger!: IScopedLogger; + #logger!: IScopedLogger; public apply(taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void { - this._logger = taskSession.logger; + this.#logger = taskSession.logger; // Once https://github.com/serverless-stack/serverless-stack/issues/1537 is fixed, we may be // eliminate the need for this parameter. @@ -44,7 +44,7 @@ export default class ServerlessStackPlugin implements IHeftTaskPlugin { // Only tap if the --sst flag is set. if (sstParameter.value) { const configureWebpackTap: () => Promise = async () => { - this._logger.terminal.writeLine( + this.#logger.terminal.writeLine( 'The command line includes "--sst", redirecting Webpack to Serverless Stack' ); return false; @@ -66,7 +66,7 @@ export default class ServerlessStackPlugin implements IHeftTaskPlugin { taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { // TODO: Handle watch / serve mode - await this._runServerlessStackAsync({ + await this.#runServerlessStackAsync({ taskSession, heftConfiguration, sstStage: sstStageParameter.value @@ -75,7 +75,7 @@ export default class ServerlessStackPlugin implements IHeftTaskPlugin { } } - private async _runServerlessStackAsync(options: { + async #runServerlessStackAsync(options: { taskSession: IHeftTaskSession; heftConfiguration: HeftConfiguration; sstStage?: string; @@ -89,7 +89,7 @@ export default class ServerlessStackPlugin implements IHeftTaskPlugin { useNodeJSResolver: true }); } catch (e) { - this._logger.emitError( + this.#logger.emitError( new Error( `The ${options.taskSession.taskName} task cannot start because your project does not seem to have ` + `a dependency on the "${SST_CLI_PACKAGE_NAME}" package: ` + @@ -99,9 +99,9 @@ export default class ServerlessStackPlugin implements IHeftTaskPlugin { return; } - const sstCliEntryPoint: string = this._getSstCliEntryPoint(sstCliPackagePath); + const sstCliEntryPoint: string = this.#getSstCliEntryPoint(sstCliPackagePath); - this._logger.terminal.writeVerboseLine('Found SST package in' + sstCliPackagePath); + this.#logger.terminal.writeVerboseLine('Found SST package in' + sstCliPackagePath); const sstCommandArgs: string[] = []; sstCommandArgs.push(sstCliEntryPoint); @@ -119,9 +119,9 @@ export default class ServerlessStackPlugin implements IHeftTaskPlugin { sstCommandArgs.push(options.sstStage); } - this._logger.terminal.writeVerboseLine('Launching child process: ' + JSON.stringify(sstCommandArgs)); + this.#logger.terminal.writeVerboseLine('Launching child process: ' + JSON.stringify(sstCommandArgs)); - const sstCommandEnv: NodeJS.ProcessEnv = this._getWorkaroundEnvironment(sstCliPackagePath); + const sstCommandEnv: NodeJS.ProcessEnv = this.#getWorkaroundEnvironment(sstCliPackagePath); const sstCommandResult: child_process.ChildProcess = child_process.spawn( process.execPath, @@ -145,20 +145,20 @@ export default class ServerlessStackPlugin implements IHeftTaskPlugin { }); sstCommandResult.stdout?.on('data', (chunk: Buffer) => { - this._writeOutput(chunk.toString(), (x) => this._logger.terminal.write(x)); + this.#writeOutput(chunk.toString(), (x) => this.#logger.terminal.write(x)); }); sstCommandResult.stderr?.on('data', (chunk: Buffer) => { - this._writeOutput(chunk.toString(), (x) => this._logger.terminal.writeError(x)); + this.#writeOutput(chunk.toString(), (x) => this.#logger.terminal.writeError(x)); }); sstCommandResult.on('exit', (code: number | null) => { if (options.serveMode) { // The child process is not supposed to terminate in watch mode - this._logger.terminal.writeErrorLine(`SST process terminated with exit code ${code}`); + this.#logger.terminal.writeErrorLine(`SST process terminated with exit code ${code}`); // TODO: Provide a Heft facility for this process.exit(1); } else { - this._logger.terminal.writeVerboseLine(`SST process terminated with exit code ${code}`); + this.#logger.terminal.writeVerboseLine(`SST process terminated with exit code ${code}`); if (!code) { completionResolve(); } else { @@ -170,7 +170,7 @@ export default class ServerlessStackPlugin implements IHeftTaskPlugin { return completionPromise; } - private _writeOutput(chunk: string, write: (message: string) => void): void { + #writeOutput(chunk: string, write: (message: string) => void): void { const lines: string[] = chunk.split('\n'); const lastLine: string = lines.pop() || ''; @@ -180,7 +180,7 @@ export default class ServerlessStackPlugin implements IHeftTaskPlugin { } } - private _getSstCliEntryPoint(sstCliPackagePath: string): string { + #getSstCliEntryPoint(sstCliPackagePath: string): string { // Entry point for SST prior to v1.2.0 let sstCliEntryPoint: string = path.join(sstCliPackagePath, 'bin/scripts.js'); if (FileSystem.exists(sstCliEntryPoint)) { @@ -208,7 +208,7 @@ export default class ServerlessStackPlugin implements IHeftTaskPlugin { // // Since we're invoking the "@serverless-stack/cli/bin/scripts.js" entry point directly, we need to // reproduce this workaround. - private _getWorkaroundEnvironment(sstCliPackagePath: string): NodeJS.ProcessEnv { + #getWorkaroundEnvironment(sstCliPackagePath: string): NodeJS.ProcessEnv { const sstCommandEnv: NodeJS.ProcessEnv = { ...process.env }; diff --git a/heft-plugins/heft-typescript-plugin/src/TypeScriptBuilder.ts b/heft-plugins/heft-typescript-plugin/src/TypeScriptBuilder.ts index b819d050c3b..6b6e758434b 100644 --- a/heft-plugins/heft-typescript-plugin/src/TypeScriptBuilder.ts +++ b/heft-plugins/heft-typescript-plugin/src/TypeScriptBuilder.ts @@ -131,33 +131,33 @@ interface ITypeScriptTool extends IBaseTypeScriptTool { } export class TypeScriptBuilder { - private readonly _configuration: ITypeScriptBuilderConfiguration; - private readonly _typescriptLogger: IScopedLogger; - private readonly _typescriptTerminal: ITerminal; + readonly #configuration: ITypeScriptBuilderConfiguration; + readonly #typescriptLogger: IScopedLogger; + readonly #typescriptTerminal: ITerminal; - private _useSolutionBuilder!: boolean; + #useSolutionBuilder!: boolean; - private _moduleKindsToEmit!: ICachedEmitModuleKind[]; - private readonly _suppressedDiagnosticCodes: Set = new Set(); + #moduleKindsToEmit!: ICachedEmitModuleKind[]; + readonly #suppressedDiagnosticCodes: Set = new Set(); - private __tsCacheFilePath: string | undefined; + #_tsCacheFilePath: string | undefined; - private _tool: ITypeScriptTool | undefined = undefined; + #tool: ITypeScriptTool | undefined = undefined; - private _nextRequestId: number = 0; + #nextRequestId: number = 0; - private get _tsCacheFilePath(): string { - if (!this.__tsCacheFilePath) { + get #tsCacheFilePath(): string { + if (!this.#_tsCacheFilePath) { // TypeScript internally handles if the tsconfig options have changed from when the tsbuildinfo file was created. // We only need to hash our additional Heft configuration. const configHash: crypto.Hash = crypto.createHash('sha1'); // Relativize the outFolderName paths before hashing to ensure portability across different machines const normalizedConfig: IEmitModuleKind[] = - this._configuration.additionalModuleKindsToEmit?.map((emitKind) => ({ + this.#configuration.additionalModuleKindsToEmit?.map((emitKind) => ({ ...emitKind, outFolderName: Path.convertToSlashes( - path.relative(this._configuration.buildFolderPath, emitKind.outFolderName) + path.relative(this.#configuration.buildFolderPath, emitKind.outFolderName) ) })) || []; @@ -168,31 +168,31 @@ export class TypeScriptBuilder { // using only '/' as the directory separator so that incremental builds don't break on Windows. // TypeScript will normalize to '/' when serializing, but not on the direct input, and uses exact string equality. const normalizedCacheFolderPath: string = Path.convertToSlashes( - this._configuration.buildMetadataFolderPath + this.#configuration.buildMetadataFolderPath ); - this.__tsCacheFilePath = `${normalizedCacheFolderPath}/ts_${serializedConfigHash}.json`; + this.#_tsCacheFilePath = `${normalizedCacheFolderPath}/ts_${serializedConfigHash}.json`; } - return this.__tsCacheFilePath; + return this.#_tsCacheFilePath; } public constructor(configuration: ITypeScriptBuilderConfiguration) { - this._configuration = configuration; - this._typescriptLogger = configuration.scopedLogger; - this._typescriptTerminal = configuration.scopedLogger.terminal; + this.#configuration = configuration; + this.#typescriptLogger = configuration.scopedLogger; + this.#typescriptTerminal = configuration.scopedLogger.terminal; } public async invokeAsync(onChangeDetected?: () => void): Promise { - if (!this._tool) { + if (!this.#tool) { const { tool: { ts, system: baseSystem, typeScriptToolPath } } = await loadTypeScriptToolAsync({ - terminal: this._typescriptTerminal, - heftConfiguration: this._configuration.heftConfiguration, - buildProjectReferences: this._configuration.buildProjectReferences, - onlyResolveSymlinksInNodeModules: this._configuration.onlyResolveSymlinksInNodeModules + terminal: this.#typescriptTerminal, + heftConfiguration: this.#configuration.heftConfiguration, + buildProjectReferences: this.#configuration.buildProjectReferences, + onlyResolveSymlinksInNodeModules: this.#configuration.onlyResolveSymlinksInNodeModules }); - this._useSolutionBuilder = !!this._configuration.buildProjectReferences; + this.#useSolutionBuilder = !!this.#configuration.buildProjectReferences; ts.performance.enable(); @@ -204,7 +204,7 @@ export class TypeScriptBuilder { ]; for (const code of suppressedCodes) { if (code !== undefined) { - this._suppressedDiagnosticCodes.add(code); + this.#suppressedDiagnosticCodes.add(code); } } @@ -225,7 +225,7 @@ export class TypeScriptBuilder { }; }; - this._typescriptTerminal.writeLine(`Using TypeScript version ${ts.version}`); + this.#typescriptTerminal.writeLine(`Using TypeScript version ${ts.version}`); const rawDiagnostics: TTypescript.Diagnostic[] = []; @@ -244,13 +244,13 @@ export class TypeScriptBuilder { fn(...args); }; pendingOperations.add(timeout); - if (!this._tool?.executing && onChangeDetected) { + if (!this.#tool?.executing && onChangeDetected) { onChangeDetected(); } return timeout; }; - const getCurrentDirectory: () => string = () => this._configuration.buildFolderPath; + const getCurrentDirectory: () => string = () => this.#configuration.buildFolderPath; // Need to also update watchFile and watchDirectory const system: ITypeScriptNodeSystem = { @@ -279,7 +279,7 @@ export class TypeScriptBuilder { }; } - this._tool = { + this.#tool = { typeScriptToolPath, ts, system, @@ -308,17 +308,17 @@ export class TypeScriptBuilder { }; } - const { performance } = this._tool.ts; + const { performance } = this.#tool.ts; // Reset the performance counters to 0 to avoid contamination from previous runs performance.disable(); performance.enable(); if (onChangeDetected !== undefined) { - await this._runWatchAsync(this._tool); - } else if (this._useSolutionBuilder) { - await this._runSolutionBuildAsync(this._tool); + await this._runWatchAsync(this.#tool); + } else if (this.#useSolutionBuilder) { + await this._runSolutionBuildAsync(this.#tool); } else { - await this._runBuildAsync(this._tool); + await this._runBuildAsync(this.#tool); } } @@ -336,28 +336,28 @@ export class TypeScriptBuilder { const { duration: configureDurationMs, tsconfig } = measureTsPerformance('Configure', () => { const _tsconfig: TTypescript.ParsedCommandLine = loadTsconfig({ tool, - tsconfigPath: this._configuration.tsconfigPath, - tsCacheFilePath: this._tsCacheFilePath + tsconfigPath: this.#configuration.tsconfigPath, + tsCacheFilePath: this.#tsCacheFilePath }); - this._validateTsconfig(ts, _tsconfig); + this.#validateTsconfig(ts, _tsconfig); return { tsconfig: _tsconfig }; }); - this._typescriptTerminal.writeVerboseLine(`Configure: ${configureDurationMs}ms`); + this.#typescriptTerminal.writeVerboseLine(`Configure: ${configureDurationMs}ms`); //#endregion - if (this._useSolutionBuilder) { - const solutionHost: TWatchSolutionHost = this._buildWatchSolutionBuilderHost(tool); + if (this.#useSolutionBuilder) { + const solutionHost: TWatchSolutionHost = this.#buildWatchSolutionBuilderHost(tool); const builder: TTypescript.SolutionBuilder = - ts.createSolutionBuilderWithWatch(solutionHost, [this._configuration.tsconfigPath], {}); + ts.createSolutionBuilderWithWatch(solutionHost, [this.#configuration.tsconfigPath], {}); tool.solutionBuilder = builder as IExtendedSolutionBuilder; builder.build(); } else { - const compilerHost: TWatchCompilerHost = this._buildWatchCompilerHost(tool, tsconfig); + const compilerHost: TWatchCompilerHost = this.#buildWatchCompilerHost(tool, tsconfig); tool.watchProgram = ts.createWatchProgram(compilerHost); } } @@ -380,7 +380,7 @@ export class TypeScriptBuilder { // eslint-disable-next-line require-atomic-updates tool.executing = false; } - this._logDiagnostics(ts, rawDiagnostics, this._useSolutionBuilder); + this.#logDiagnostics(ts, rawDiagnostics, this.#useSolutionBuilder); } public async _runBuildAsync(tool: ITypeScriptTool): Promise { @@ -394,19 +394,19 @@ export class TypeScriptBuilder { } = measureTsPerformance('Configure', () => { const _tsconfig: TTypescript.ParsedCommandLine = loadTsconfig({ tool, - tsconfigPath: this._configuration.tsconfigPath, - tsCacheFilePath: this._tsCacheFilePath + tsconfigPath: this.#configuration.tsconfigPath, + tsCacheFilePath: this.#tsCacheFilePath }); - this._validateTsconfig(ts, _tsconfig); + this.#validateTsconfig(ts, _tsconfig); - const _compilerHost: TTypescript.CompilerHost = this._buildIncrementalCompilerHost(tool, _tsconfig); + const _compilerHost: TTypescript.CompilerHost = this.#buildIncrementalCompilerHost(tool, _tsconfig); return { tsconfig: _tsconfig, compilerHost: _compilerHost }; }); - this._typescriptTerminal.writeVerboseLine(`Configure: ${configureDurationMs}ms`); + this.#typescriptTerminal.writeVerboseLine(`Configure: ${configureDurationMs}ms`); //#endregion //#region PROGRAM @@ -415,7 +415,7 @@ export class TypeScriptBuilder { let innerProgram: TTypescript.Program; const isolatedModules: boolean = - !!this._configuration.useTranspilerWorker && !!tsconfig.options.isolatedModules; + !!this.#configuration.useTranspilerWorker && !!tsconfig.options.isolatedModules; const mode: 'both' | 'declaration' = isolatedModules ? 'declaration' : 'both'; let filesToTranspile: Map | undefined; @@ -450,12 +450,12 @@ export class TypeScriptBuilder { // Prefer the builder program, since it is what gives us incremental builds const genericProgram: TTypescript.BuilderProgram | TTypescript.Program = builderProgram || innerProgram; - this._logReadPerformance(ts); + this.#logReadPerformance(ts); //#endregion if (isolatedModules) { // Kick the transpilation worker. - this._queueTranspileInWorker(tool, genericProgram.getCompilerOptions(), filesToTranspile); + this.#queueTranspileInWorker(tool, genericProgram.getCompilerOptions(), filesToTranspile); } //#region ANALYSIS @@ -472,11 +472,11 @@ export class TypeScriptBuilder { return { diagnostics: rawDiagnostics }; } ); - this._typescriptTerminal.writeVerboseLine(`Analyze: ${diagnosticsDurationMs}ms`); + this.#typescriptTerminal.writeVerboseLine(`Analyze: ${diagnosticsDurationMs}ms`); //#endregion //#region EMIT - const { changedFiles } = configureProgramForMultiEmit(innerProgram, ts, this._moduleKindsToEmit, mode); + const { changedFiles } = configureProgramForMultiEmit(innerProgram, ts, this.#moduleKindsToEmit, mode); const emitResult: TTypescript.EmitResult = genericProgram.emit( undefined, @@ -487,18 +487,18 @@ export class TypeScriptBuilder { undefined ); - this._cleanupWorker(); + this.#cleanupWorker(); //#endregion - this._emitModulePackageJsonFiles(ts); - this._logEmitPerformance(ts); + this.#emitModulePackageJsonFiles(ts); + this.#logEmitPerformance(ts); //#region FINAL_ANALYSIS // Need to ensure that we include emit diagnostics, since they might not be part of the other sets const rawDiagnostics: TTypescript.Diagnostic[] = [...preDiagnostics, ...emitResult.diagnostics]; //#endregion - this._configuration.emitChangedFilesCallback(innerProgram, changedFiles); + this.#configuration.emitChangedFilesCallback(innerProgram, changedFiles); if (pendingTranspilePromises.size) { const emitResults: TTypescript.EmitResult[] = await Promise.all(pendingTranspilePromises.values()); @@ -509,14 +509,14 @@ export class TypeScriptBuilder { } } - this._logDiagnostics(ts, rawDiagnostics); + this.#logDiagnostics(ts, rawDiagnostics); // Reset performance counters in case any are used in the callback ts.performance.disable(); ts.performance.enable(); } public async _runSolutionBuildAsync(tool: ITypeScriptTool): Promise { - this._typescriptTerminal.writeVerboseLine(`Using solution mode`); + this.#typescriptTerminal.writeVerboseLine(`Using solution mode`); const { ts, measureSync, rawDiagnostics, pendingTranspilePromises } = tool; rawDiagnostics.length = 0; @@ -526,23 +526,23 @@ export class TypeScriptBuilder { const { duration: configureDurationMs, solutionBuilderHost } = measureSync('Configure', () => { const _tsconfig: TTypescript.ParsedCommandLine = loadTsconfig({ tool, - tsconfigPath: this._configuration.tsconfigPath, - tsCacheFilePath: this._tsCacheFilePath + tsconfigPath: this.#configuration.tsconfigPath, + tsCacheFilePath: this.#tsCacheFilePath }); - this._validateTsconfig(ts, _tsconfig); + this.#validateTsconfig(ts, _tsconfig); - const _solutionBuilderHost: TSolutionHost = this._buildSolutionBuilderHost(tool); + const _solutionBuilderHost: TSolutionHost = this.#buildSolutionBuilderHost(tool); return { solutionBuilderHost: _solutionBuilderHost }; }); - this._typescriptTerminal.writeVerboseLine(`Configure: ${configureDurationMs}ms`); + this.#typescriptTerminal.writeVerboseLine(`Configure: ${configureDurationMs}ms`); //#endregion tool.solutionBuilder = ts.createSolutionBuilder( solutionBuilderHost, - [this._configuration.tsconfigPath], + [this.#configuration.tsconfigPath], {} ) as IExtendedSolutionBuilder; } else { @@ -555,10 +555,10 @@ export class TypeScriptBuilder { //#region EMIT // Ignoring the exit status because we only care about presence of diagnostics tool.solutionBuilder.build(); - this._cleanupWorker(); + this.#cleanupWorker(); //#endregion - this._emitModulePackageJsonFiles(ts); + this.#emitModulePackageJsonFiles(ts); if (pendingTranspilePromises.size) { const emitResults: TTypescript.EmitResult[] = await Promise.all(pendingTranspilePromises.values()); @@ -569,10 +569,10 @@ export class TypeScriptBuilder { } } - this._logDiagnostics(ts, rawDiagnostics, true); + this.#logDiagnostics(ts, rawDiagnostics, true); } - private _logDiagnostics( + #logDiagnostics( ts: ExtendedTypeScript, rawDiagnostics: TTypescript.Diagnostic[], isSolutionMode?: boolean @@ -583,11 +583,11 @@ export class TypeScriptBuilder { let warningCount: number = 0; let hasError: boolean = false; - this._typescriptTerminal.writeLine( + this.#typescriptTerminal.writeLine( `Encountered ${diagnostics.length} TypeScript issue${diagnostics.length > 1 ? 's' : ''}:` ); for (const diagnostic of diagnostics) { - const diagnosticCategory: TTypescript.DiagnosticCategory = this._getAdjustedDiagnosticCategory( + const diagnosticCategory: TTypescript.DiagnosticCategory = this.#getAdjustedDiagnosticCategory( diagnostic, ts ); @@ -598,11 +598,11 @@ export class TypeScriptBuilder { hasError = true; } - this._printDiagnosticMessage(ts, diagnostic, diagnosticCategory); + this.#printDiagnosticMessage(ts, diagnostic, diagnosticCategory); } if (isSolutionMode && warningCount > 0 && !hasError) { - this._typescriptLogger.emitError( + this.#typescriptLogger.emitError( new Error( `TypeScript encountered ${warningCount} warning${warningCount === 1 ? '' : 's'} ` + `and is configured to build project references. As a result, no files were emitted. Please fix the reported warnings to proceed.` @@ -612,45 +612,45 @@ export class TypeScriptBuilder { } } - private _logEmitPerformance(ts: ExtendedTypeScript): void { - this._typescriptTerminal.writeVerboseLine(`Bind: ${ts.performance.getDuration('Bind')}ms`); - this._typescriptTerminal.writeVerboseLine(`Check: ${ts.performance.getDuration('Check')}ms`); - this._typescriptTerminal.writeVerboseLine( + #logEmitPerformance(ts: ExtendedTypeScript): void { + this.#typescriptTerminal.writeVerboseLine(`Bind: ${ts.performance.getDuration('Bind')}ms`); + this.#typescriptTerminal.writeVerboseLine(`Check: ${ts.performance.getDuration('Check')}ms`); + this.#typescriptTerminal.writeVerboseLine( `Transform: ${ts.performance.getDuration('transformTime')}ms ` + `(${ts.performance.getCount('beforeTransform')} files)` ); - this._typescriptTerminal.writeVerboseLine( + this.#typescriptTerminal.writeVerboseLine( `Print: ${ts.performance.getDuration('printTime')}ms ` + `(${ts.performance.getCount('beforePrint')} files) (Includes Transform)` ); - this._typescriptTerminal.writeVerboseLine( + this.#typescriptTerminal.writeVerboseLine( `Emit: ${ts.performance.getDuration('Emit')}ms (Includes Print)` ); - this._typescriptTerminal.writeVerboseLine( + this.#typescriptTerminal.writeVerboseLine( `I/O Write: ${ts.performance.getDuration('I/O Write')}ms (${ts.performance.getCount( 'beforeIOWrite' )} files)` ); } - private _logReadPerformance(ts: ExtendedTypeScript): void { - this._typescriptTerminal.writeVerboseLine( + #logReadPerformance(ts: ExtendedTypeScript): void { + this.#typescriptTerminal.writeVerboseLine( `I/O Read: ${ts.performance.getDuration('I/O Read')}ms (${ts.performance.getCount( 'beforeIORead' )} files)` ); - this._typescriptTerminal.writeVerboseLine( + this.#typescriptTerminal.writeVerboseLine( `Parse: ${ts.performance.getDuration('Parse')}ms (${ts.performance.getCount('beforeParse')} files)` ); - this._typescriptTerminal.writeVerboseLine( + this.#typescriptTerminal.writeVerboseLine( `Program (includes Read + Parse): ${ts.performance.getDuration('Program')}ms` ); } - private _printDiagnosticMessage( + #printDiagnosticMessage( ts: ExtendedTypeScript, diagnostic: TTypescript.Diagnostic, - diagnosticCategory: TTypescript.DiagnosticCategory = this._getAdjustedDiagnosticCategory(diagnostic, ts) + diagnosticCategory: TTypescript.DiagnosticCategory = this.#getAdjustedDiagnosticCategory(diagnostic, ts) ): void { // Code taken from reference example let diagnosticMessage: string; @@ -661,7 +661,7 @@ export class TypeScriptBuilder { const formattedMessage: string = `(TS${diagnostic.code}) ${message}`; errorObject = new FileError(formattedMessage, { absolutePath: diagnostic.file.fileName, - projectFolder: this._configuration.buildFolderPath, + projectFolder: this.#configuration.buildFolderPath, line: line + 1, column: character + 1 }); @@ -673,23 +673,23 @@ export class TypeScriptBuilder { switch (diagnosticCategory) { case ts.DiagnosticCategory.Error: { - this._typescriptLogger.emitError(errorObject); + this.#typescriptLogger.emitError(errorObject); break; } case ts.DiagnosticCategory.Warning: { - this._typescriptLogger.emitWarning(errorObject); + this.#typescriptLogger.emitWarning(errorObject); break; } default: { - this._typescriptTerminal.writeLine(...diagnosticMessage); + this.#typescriptTerminal.writeLine(...diagnosticMessage); break; } } } - private _getAdjustedDiagnosticCategory( + #getAdjustedDiagnosticCategory( diagnostic: TTypescript.Diagnostic, ts: ExtendedTypeScript ): TTypescript.DiagnosticCategory { @@ -705,14 +705,14 @@ export class TypeScriptBuilder { } // These pedantic checks also should not be treated as hard errors - if (this._suppressedDiagnosticCodes.has(diagnostic.code)) { + if (this.#suppressedDiagnosticCodes.has(diagnostic.code)) { return ts.DiagnosticCategory.Warning; } return diagnostic.category; } - private _validateTsconfig(ts: ExtendedTypeScript, tsconfig: TTypescript.ParsedCommandLine): void { + #validateTsconfig(ts: ExtendedTypeScript, tsconfig: TTypescript.ParsedCommandLine): void { if ( (tsconfig.options.module && !tsconfig.options.outDir) || (!tsconfig.options.module && tsconfig.options.outDir) @@ -722,7 +722,7 @@ export class TypeScriptBuilder { ); } - this._moduleKindsToEmit = []; + this.#moduleKindsToEmit = []; const specifiedKinds: Map = new Map(); const specifiedOutDirs: Map = new Map(); @@ -733,8 +733,8 @@ export class TypeScriptBuilder { ); } - if (this._configuration.emitCjsExtensionForCommonJS) { - this._addModuleKindToEmit( + if (this.#configuration.emitCjsExtensionForCommonJS) { + this.#addModuleKindToEmit( ts.ModuleKind.CommonJS, tsconfig.options.outDir!, /* isPrimary */ tsconfig.options.module === ts.ModuleKind.CommonJS, @@ -753,8 +753,8 @@ export class TypeScriptBuilder { specifiedOutDirs.set(`${tsconfig.options.outDir!}:.cjs`, cjsReason); } - if (this._configuration.emitMjsExtensionForESModule) { - this._addModuleKindToEmit( + if (this.#configuration.emitMjsExtensionForESModule) { + this.#addModuleKindToEmit( ts.ModuleKind.ESNext, tsconfig.options.outDir!, /* isPrimary */ tsconfig.options.module === ts.ModuleKind.ESNext, @@ -774,7 +774,7 @@ export class TypeScriptBuilder { } if (!specifiedKinds.has(tsconfig.options.module)) { - this._addModuleKindToEmit( + this.#addModuleKindToEmit( tsconfig.options.module, tsconfig.options.outDir!, /* isPrimary */ true, @@ -793,10 +793,10 @@ export class TypeScriptBuilder { specifiedOutDirs.set(`${tsconfig.options.outDir!}:.js`, tsConfigReason); } - if (this._configuration.additionalModuleKindsToEmit) { + if (this.#configuration.additionalModuleKindsToEmit) { for (const { moduleKind: moduleKindString, outFolderName, emitModulePackageJson = false } of this - ._configuration.additionalModuleKindsToEmit) { - const moduleKind: TTypescript.ModuleKind = this._parseModuleKind(ts, moduleKindString); + .#configuration.additionalModuleKindsToEmit) { + const moduleKind: TTypescript.ModuleKind = this.#parseModuleKind(ts, moduleKindString); const outDirKey: string = `${outFolderName}:.js`; const moduleKindReason: IModuleKindReason = { @@ -818,7 +818,7 @@ export class TypeScriptBuilder { `Output folder "${outFolderName}" already contains module kind ${existingDir.kind} with extension '${existingDir.extension}', specified by option ${existingDir.reason}.` ); } else { - const outFolderKey: string | undefined = this._addModuleKindToEmit( + const outFolderKey: string | undefined = this.#addModuleKindToEmit( moduleKind, outFolderName, /* isPrimary */ false, @@ -835,7 +835,7 @@ export class TypeScriptBuilder { } } - private _addModuleKindToEmit( + #addModuleKindToEmit( moduleKind: TTypescript.ModuleKind, outFolderPath: string, isPrimary: boolean, @@ -844,16 +844,16 @@ export class TypeScriptBuilder { ): string | undefined { let outFolderName: string; if (path.isAbsolute(outFolderPath)) { - outFolderName = path.relative(this._configuration.buildFolderPath, outFolderPath); + outFolderName = path.relative(this.#configuration.buildFolderPath, outFolderPath); } else { outFolderName = outFolderPath; - outFolderPath = path.resolve(this._configuration.buildFolderPath, outFolderPath); + outFolderPath = path.resolve(this.#configuration.buildFolderPath, outFolderPath); } outFolderPath = Path.convertToSlashes(outFolderPath); outFolderPath = outFolderPath.replace(/\/*$/, '/'); // Ensure the outFolderPath ends with a slash - for (const existingModuleKindToEmit of this._moduleKindsToEmit) { + for (const existingModuleKindToEmit of this.#moduleKindsToEmit) { let errorText: string | undefined; if (existingModuleKindToEmit.outFolderPath === outFolderPath) { @@ -882,12 +882,12 @@ export class TypeScriptBuilder { } if (errorText) { - this._typescriptLogger.emitError(new Error(errorText)); + this.#typescriptLogger.emitError(new Error(errorText)); return undefined; } } - this._moduleKindsToEmit.push({ + this.#moduleKindsToEmit.push({ outFolderPath, moduleKind, jsExtensionOverride, @@ -898,12 +898,10 @@ export class TypeScriptBuilder { return `${outFolderName}:${jsExtensionOverride || '.js'}`; } - private _getCreateBuilderProgram( + #getCreateBuilderProgram( ts: ExtendedTypeScript ): TTypescript.CreateProgram { - const { - _configuration: { emitChangedFilesCallback } - } = this; + const { emitChangedFilesCallback } = this.#configuration; const createMultiEmitBuilderProgram: TTypescript.CreateProgram< TTypescript.EmitAndSemanticDiagnosticsBuilderProgram @@ -919,7 +917,7 @@ export class TypeScriptBuilder { ts.performance.disable(); ts.performance.enable(); - this._typescriptTerminal.writeVerboseLine(`Reading program "${compilerOptions!.configFilePath}"`); + this.#typescriptTerminal.writeVerboseLine(`Reading program "${compilerOptions!.configFilePath}"`); const newProgram: TTypescript.EmitAndSemanticDiagnosticsBuilderProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram( @@ -931,16 +929,16 @@ export class TypeScriptBuilder { projectReferences ); - this._logReadPerformance(ts); + this.#logReadPerformance(ts); const isolatedModules: boolean = - !!this._configuration.useTranspilerWorker && !!compilerOptions!.isolatedModules; + !!this.#configuration.useTranspilerWorker && !!compilerOptions!.isolatedModules; const mode: 'both' | 'declaration' = isolatedModules ? 'declaration' : 'both'; if (isolatedModules) { // Kick the transpilation worker. const filesToTranspile: Map = getFilesToTranspileFromBuilderProgram(newProgram); - this._queueTranspileInWorker(this._tool!, compilerOptions!, filesToTranspile); + this.#queueTranspileInWorker(this.#tool!, compilerOptions!, filesToTranspile); } const { emit: originalEmit } = newProgram; @@ -959,7 +957,7 @@ export class TypeScriptBuilder { const { changedFiles } = configureProgramForMultiEmit( innerProgram, ts, - this._moduleKindsToEmit, + this.#moduleKindsToEmit, mode ); @@ -974,12 +972,12 @@ export class TypeScriptBuilder { (result as IExtendedEmitResult).changedSourceFiles = changedFiles; - this._typescriptTerminal.writeVerboseLine( + this.#typescriptTerminal.writeVerboseLine( `Emitting program "${innerCompilerOptions!.configFilePath}"` ); - this._emitModulePackageJsonFiles(ts); - this._logEmitPerformance(ts); + this.#emitModulePackageJsonFiles(ts); + this.#logEmitPerformance(ts); // Reset performance counters ts.performance.disable(); @@ -998,7 +996,7 @@ export class TypeScriptBuilder { return createMultiEmitBuilderProgram; } - private _buildSolutionBuilderHost(tool: ITypeScriptTool): TSolutionHost { + #buildSolutionBuilderHost(tool: ITypeScriptTool): TSolutionHost { const reportSolutionBuilderStatus: TTypescript.DiagnosticReporter = tool.reportDiagnostic; const reportEmitErrorSummary: TTypescript.ReportEmitErrorSummary = (errorCount: number): void => { // Do nothing @@ -1009,7 +1007,7 @@ export class TypeScriptBuilder { const solutionBuilderHost: TTypescript.SolutionBuilderHost = ts.createSolutionBuilderHost( system, - this._getCreateBuilderProgram(ts), + this.#getCreateBuilderProgram(ts), tool.reportDiagnostic, reportSolutionBuilderStatus, reportEmitErrorSummary @@ -1019,7 +1017,7 @@ export class TypeScriptBuilder { program: TTypescript.EmitAndSemanticDiagnosticsBuilderProgram ) => { // Use the native metric since we aren't overwriting the writer - this._typescriptTerminal.writeVerboseLine( + this.#typescriptTerminal.writeVerboseLine( `I/O Write: ${ts.performance.getDuration('I/O Write')}ms (${ts.performance.getCount( 'beforeIOWrite' )} files)` @@ -1029,7 +1027,7 @@ export class TypeScriptBuilder { return solutionBuilderHost; } - private _buildIncrementalCompilerHost( + #buildIncrementalCompilerHost( tool: ITypeScriptTool, tsconfig: TTypescript.ParsedCommandLine ): TTypescript.CompilerHost { @@ -1047,26 +1045,26 @@ export class TypeScriptBuilder { ); } - this._changeCompilerHostToUseCache(compilerHost, tool); + this.#changeCompilerHostToUseCache(compilerHost, tool); return compilerHost; } - private _buildWatchCompilerHost( + #buildWatchCompilerHost( tool: ITypeScriptTool, tsconfig: TTypescript.ParsedCommandLine ): TWatchCompilerHost { const { ts, system } = tool; const reportWatchStatus: TTypescript.DiagnosticReporter = (diagnostic: TTypescript.Diagnostic): void => { - this._printDiagnosticMessage(ts, diagnostic); + this.#printDiagnosticMessage(ts, diagnostic); }; const compilerHost: TWatchCompilerHost = ts.createWatchCompilerHost( tsconfig.fileNames, tsconfig.options, system, - this._getCreateBuilderProgram(ts), + this.#getCreateBuilderProgram(ts), tool.reportDiagnostic, reportWatchStatus, tsconfig.projectReferences, @@ -1076,7 +1074,7 @@ export class TypeScriptBuilder { return compilerHost; } - private _changeCompilerHostToUseCache(compilerHost: TTypescript.CompilerHost, tool: ITypeScriptTool): void { + #changeCompilerHostToUseCache(compilerHost: TTypescript.CompilerHost, tool: ITypeScriptTool): void { const { sourceFileCache } = tool; const { getSourceFile: innerGetSourceFile } = compilerHost; @@ -1084,7 +1082,7 @@ export class TypeScriptBuilder { return; } - compilerHost.getCurrentDirectory = () => this._configuration.buildFolderPath; + compilerHost.getCurrentDirectory = () => this.#configuration.buildFolderPath; // Enable source file persistence const getSourceFile: typeof innerGetSourceFile & { @@ -1121,12 +1119,12 @@ export class TypeScriptBuilder { compilerHost.getSourceFile = getSourceFile; } - private _buildWatchSolutionBuilderHost(tool: ITypeScriptTool): TWatchSolutionHost { + #buildWatchSolutionBuilderHost(tool: ITypeScriptTool): TWatchSolutionHost { const { reportDiagnostic, ts, system } = tool; const host: TWatchSolutionHost = ts.createSolutionBuilderWithWatchHost( system, - this._getCreateBuilderProgram(ts), + this.#getCreateBuilderProgram(ts), reportDiagnostic, reportDiagnostic, reportDiagnostic @@ -1140,8 +1138,8 @@ export class TypeScriptBuilder { * `package.json` with the appropriate `"type"` field to ensure Node.js correctly * interprets `.js` files in the output folder. */ - private _emitModulePackageJsonFiles(ts: ExtendedTypeScript): void { - for (const { emitModulePackageJson, moduleKind, outFolderPath } of this._moduleKindsToEmit) { + #emitModulePackageJsonFiles(ts: ExtendedTypeScript): void { + for (const { emitModulePackageJson, moduleKind, outFolderPath } of this.#moduleKindsToEmit) { if (!emitModulePackageJson) { continue; } @@ -1176,7 +1174,7 @@ export class TypeScriptBuilder { const packageJsonContent: string = `{\n "type": "${moduleType}"\n}\n`; ts.sys.writeFile(packageJsonPath, packageJsonContent); - this._typescriptTerminal.writeVerboseLine(`Wrote ${packageJsonPath} with "type": "${moduleType}"`); + this.#typescriptTerminal.writeVerboseLine(`Wrote ${packageJsonPath} with "type": "${moduleType}"`); } else { throw new Error( `Unsupported module kind ${ts.ModuleKind[moduleKind]} for package.json generation. ` + @@ -1186,7 +1184,7 @@ export class TypeScriptBuilder { } } - private _parseModuleKind(ts: ExtendedTypeScript, moduleKindName: string): TTypescript.ModuleKind { + #parseModuleKind(ts: ExtendedTypeScript, moduleKindName: string): TTypescript.ModuleKind { switch (moduleKindName.toLowerCase()) { case 'commonjs': return ts.ModuleKind.CommonJS; @@ -1211,7 +1209,7 @@ export class TypeScriptBuilder { } } - private _queueTranspileInWorker( + #queueTranspileInWorker( tool: ITypeScriptTool, compilerOptions: TTypescript.CompilerOptions, filesToTranspile: Map @@ -1235,14 +1233,14 @@ export class TypeScriptBuilder { if (signal) { signal.reject(error); } else { - this._typescriptTerminal.writeErrorLine( + this.#typescriptTerminal.writeErrorLine( `Unexpected worker rejection for request with id ${resolvingRequestId}: ${error}` ); } } else if (signal) { signal.resolve(result); } else { - this._typescriptTerminal.writeErrorLine( + this.#typescriptTerminal.writeErrorLine( `Unexpected worker resolution for request with id ${resolvingRequestId}` ); } @@ -1272,16 +1270,16 @@ export class TypeScriptBuilder { // make linter happy const worker: Worker = maybeWorker; - const requestId: number = ++this._nextRequestId; + const requestId: number = ++this.#nextRequestId; const transpilePromise: Promise = new Promise( (resolve: (result: TTypescript.EmitResult) => void, reject: (err: Error) => void) => { pendingTranspileSignals.set(requestId, { resolve, reject }); - this._typescriptTerminal.writeLine(`Asynchronously transpiling ${compilerOptions.configFilePath}`); + this.#typescriptTerminal.writeLine(`Asynchronously transpiling ${compilerOptions.configFilePath}`); const request: ITranspilationRequestMessage = { compilerOptions, filesToTranspile, - moduleKindsToEmit: this._moduleKindsToEmit, + moduleKindsToEmit: this.#moduleKindsToEmit, requestId }; @@ -1292,8 +1290,8 @@ export class TypeScriptBuilder { pendingTranspilePromises.set(requestId, transpilePromise); } - private _cleanupWorker(): void { - const tool: ITypeScriptTool | undefined = this._tool; + #cleanupWorker(): void { + const tool: ITypeScriptTool | undefined = this.#tool; if (!tool) { return; } diff --git a/heft-plugins/heft-typescript-plugin/src/TypeScriptPlugin.ts b/heft-plugins/heft-typescript-plugin/src/TypeScriptPlugin.ts index 6fb6eb72647..32dff7658e2 100644 --- a/heft-plugins/heft-typescript-plugin/src/TypeScriptPlugin.ts +++ b/heft-plugins/heft-typescript-plugin/src/TypeScriptPlugin.ts @@ -259,7 +259,7 @@ export default class TypeScriptPlugin implements IHeftTaskPlugin { // all source files to this set of static assets. This would allow us to avoid // having to copy the static assets multiple times, increasing build times and // package size. - for (const copyOperation of await this._getStaticAssetCopyOperationsAsync( + for (const copyOperation of await this.#getStaticAssetCopyOperationsAsync( taskSession, heftConfiguration )) { @@ -271,7 +271,7 @@ export default class TypeScriptPlugin implements IHeftTaskPlugin { ); taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { - const builder: TypeScriptBuilder | false = await this._getTypeScriptBuilderAsync( + const builder: TypeScriptBuilder | false = await this.#getTypeScriptBuilderAsync( taskSession, heftConfiguration ); @@ -286,7 +286,7 @@ export default class TypeScriptPlugin implements IHeftTaskPlugin { async (runIncrementalOptions: IHeftTaskRunIncrementalHookOptions) => { if (incrementalBuilder === undefined) { // eslint-disable-next-line require-atomic-updates - incrementalBuilder = await this._getTypeScriptBuilderAsync(taskSession, heftConfiguration); + incrementalBuilder = await this.#getTypeScriptBuilderAsync(taskSession, heftConfiguration); } if (incrementalBuilder) { @@ -296,11 +296,11 @@ export default class TypeScriptPlugin implements IHeftTaskPlugin { ); } - private async _getStaticAssetCopyOperationsAsync( + async #getStaticAssetCopyOperationsAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration ): Promise { - const { typeScriptConfigurationJson, partialTsconfigFile } = await this._loadConfigAsync( + const { typeScriptConfigurationJson, partialTsconfigFile } = await this.#loadConfigAsync( taskSession, heftConfiguration ); @@ -341,11 +341,11 @@ export default class TypeScriptPlugin implements IHeftTaskPlugin { return copyOperations; } - private async _getTypeScriptBuilderAsync( + async #getTypeScriptBuilderAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration ): Promise { - const { typeScriptConfigurationJson, partialTsconfigFile } = await this._loadConfigAsync( + const { typeScriptConfigurationJson, partialTsconfigFile } = await this.#loadConfigAsync( taskSession, heftConfiguration ); @@ -391,7 +391,7 @@ export default class TypeScriptPlugin implements IHeftTaskPlugin { return typeScriptBuilder; } - private async _loadConfigAsync( + async #loadConfigAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration ): Promise { diff --git a/heft-plugins/heft-typescript-plugin/src/fileSystem/TypeScriptCachedFileSystem.ts b/heft-plugins/heft-typescript-plugin/src/fileSystem/TypeScriptCachedFileSystem.ts index ca76573d285..a3039343bd4 100644 --- a/heft-plugins/heft-typescript-plugin/src/fileSystem/TypeScriptCachedFileSystem.ts +++ b/heft-plugins/heft-typescript-plugin/src/fileSystem/TypeScriptCachedFileSystem.ts @@ -33,10 +33,10 @@ interface ICacheEntry { * instance. */ export class TypeScriptCachedFileSystem { - private _statsCache: Map> = new Map(); - private _readFolderCache: Map> = new Map(); - private _readFileCache: Map> = new Map(); - private _realPathCache: Map> = new Map(); + #statsCache: Map> = new Map(); + #readFolderCache: Map> = new Map(); + #readFileCache: Map> = new Map(); + #realPathCache: Map> = new Map(); public exists: (path: string) => boolean = (path: string) => { try { @@ -65,20 +65,20 @@ export class TypeScriptCachedFileSystem { }; public getStatistics: (path: string) => FileSystemStats = (path: string) => { - return this._withCaching(path, FileSystem.getStatistics, this._statsCache); + return this.#withCaching(path, FileSystem.getStatistics, this.#statsCache); }; public ensureFolder: (folderPath: string) => void = (folderPath: string) => { - if (!this._readFolderCache.get(folderPath)?.entry && !this._statsCache.get(folderPath)?.entry) { + if (!this.#readFolderCache.get(folderPath)?.entry && !this.#statsCache.get(folderPath)?.entry) { FileSystem.ensureFolder(folderPath); - this._invalidateCacheEntry(folderPath); + this.#invalidateCacheEntry(folderPath); } }; public ensureFolderAsync: (folderPath: string) => Promise = async (folderPath: string) => { - if (!this._readFolderCache.get(folderPath)?.entry && !this._statsCache.get(folderPath)?.entry) { + if (!this.#readFolderCache.get(folderPath)?.entry && !this.#statsCache.get(folderPath)?.entry) { await FileSystem.ensureFolderAsync(folderPath); - this._invalidateCacheEntry(folderPath); + this.#invalidateCacheEntry(folderPath); } }; @@ -92,7 +92,7 @@ export class TypeScriptCachedFileSystem { options?: IFileSystemWriteFileOptions | undefined ) => { FileSystem.writeFile(filePath, contents, options); - this._invalidateCacheEntry(filePath); + this.#invalidateCacheEntry(filePath); }; public readFile: (filePath: string, options?: IFileSystemReadFileOptions | undefined) => string = ( @@ -108,24 +108,24 @@ export class TypeScriptCachedFileSystem { }; public readFileToBuffer: (filePath: string) => Buffer = (filePath: string) => { - return this._withCaching(filePath, FileSystem.readFileToBuffer, this._readFileCache); + return this.#withCaching(filePath, FileSystem.readFileToBuffer, this.#readFileCache); }; public copyFileAsync: (options: IFileSystemCopyFileOptions) => Promise = async ( options: IFileSystemCopyFileOptions ) => { await FileSystem.copyFileAsync(options); - this._invalidateCacheEntry(options.destinationPath); + this.#invalidateCacheEntry(options.destinationPath); }; public deleteFile: (filePath: string, options?: IFileSystemDeleteFileOptions | undefined) => void = ( filePath: string, options?: IFileSystemDeleteFileOptions | undefined ) => { - const cachedError: Error | undefined = this._statsCache.get(filePath)?.error; + const cachedError: Error | undefined = this.#statsCache.get(filePath)?.error; if (!cachedError || !FileSystem.isFileDoesNotExistError(cachedError)) { FileSystem.deleteFile(filePath); - this._invalidateCacheEntry(filePath); + this.#invalidateCacheEntry(filePath); } else if (options?.throwIfNotExists) { throw cachedError; } @@ -135,11 +135,11 @@ export class TypeScriptCachedFileSystem { options: IFileSystemCreateLinkOptions ) => { await FileSystem.createHardLinkAsync(options); - this._invalidateCacheEntry(options.newLinkPath); + this.#invalidateCacheEntry(options.newLinkPath); }; public getRealPath: (linkPath: string) => string = (linkPath: string) => { - return this._withCaching( + return this.#withCaching( linkPath, (path: string) => { try { @@ -153,24 +153,24 @@ export class TypeScriptCachedFileSystem { } } }, - this._realPathCache + this.#realPathCache ); }; public readFolderFilesAndDirectories: (folderPath: string) => IReadFolderFilesAndDirectoriesResult = ( folderPath: string ) => { - return this._withCaching( + return this.#withCaching( folderPath, (path: string) => { const folderEntries: FolderItem[] = FileSystem.readFolderItems(path); - return this._sortFolderEntries(folderEntries); + return this.#sortFolderEntries(folderEntries); }, - this._readFolderCache + this.#readFolderCache ); }; - private _sortFolderEntries(folderEntries: FolderItem[]): IReadFolderFilesAndDirectoriesResult { + #sortFolderEntries(folderEntries: FolderItem[]): IReadFolderFilesAndDirectoriesResult { // TypeScript expects entries sorted ordinally by name // In practice this might not matter folderEntries.sort((a, b) => Sort.compareByValue(a, b)); @@ -188,7 +188,7 @@ export class TypeScriptCachedFileSystem { return { files, directories }; } - private _withCaching( + #withCaching( path: string, fn: (path: string) => TResult, cache: Map> @@ -211,10 +211,10 @@ export class TypeScriptCachedFileSystem { } } - private _invalidateCacheEntry(path: string): void { - this._statsCache.delete(path); - this._readFolderCache.delete(path); - this._readFileCache.delete(path); - this._realPathCache.delete(path); + #invalidateCacheEntry(path: string): void { + this.#statsCache.delete(path); + this.#readFolderCache.delete(path); + this.#readFileCache.delete(path); + this.#realPathCache.delete(path); } } diff --git a/heft-plugins/heft-webpack4-plugin/src/DeferredWatchFileSystem.ts b/heft-plugins/heft-webpack4-plugin/src/DeferredWatchFileSystem.ts index e3032c9a541..d0f719a2041 100644 --- a/heft-plugins/heft-webpack4-plugin/src/DeferredWatchFileSystem.ts +++ b/heft-plugins/heft-webpack4-plugin/src/DeferredWatchFileSystem.ts @@ -67,8 +67,8 @@ export class DeferredWatchFileSystem implements IWatchFileSystem { public readonly watcherOptions: WatchOptions; public watcher: Watchpack | undefined; - private readonly _onChange: () => void; - private _state: IWatchState | undefined; + readonly #onChange: () => void; + #state: IWatchState | undefined; public constructor(inputFileSystem: IPurgeable, onChange: () => void) { this.inputFileSystem = inputFileSystem; @@ -76,11 +76,11 @@ export class DeferredWatchFileSystem implements IWatchFileSystem { aggregateTimeout: 0 }; this.watcher = new Watchpack(this.watcherOptions); - this._onChange = onChange; + this.#onChange = onChange; } public flush(): boolean { - const state: IWatchState | undefined = this._state; + const state: IWatchState | undefined = this.#state; if (!state) { return false; @@ -136,7 +136,7 @@ export class DeferredWatchFileSystem implements IWatchFileSystem { const changes: Set = new Set(); const removals: Set = new Set(); - this._state = { + this.#state = { files: new Set(files), dirs: new Set(directories), missing: new Set(missing), @@ -158,7 +158,7 @@ export class DeferredWatchFileSystem implements IWatchFileSystem { removals.add(removal); } - this._onChange(); + this.#onChange(); }); watcher.watch({ @@ -198,16 +198,16 @@ export class DeferredWatchFileSystem implements IWatchFileSystem { export class OverrideNodeWatchFSPlugin implements Plugin { public readonly fileSystems: Set = new Set(); - private readonly _onChange: () => void; + readonly #onChange: () => void; public constructor(onChange: () => void) { - this._onChange = onChange; + this.#onChange = onChange; } public apply(compiler: Compiler): void { const watchFileSystem: DeferredWatchFileSystem = new DeferredWatchFileSystem( compiler.inputFileSystem, - this._onChange + this.#onChange ); this.fileSystems.add(watchFileSystem); (compiler as { watchFileSystem?: IWatchFileSystem }).watchFileSystem = watchFileSystem; diff --git a/heft-plugins/heft-webpack4-plugin/src/Webpack4Plugin.ts b/heft-plugins/heft-webpack4-plugin/src/Webpack4Plugin.ts index 644f585c8e8..c8d9fc7cff7 100644 --- a/heft-plugins/heft-webpack4-plugin/src/Webpack4Plugin.ts +++ b/heft-plugins/heft-webpack4-plugin/src/Webpack4Plugin.ts @@ -74,28 +74,28 @@ const WEBPACK_DEV_MIDDLEWARE_PACKAGE_NAME: 'webpack-dev-middleware' = 'webpack-d * @internal */ export default class Webpack4Plugin implements IHeftTaskPlugin { - private _accessor: IWebpackPluginAccessor | undefined; - private _isServeMode: boolean = false; - private _webpack: typeof TWebpack | undefined; - private _webpackCompiler: ExtendedCompiler | ExtendedMultiCompiler | undefined; - private _webpackConfiguration: IWebpackConfiguration | undefined | false = false; - private _webpackCompilationDonePromise: Promise | undefined; - private _webpackCompilationDonePromiseResolveFn: (() => void) | undefined; - private _watchFileSystems: Set | undefined; - - private _warnings: Error[] = []; - private _errors: Error[] = []; + #accessor: IWebpackPluginAccessor | undefined; + #isServeMode: boolean = false; + #webpack: typeof TWebpack | undefined; + #webpackCompiler: ExtendedCompiler | ExtendedMultiCompiler | undefined; + #webpackConfiguration: IWebpackConfiguration | undefined | false = false; + #webpackCompilationDonePromise: Promise | undefined; + #webpackCompilationDonePromiseResolveFn: (() => void) | undefined; + #watchFileSystems: Set | undefined; + + #warnings: Error[] = []; + #errors: Error[] = []; public get accessor(): IWebpackPluginAccessor { - if (!this._accessor) { - this._accessor = { + if (!this.#accessor) { + this.#accessor = { hooks: _createAccessorHooks(), parameters: { - isServeMode: this._isServeMode + isServeMode: this.#isServeMode } }; } - return this._accessor; + return this.#accessor; } public apply( @@ -103,8 +103,8 @@ export default class Webpack4Plugin implements IHeftTaskPlugin { - await this._runWebpackAsync(taskSession, heftConfiguration, options); + await this.#runWebpackAsync(taskSession, heftConfiguration, options); }); taskSession.hooks.runIncremental.tapPromise( PLUGIN_NAME, async (runOptions: IHeftTaskRunIncrementalHookOptions) => { - await this._runWebpackWatchAsync(taskSession, heftConfiguration, options, runOptions.requestRun); + await this.#runWebpackWatchAsync(taskSession, heftConfiguration, options, runOptions.requestRun); } ); } - private async _getWebpackConfigurationAsync( + async #getWebpackConfigurationAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, options: IWebpackPluginOptions, requestRun?: () => void ): Promise { - if (this._webpackConfiguration === false) { + if (this.#webpackConfiguration === false) { const webpackConfiguration: IWebpackConfiguration | undefined = await tryLoadWebpackConfigurationAsync( { taskSession, heftConfiguration, hooks: this.accessor.hooks, - serveMode: this._isServeMode, - loadWebpackAsyncFn: this._loadWebpackAsync.bind(this) + serveMode: this.#isServeMode, + loadWebpackAsyncFn: this.#loadWebpackAsync.bind(this) }, options ); if (webpackConfiguration && requestRun) { const overrideWatchFSPlugin: OverrideNodeWatchFSPlugin = new OverrideNodeWatchFSPlugin(requestRun); - this._watchFileSystems = overrideWatchFSPlugin.fileSystems; + this.#watchFileSystems = overrideWatchFSPlugin.fileSystems; for (const config of Array.isArray(webpackConfiguration) ? webpackConfiguration : [webpackConfiguration]) { @@ -156,49 +156,49 @@ export default class Webpack4Plugin implements IHeftTaskPlugin { - if (!this._webpack) { + async #loadWebpackAsync(): Promise { + if (!this.#webpack) { // Allow this to fail if webpack is not installed - this._webpack = await import(WEBPACK_PACKAGE_NAME); + this.#webpack = await import(WEBPACK_PACKAGE_NAME); } - return this._webpack!; + return this.#webpack!; } - private async _getWebpackCompilerAsync( + async #getWebpackCompilerAsync( taskSession: IHeftTaskSession, webpackConfiguration: IWebpackConfiguration ): Promise { - if (!this._webpackCompiler) { - const webpack: typeof TWebpack = await this._loadWebpackAsync(); + if (!this.#webpackCompiler) { + const webpack: typeof TWebpack = await this.#loadWebpackAsync(); taskSession.logger.terminal.writeLine(`Using Webpack version ${webpack.version}`); - this._webpackCompiler = Array.isArray(webpackConfiguration) + this.#webpackCompiler = Array.isArray(webpackConfiguration) ? (webpack.default( webpackConfiguration ) as ExtendedMultiCompiler) /* (webpack.Compilation[]) => MultiCompiler */ : (webpack.default(webpackConfiguration) as ExtendedCompiler); /* (webpack.Compilation) => Compiler */ } - return this._webpackCompiler; + return this.#webpackCompiler; } - private async _runWebpackAsync( + async #runWebpackAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, options: IWebpackPluginOptions ): Promise { - this._validateEnvironmentVariable(taskSession); - if (taskSession.parameters.watch || this._isServeMode) { + this.#validateEnvironmentVariable(taskSession); + if (taskSession.parameters.watch || this.#isServeMode) { // Should never happen, but just in case throw new InternalError('Cannot run Webpack in compilation mode when watch mode is enabled'); } // Load the config and compiler, and return if there is no config found - const webpackConfiguration: IWebpackConfiguration | undefined = await this._getWebpackConfigurationAsync( + const webpackConfiguration: IWebpackConfiguration | undefined = await this.#getWebpackConfigurationAsync( taskSession, heftConfiguration, options @@ -206,7 +206,7 @@ export default class Webpack4Plugin implements IHeftTaskPlugin { // Save a handle to the original promise, since the this-scoped promise will be replaced whenever // the compilation completes. - let webpackCompilationDonePromise: Promise | undefined = this._webpackCompilationDonePromise; + let webpackCompilationDonePromise: Promise | undefined = this.#webpackCompilationDonePromise; let isInitial: boolean = false; - if (!this._webpackCompiler) { + if (!this.#webpackCompiler) { isInitial = true; - this._validateEnvironmentVariable(taskSession); + this.#validateEnvironmentVariable(taskSession); if (!taskSession.parameters.watch) { // Should never happen, but just in case throw new InternalError('Cannot run Webpack in watch mode when compilation mode is enabled'); @@ -254,36 +254,36 @@ export default class Webpack4Plugin implements IHeftTaskPlugin void) => { - this._webpackCompilationDonePromiseResolveFn = resolve; + this.#webpackCompilationDonePromise = new Promise((resolve: () => void) => { + this.#webpackCompilationDonePromiseResolveFn = resolve; }); - webpackCompilationDonePromise = this._webpackCompilationDonePromise; + webpackCompilationDonePromise = this.#webpackCompilationDonePromise; compiler.hooks.done.tap(PLUGIN_NAME, (stats?: TWebpack.Stats | TWebpack.MultiStats) => { - this._webpackCompilationDonePromiseResolveFn!(); - this._webpackCompilationDonePromise = new Promise((resolve: () => void) => { - this._webpackCompilationDonePromiseResolveFn = resolve; + this.#webpackCompilationDonePromiseResolveFn!(); + this.#webpackCompilationDonePromise = new Promise((resolve: () => void) => { + this.#webpackCompilationDonePromiseResolveFn = resolve; }); if (stats) { - this._recordErrors(stats); + this.#recordErrors(stats); } }); // Determine how we will run the compiler. When serving, we will run the compiler // via the webpack-dev-server. Otherwise, we will run the compiler directly. - if (this._isServeMode) { + if (this.#isServeMode) { const defaultDevServerOptions: TWebpackDevServer.Configuration = { host: 'localhost', devMiddleware: { @@ -396,9 +396,9 @@ export default class Webpack4Plugin implements IHeftTaskPlugin void; - private _state: IWatchState | undefined; + readonly #onChange: () => void; + #state: IWatchState | undefined; public constructor(inputFileSystem: InputFileSystem, onChange: () => void) { this.inputFileSystem = inputFileSystem; @@ -45,11 +45,11 @@ export class DeferredWatchFileSystem implements WatchFileSystem { aggregateTimeout: 0 }; this.watcher = new Watchpack(this.watcherOptions); - this._onChange = onChange; + this.#onChange = onChange; } public flush(): boolean { - const state: IWatchState | undefined = this._state; + const state: IWatchState | undefined = this.#state; if (!state) { return false; @@ -75,9 +75,9 @@ export class DeferredWatchFileSystem implements WatchFileSystem { } if (changes.size > 0 || removals.size > 0) { - this._purge(removals, changes); + this.#purge(removals, changes); - const { fileTimeInfoEntries, contextTimeInfoEntries } = this._fetchTimeInfo(); + const { fileTimeInfoEntries, contextTimeInfoEntries } = this.#fetchTimeInfo(); callback(null, fileTimeInfoEntries, contextTimeInfoEntries, changes, removals); @@ -105,7 +105,7 @@ export class DeferredWatchFileSystem implements WatchFileSystem { const changes: Set = new Set(); const removals: Set = new Set(); - this._state = { + this.#state = { changes, removals, @@ -122,7 +122,7 @@ export class DeferredWatchFileSystem implements WatchFileSystem { removals.add(removal); } - this._onChange(); + this.#onChange(); }); this.watcher.watch({ @@ -151,8 +151,8 @@ export class DeferredWatchFileSystem implements WatchFileSystem { getInfo: () => { const newRemovals: Set | undefined = this.watcher?.aggregatedRemovals; const newChanges: Set | undefined = this.watcher?.aggregatedChanges; - this._purge(newRemovals, newChanges); - const { fileTimeInfoEntries, contextTimeInfoEntries } = this._fetchTimeInfo(); + this.#purge(newRemovals, newChanges); + const { fileTimeInfoEntries, contextTimeInfoEntries } = this.#fetchTimeInfo(); return { changes: newChanges!, removals: newRemovals!, @@ -161,24 +161,24 @@ export class DeferredWatchFileSystem implements WatchFileSystem { }; }, getContextTimeInfoEntries: () => { - const { contextTimeInfoEntries } = this._fetchTimeInfo(); + const { contextTimeInfoEntries } = this.#fetchTimeInfo(); return contextTimeInfoEntries; }, getFileTimeInfoEntries: () => { - const { fileTimeInfoEntries } = this._fetchTimeInfo(); + const { fileTimeInfoEntries } = this.#fetchTimeInfo(); return fileTimeInfoEntries; } }; } - private _fetchTimeInfo(): ITimeInfoEntries { + #fetchTimeInfo(): ITimeInfoEntries { const fileTimeInfoEntries: IRawFileSystemMap = new Map(); const contextTimeInfoEntries: IRawFileSystemMap = new Map(); this.watcher?.collectTimeInfoEntries(fileTimeInfoEntries, contextTimeInfoEntries); return { fileTimeInfoEntries, contextTimeInfoEntries }; } - private _purge(removals: Set | undefined, changes: Set | undefined): void { + #purge(removals: Set | undefined, changes: Set | undefined): void { const fs: InputFileSystem = this.inputFileSystem; if (fs.purge) { if (removals) { @@ -197,10 +197,10 @@ export class DeferredWatchFileSystem implements WatchFileSystem { export class OverrideNodeWatchFSPlugin implements WebpackPluginInstance { public readonly fileSystems: Set = new Set(); - private readonly _onChange: () => void; + readonly #onChange: () => void; public constructor(onChange: () => void) { - this._onChange = onChange; + this.#onChange = onChange; } public apply(compiler: Compiler): void { @@ -211,7 +211,7 @@ export class OverrideNodeWatchFSPlugin implements WebpackPluginInstance { const watchFileSystem: DeferredWatchFileSystem = new DeferredWatchFileSystem( inputFileSystem, - this._onChange + this.#onChange ); this.fileSystems.add(watchFileSystem); compiler.watchFileSystem = watchFileSystem; diff --git a/heft-plugins/heft-webpack5-plugin/src/Webpack5Plugin.ts b/heft-plugins/heft-webpack5-plugin/src/Webpack5Plugin.ts index 59bf0c4b725..bfa7e1e0dde 100644 --- a/heft-plugins/heft-webpack5-plugin/src/Webpack5Plugin.ts +++ b/heft-plugins/heft-webpack5-plugin/src/Webpack5Plugin.ts @@ -41,28 +41,28 @@ const WEBPACK_DEV_MIDDLEWARE_PACKAGE_NAME: 'webpack-dev-middleware' = 'webpack-d * @internal */ export default class Webpack5Plugin implements IHeftTaskPlugin { - private _accessor: IWebpackPluginAccessor | undefined; - private _isServeMode: boolean = false; - private _webpack: typeof TWebpack | undefined; - private _webpackCompiler: TWebpack.Compiler | TWebpack.MultiCompiler | undefined; - private _webpackConfiguration: IWebpackConfiguration | undefined | false = false; - private _webpackCompilationDonePromise: Promise | undefined; - private _webpackCompilationDonePromiseResolveFn: (() => void) | undefined; - private _watchFileSystems: Set | undefined; - - private _warnings: Error[] = []; - private _errors: Error[] = []; + #accessor: IWebpackPluginAccessor | undefined; + #isServeMode: boolean = false; + #webpack: typeof TWebpack | undefined; + #webpackCompiler: TWebpack.Compiler | TWebpack.MultiCompiler | undefined; + #webpackConfiguration: IWebpackConfiguration | undefined | false = false; + #webpackCompilationDonePromise: Promise | undefined; + #webpackCompilationDonePromiseResolveFn: (() => void) | undefined; + #watchFileSystems: Set | undefined; + + #warnings: Error[] = []; + #errors: Error[] = []; public get accessor(): IWebpackPluginAccessor { - if (!this._accessor) { - this._accessor = { + if (!this.#accessor) { + this.#accessor = { hooks: _createAccessorHooks(), parameters: { - isServeMode: this._isServeMode + isServeMode: this.#isServeMode } }; } - return this._accessor; + return this.#accessor; } public apply( @@ -70,8 +70,8 @@ export default class Webpack5Plugin implements IHeftTaskPlugin { - await this._runWebpackAsync(taskSession, heftConfiguration, options); + await this.#runWebpackAsync(taskSession, heftConfiguration, options); }); taskSession.hooks.runIncremental.tapPromise( PLUGIN_NAME, async (runOptions: IHeftTaskRunIncrementalHookOptions) => { - await this._runWebpackWatchAsync(taskSession, heftConfiguration, options, runOptions.requestRun); + await this.#runWebpackWatchAsync(taskSession, heftConfiguration, options, runOptions.requestRun); } ); } - private async _getWebpackConfigurationAsync( + async #getWebpackConfigurationAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, options: IWebpackPluginOptions, requestRun?: () => void ): Promise { - if (this._webpackConfiguration === false) { + if (this.#webpackConfiguration === false) { const webpackConfiguration: IWebpackConfiguration | undefined = await tryLoadWebpackConfigurationAsync( { taskSession, heftConfiguration, hooks: this.accessor.hooks, - serveMode: this._isServeMode, - loadWebpackAsyncFn: this._loadWebpackAsync.bind(this, taskSession, heftConfiguration) + serveMode: this.#isServeMode, + loadWebpackAsyncFn: this.#loadWebpackAsync.bind(this, taskSession, heftConfiguration) }, options ); if (webpackConfiguration && requestRun) { const overrideWatchFSPlugin: OverrideNodeWatchFSPlugin = new OverrideNodeWatchFSPlugin(requestRun); - this._watchFileSystems = overrideWatchFSPlugin.fileSystems; + this.#watchFileSystems = overrideWatchFSPlugin.fileSystems; for (const config of Array.isArray(webpackConfiguration) ? webpackConfiguration : [webpackConfiguration]) { @@ -125,61 +125,61 @@ export default class Webpack5Plugin implements IHeftTaskPlugin { - if (!this._webpack) { + if (!this.#webpack) { try { const webpackPackagePath: string = await heftConfiguration.rigPackageResolver.resolvePackageAsync( WEBPACK_PACKAGE_NAME, taskSession.logger.terminal ); - this._webpack = await import(webpackPackagePath); + this.#webpack = await import(webpackPackagePath); taskSession.logger.terminal.writeDebugLine(`Using Webpack from rig package at "${webpackPackagePath}"`); } catch (e) { // Fallback to bundled version if not found in rig. - this._webpack = await import(WEBPACK_PACKAGE_NAME); + this.#webpack = await import(WEBPACK_PACKAGE_NAME); taskSession.logger.terminal.writeDebugLine(`Using Webpack from built-in "${WEBPACK_PACKAGE_NAME}"`); } } - return this._webpack!; + return this.#webpack!; } - private async _getWebpackCompilerAsync( + async #getWebpackCompilerAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, webpackConfiguration: IWebpackConfiguration ): Promise { - if (!this._webpackCompiler) { - const webpack: typeof TWebpack = await this._loadWebpackAsync(taskSession, heftConfiguration); + if (!this.#webpackCompiler) { + const webpack: typeof TWebpack = await this.#loadWebpackAsync(taskSession, heftConfiguration); taskSession.logger.terminal.writeLine(`Using Webpack version ${webpack.version}`); - this._webpackCompiler = Array.isArray(webpackConfiguration) + this.#webpackCompiler = Array.isArray(webpackConfiguration) ? webpack.default(webpackConfiguration) /* (webpack.Compilation[]) => MultiCompiler */ : webpack.default(webpackConfiguration); /* (webpack.Compilation) => Compiler */ } - return this._webpackCompiler; + return this.#webpackCompiler; } - private async _runWebpackAsync( + async #runWebpackAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, options: IWebpackPluginOptions ): Promise { - this._validateEnvironmentVariable(taskSession); - if (taskSession.parameters.watch || this._isServeMode) { + this.#validateEnvironmentVariable(taskSession); + if (taskSession.parameters.watch || this.#isServeMode) { // Should never happen, but just in case throw new InternalError('Cannot run Webpack in compilation mode when watch mode is enabled'); } // Load the config and compiler, and return if there is no config found - const webpackConfiguration: IWebpackConfiguration | undefined = await this._getWebpackConfigurationAsync( + const webpackConfiguration: IWebpackConfiguration | undefined = await this.#getWebpackConfigurationAsync( taskSession, heftConfiguration, options @@ -187,7 +187,7 @@ export default class Webpack5Plugin implements IHeftTaskPlugin { // Save a handle to the original promise, since the this-scoped promise will be replaced whenever // the compilation completes. - let webpackCompilationDonePromise: Promise | undefined = this._webpackCompilationDonePromise; + let webpackCompilationDonePromise: Promise | undefined = this.#webpackCompilationDonePromise; let isInitial: boolean = false; - if (!this._webpackCompiler) { + if (!this.#webpackCompiler) { isInitial = true; - this._validateEnvironmentVariable(taskSession); + this.#validateEnvironmentVariable(taskSession); if (!taskSession.parameters.watch) { // Should never happen, but just in case throw new InternalError('Cannot run Webpack in watch mode when watch mode is not enabled'); @@ -237,13 +237,13 @@ export default class Webpack5Plugin implements IHeftTaskPlugin void) => { - this._webpackCompilationDonePromiseResolveFn = resolve; + this.#webpackCompilationDonePromise = new Promise((resolve: () => void) => { + this.#webpackCompilationDonePromiseResolveFn = resolve; }); - webpackCompilationDonePromise = this._webpackCompilationDonePromise; + webpackCompilationDonePromise = this.#webpackCompilationDonePromise; compiler.hooks.done.tap(PLUGIN_NAME, (stats?: TWebpack.Stats | TWebpack.MultiStats) => { - this._webpackCompilationDonePromiseResolveFn!(); - this._webpackCompilationDonePromise = new Promise((resolve: () => void) => { - this._webpackCompilationDonePromiseResolveFn = resolve; + this.#webpackCompilationDonePromiseResolveFn!(); + this.#webpackCompilationDonePromise = new Promise((resolve: () => void) => { + this.#webpackCompilationDonePromiseResolveFn = resolve; }); if (stats) { - this._recordErrors(stats, heftConfiguration.buildFolderPath); + this.#recordErrors(stats, heftConfiguration.buildFolderPath); } }); // Determine how we will run the compiler. When serving, we will run the compiler // via the webpack-dev-server. Otherwise, we will run the compiler directly. - if (this._isServeMode) { + if (this.#isServeMode) { const defaultDevServerOptions: TWebpackDevServer.Configuration = { host: 'localhost', devMiddleware: { @@ -397,9 +397,9 @@ export default class Webpack5Plugin implements IHeftTaskPlugin { if (!this.expression) { - this.expression = await this._collectAssetsAndGetExpressionAsync(compilation, globFs); + this.expression = await this.#collectAssetsAndGetExpressionAsync(compilation, globFs); } } - private async _collectAssetsAndGetExpressionAsync( + async #collectAssetsAndGetExpressionAsync( compilation: webpack.Compilation, globFs: glob.FileSystemAdapter ): Promise { diff --git a/webpack/set-webpack-public-path-plugin/src/SetPublicPathPlugin.ts b/webpack/set-webpack-public-path-plugin/src/SetPublicPathPlugin.ts index a380fa91989..5f5085786df 100644 --- a/webpack/set-webpack-public-path-plugin/src/SetPublicPathPlugin.ts +++ b/webpack/set-webpack-public-path-plugin/src/SetPublicPathPlugin.ts @@ -123,11 +123,11 @@ export class SetPublicPathPlugin extends SetPublicPathPluginBase { protected _applyCompilation(thisWebpack: typeof webpack, compilation: webpack.Compilation): void { class SetPublicPathRuntimeModule extends thisWebpack.RuntimeModule { - private readonly _pluginOptions: ISetWebpackPublicPathPluginOptions; + readonly #pluginOptions: ISetWebpackPublicPathPluginOptions; public constructor(pluginOptions: ISetWebpackPublicPathPluginOptions) { super('publicPath', thisWebpack.RuntimeModule.STAGE_BASIC); - this._pluginOptions = pluginOptions; + this.#pluginOptions = pluginOptions; } public override generate(): string { @@ -135,7 +135,7 @@ export class SetPublicPathPlugin extends SetPublicPathPluginBase { name: regexpName, isTokenized: regexpIsTokenized, useAssetName - } = this._pluginOptions.scriptName as IScriptNameInternalOptions; + } = this.#pluginOptions.scriptName as IScriptNameInternalOptions; const { chunk } = this; if (!chunk) { @@ -161,7 +161,7 @@ export class SetPublicPathPlugin extends SetPublicPathPluginBase { const moduleOptions: IInternalOptions = { webpackPublicPathVariable: thisWebpack.RuntimeGlobals.publicPath, regexName, - ...this._pluginOptions + ...this.#pluginOptions }; return getSetPublicPathCode(moduleOptions); diff --git a/webpack/set-webpack-public-path-plugin/src/SetPublicPathPluginBase.ts b/webpack/set-webpack-public-path-plugin/src/SetPublicPathPluginBase.ts index f10019fa03d..5a81a2e0786 100644 --- a/webpack/set-webpack-public-path-plugin/src/SetPublicPathPluginBase.ts +++ b/webpack/set-webpack-public-path-plugin/src/SetPublicPathPluginBase.ts @@ -10,10 +10,10 @@ import { PackageJsonLookup, type IPackageJson } from '@rushstack/node-core-libra * @public */ export abstract class SetPublicPathPluginBase implements webpack.WebpackPluginInstance { - private readonly _pluginName: string; + readonly #pluginName: string; public constructor(pluginName: string) { - this._pluginName = pluginName; + this.#pluginName = pluginName; } public apply(compiler: webpack.Compiler): void { @@ -30,7 +30,7 @@ export abstract class SetPublicPathPluginBase implements webpack.WebpackPluginIn const initialOutputPublicPathSetting: typeof compiler.options.output.publicPath = compiler.options.output.publicPath; - compiler.hooks.thisCompilation.tap(this._pluginName, (compilation: webpack.Compilation) => { + compiler.hooks.thisCompilation.tap(this.#pluginName, (compilation: webpack.Compilation) => { if (initialOutputPublicPathSetting) { compilation.warnings.push( new compiler.webpack.WebpackError( @@ -41,7 +41,7 @@ export abstract class SetPublicPathPluginBase implements webpack.WebpackPluginIn ); } else { compilation.hooks.runtimeRequirementInTree.for(thisWebpack.RuntimeGlobals.publicPath).intercept({ - name: this._pluginName, + name: this.#pluginName, register: (tap) => { if (tap.name === 'RuntimePlugin') { // Disable the default public path runtime plugin diff --git a/webpack/webpack-deep-imports-plugin/src/DeepImportsPlugin.ts b/webpack/webpack-deep-imports-plugin/src/DeepImportsPlugin.ts index 6525b360259..e1ffcaf9788 100644 --- a/webpack/webpack-deep-imports-plugin/src/DeepImportsPlugin.ts +++ b/webpack/webpack-deep-imports-plugin/src/DeepImportsPlugin.ts @@ -66,10 +66,10 @@ function countSlashes(str: string): number { * @public */ export class DeepImportsPlugin extends DllPlugin { - private readonly _inFolderName: string; - private readonly _outFolderName: string; - private readonly _pathsToIgnoreWithoutExtensions: Set; - private readonly _dTsFilesInputFolderName: string | undefined; + readonly #inFolderName: string; + readonly #outFolderName: string; + readonly #pathsToIgnoreWithoutExtensions: Set; + readonly #dTsFilesInputFolderName: string | undefined; public constructor(options: IDeepImportsPluginOptions) { const superOptions: DllPluginOptions = { @@ -114,10 +114,10 @@ export class DeepImportsPlugin extends DllPlugin { pathsToIgnoreWithoutExtensions.add(normalizedPathToIgnore); } - this._inFolderName = options.inFolderName; - this._outFolderName = options.outFolderName; - this._pathsToIgnoreWithoutExtensions = pathsToIgnoreWithoutExtensions; - this._dTsFilesInputFolderName = dTsFilesInputFolderName; + this.#inFolderName = options.inFolderName; + this.#outFolderName = options.outFolderName; + this.#pathsToIgnoreWithoutExtensions = pathsToIgnoreWithoutExtensions; + this.#dTsFilesInputFolderName = dTsFilesInputFolderName; } public override apply(compiler: Compiler): void { @@ -153,8 +153,8 @@ export class DeepImportsPlugin extends DllPlugin { exportsInfo: IExportsInfo; } - const pathsToIgnoreWithoutExtension: Set = this._pathsToIgnoreWithoutExtensions; - const resolvedLibInFolder: string = path.join(compiler.context, this._inFolderName); + const pathsToIgnoreWithoutExtension: Set = this.#pathsToIgnoreWithoutExtensions; + const resolvedLibInFolder: string = path.join(compiler.context, this.#inFolderName); const libModulesByChunk: Map = new Map(); const encounteredLibPaths: Set = new Set(); for (const runtimeChunk of runtimeChunks) { @@ -199,13 +199,13 @@ export class DeepImportsPlugin extends DllPlugin { libModulesByChunk.set(runtimeChunk, libModules); } - const resolvedLibOutFolder: string = path.join(compiler.context, this._outFolderName); + const resolvedLibOutFolder: string = path.join(compiler.context, this.#outFolderName); const outputPathRelativeLibOutFolder: string = Path.convertToSlashes( path.relative(outputPath, resolvedLibOutFolder) ); - const resolvedDtsFilesInputFolderName: string | undefined = this._dTsFilesInputFolderName - ? path.join(compiler.context, this._dTsFilesInputFolderName) + const resolvedDtsFilesInputFolderName: string | undefined = this.#dTsFilesInputFolderName + ? path.join(compiler.context, this.#dTsFilesInputFolderName) : undefined; for (const [chunk, libModules] of libModulesByChunk) { diff --git a/webpack/webpack-embedded-dependencies-plugin/src/EmbeddedDependenciesWebpackPlugin.ts b/webpack/webpack-embedded-dependencies-plugin/src/EmbeddedDependenciesWebpackPlugin.ts index 103d2e859ad..b2cee495800 100644 --- a/webpack/webpack-embedded-dependencies-plugin/src/EmbeddedDependenciesWebpackPlugin.ts +++ b/webpack/webpack-embedded-dependencies-plugin/src/EmbeddedDependenciesWebpackPlugin.ts @@ -148,19 +148,19 @@ type DefaultLicenseTemplate = `
${string}

${string}`; * and their licenses. */ export default class EmbeddedDependenciesWebpackPlugin implements WebpackPluginInstance { - private readonly _outputFileName: string; - private readonly _generateLicenseFile: boolean; - private readonly _generateLicenseFileFunction: LicenseFileGeneratorFunction; - private readonly _generatedLicenseFilename: LicenseFileName; - private readonly _packageFilterFunction: (packageJson: IPackageData, filePath: string) => boolean; + readonly #outputFileName: string; + readonly #generateLicenseFile: boolean; + readonly #generateLicenseFileFunction: LicenseFileGeneratorFunction; + readonly #generatedLicenseFilename: LicenseFileName; + readonly #packageFilterFunction: (packageJson: IPackageData, filePath: string) => boolean; public constructor(options?: IEmbeddedDependenciesWebpackPluginOptions) { - this._outputFileName = options?.outputFileName || DEFAULT_EMBEDDED_DEPENDENCIES_FILE_NAME; - this._generateLicenseFile = options?.generateLicenseFile || false; - this._generateLicenseFileFunction = - options?.generateLicenseFileFunction || this._defaultLicenseFileGenerator; - this._generatedLicenseFilename = options?.generatedLicenseFilename || DEFAULT_GENERATED_LICENSE_FILE_NAME; - this._packageFilterFunction = options?.packageFilterPredicate || DEFAULT_PACKAGE_FILTER_FUNCTION; + this.#outputFileName = options?.outputFileName || DEFAULT_EMBEDDED_DEPENDENCIES_FILE_NAME; + this.#generateLicenseFile = options?.generateLicenseFile || false; + this.#generateLicenseFileFunction = + options?.generateLicenseFileFunction || this.#defaultLicenseFileGenerator; + this.#generatedLicenseFilename = options?.generatedLicenseFilename || DEFAULT_GENERATED_LICENSE_FILE_NAME; + this.#packageFilterFunction = options?.packageFilterPredicate || DEFAULT_PACKAGE_FILTER_FUNCTION; } /** @@ -188,7 +188,7 @@ export default class EmbeddedDependenciesWebpackPlugin implements WebpackPluginI if ( pkg && filePath && - this._packageFilterFunction(pkg, filePath) && + this.#packageFilterFunction(pkg, filePath) && filePath?.includes('node_modules') ) { const key: PackageNameAndVersion = makePackageMapKeyForPackage(pkg); @@ -210,12 +210,12 @@ export default class EmbeddedDependenciesWebpackPlugin implements WebpackPluginI const { name, version } = data; let licenseSource: string | undefined; const license: string | undefined = parseLicense(data); - const licensePath: string | undefined = await this._getLicenseFilePathAsync(dir, compiler); + const licensePath: string | undefined = await this.#getLicenseFilePathAsync(dir, compiler); if (licensePath) { licenseSource = await FileSystem.readFileAsync(licensePath); const copyright: string | undefined = - this._parseCopyright(licenseSource) || parsePackageAuthor(data); + this.#parseCopyright(licenseSource) || parsePackageAuthor(data); packages.push({ name, @@ -238,7 +238,7 @@ export default class EmbeddedDependenciesWebpackPlugin implements WebpackPluginI } ); } catch (error) { - this._emitWebpackError(compilation, 'Failed to process embedded dependencies', error); + this.#emitWebpackError(compilation, 'Failed to process embedded dependencies', error); } finally { Sort.sortBy(packages, (pkg) => pkg.name); } @@ -247,17 +247,17 @@ export default class EmbeddedDependenciesWebpackPlugin implements WebpackPluginI embeddedDependencies: packages }; - compilation.emitAsset(this._outputFileName, new sources.RawSource(JSON.stringify(dataToStringify))); + compilation.emitAsset(this.#outputFileName, new sources.RawSource(JSON.stringify(dataToStringify))); - if (this._generateLicenseFile) { + if (this.#generateLicenseFile) { // We should try catch here because generator function can be output from user config try { compilation.emitAsset( - this._generatedLicenseFilename, - new sources.RawSource(this._generateLicenseFileFunction(packages)) + this.#generatedLicenseFilename, + new sources.RawSource(this.#generateLicenseFileFunction(packages)) ); } catch (error: unknown) { - this._emitWebpackError(compilation, 'Failed to generate license file', error); + this.#emitWebpackError(compilation, 'Failed to generate license file', error); } } @@ -287,7 +287,7 @@ export default class EmbeddedDependenciesWebpackPlugin implements WebpackPluginI * } * ``` */ - private _emitWebpackError(compilation: Compilation, errorMessage: string, error: unknown): void { + #emitWebpackError(compilation: Compilation, errorMessage: string, error: unknown): void { let emittedError: WebpackError; const { WebpackError } = compilation.compiler.webpack; // If the error is a string, we can just emit it as is with message prefix and error message @@ -311,7 +311,7 @@ export default class EmbeddedDependenciesWebpackPlugin implements WebpackPluginI /** * Searches a third party package directory for a license file. */ - private async _getLicenseFilePathAsync( + async #getLicenseFilePathAsync( modulePath: string, compiler: Compiler ): Promise { @@ -344,7 +344,7 @@ export default class EmbeddedDependenciesWebpackPlugin implements WebpackPluginI /** * Given a module path, try to parse the module's copyright attribution. */ - private _parseCopyright(licenseSource: string): string | undefined { + #parseCopyright(licenseSource: string): string | undefined { const match: RegExpMatchArray | null = licenseSource.match(COPYRIGHT_REGEX); if (match) { @@ -354,7 +354,7 @@ export default class EmbeddedDependenciesWebpackPlugin implements WebpackPluginI return undefined; } - private _defaultLicenseFileGenerator(packages: IPackageData[]): string { + #defaultLicenseFileGenerator(packages: IPackageData[]): string { const licenseContent = (pkg: IPackageData): string => pkg.licenseSource || pkg.copyright || 'License or Copyright not found'; diff --git a/webpack/webpack-workspace-resolve-plugin/src/KnownDescriptionFilePlugin.ts b/webpack/webpack-workspace-resolve-plugin/src/KnownDescriptionFilePlugin.ts index 30b26319570..44327dbacad 100644 --- a/webpack/webpack-workspace-resolve-plugin/src/KnownDescriptionFilePlugin.ts +++ b/webpack/webpack-workspace-resolve-plugin/src/KnownDescriptionFilePlugin.ts @@ -18,8 +18,8 @@ export class KnownDescriptionFilePlugin { public readonly source: string; public readonly target: string; - private readonly _skipForContext: boolean; - private readonly _cache: WorkspaceLayoutCache; + readonly #skipForContext: boolean; + readonly #cache: WorkspaceLayoutCache; /** * Constructs a new instance of `KnownDescriptionFilePlugin`. @@ -31,12 +31,12 @@ export class KnownDescriptionFilePlugin { public constructor(cache: WorkspaceLayoutCache, source: string, target: string, skipForContext?: boolean) { this.source = source; this.target = target; - this._cache = cache; - this._skipForContext = !!skipForContext; + this.#cache = cache; + this.#skipForContext = !!skipForContext; } public apply(resolver: Resolver): void { - if (this._skipForContext && resolver.options.resolveToContext) { + if (this.#skipForContext && resolver.options.resolveToContext) { return; } @@ -71,7 +71,7 @@ export class KnownDescriptionFilePlugin { return callback(); } - const cache: WorkspaceLayoutCache = this._cache; + const cache: WorkspaceLayoutCache = this.#cache; const match: IPrefixMatch | undefined = cache.contextLookup.findLongestPrefixMatch(path); diff --git a/webpack/webpack-workspace-resolve-plugin/src/KnownPackageDependenciesPlugin.ts b/webpack/webpack-workspace-resolve-plugin/src/KnownPackageDependenciesPlugin.ts index 2f721e018fb..fc48fe7df99 100644 --- a/webpack/webpack-workspace-resolve-plugin/src/KnownPackageDependenciesPlugin.ts +++ b/webpack/webpack-workspace-resolve-plugin/src/KnownPackageDependenciesPlugin.ts @@ -19,7 +19,7 @@ export class KnownPackageDependenciesPlugin { public readonly source: string; public readonly target: string; - private readonly _cache: WorkspaceLayoutCache; + readonly #cache: WorkspaceLayoutCache; /** * Constructs a new instance of `KnownPackageDependenciesPlugin`. @@ -30,7 +30,7 @@ export class KnownPackageDependenciesPlugin { public constructor(cache: WorkspaceLayoutCache, source: string, target: string) { this.source = source; this.target = target; - this._cache = cache; + this.#cache = cache; } public apply(resolver: Resolver): void { @@ -53,7 +53,7 @@ export class KnownPackageDependenciesPlugin { return callback(new Error(`Expected descriptionFileData for ${path}`)); } - const cache: WorkspaceLayoutCache = this._cache; + const cache: WorkspaceLayoutCache = this.#cache; let scope: IPrefixMatch | undefined = cache.contextForPackage.get(descriptionFileData); diff --git a/webpack/webpack-workspace-resolve-plugin/src/WorkspaceLayoutCache.ts b/webpack/webpack-workspace-resolve-plugin/src/WorkspaceLayoutCache.ts index 0f2d988b634..671e43de4a8 100644 --- a/webpack/webpack-workspace-resolve-plugin/src/WorkspaceLayoutCache.ts +++ b/webpack/webpack-workspace-resolve-plugin/src/WorkspaceLayoutCache.ts @@ -138,30 +138,30 @@ export class WorkspaceLayoutCache { // Internal class due to coupling to `resolveContexts` class ResolveContext implements IResolveContext { - private readonly _serialized: ISerializedResolveContext; - private _descriptionFileRoot: string | undefined; - private _dependencies: LookupByPath | undefined; + readonly #serialized: ISerializedResolveContext; + #descriptionFileRoot: string | undefined; + #dependencies: LookupByPath | undefined; public constructor(serialized: ISerializedResolveContext) { - this._serialized = serialized; - this._descriptionFileRoot = undefined; - this._dependencies = undefined; + this.#serialized = serialized; + this.#descriptionFileRoot = undefined; + this.#dependencies = undefined; } public get descriptionFileRoot(): string { - if (!this._descriptionFileRoot) { - const merged: string = `${basePath}${this._serialized.root}`; - this._descriptionFileRoot = normalizeToPlatform?.(merged) ?? merged; + if (!this.#descriptionFileRoot) { + const merged: string = `${basePath}${this.#serialized.root}`; + this.#descriptionFileRoot = normalizeToPlatform?.(merged) ?? merged; } - return this._descriptionFileRoot; + return this.#descriptionFileRoot; } public findDependency(request: string): IPrefixMatch | undefined { - if (!this._dependencies) { + if (!this.#dependencies) { // Lazy initialize this object since most packages won't be requested. const dependencies: LookupByPath = new LookupByPath(undefined, '/'); - const { name, deps } = this._serialized; + const { name, deps } = this.#serialized; // Handle the self-reference scenario dependencies.setItem(name, this); @@ -171,10 +171,10 @@ export class WorkspaceLayoutCache { dependencies.setItem(key, resolveContexts[ordinal]); } } - this._dependencies = dependencies; + this.#dependencies = dependencies; } - return this._dependencies.findLongestPrefixMatch(request); + return this.#dependencies.findLongestPrefixMatch(request); } } diff --git a/webpack/webpack-workspace-resolve-plugin/src/WorkspaceResolvePlugin.ts b/webpack/webpack-workspace-resolve-plugin/src/WorkspaceResolvePlugin.ts index a68a97aa5db..ec9225764fe 100644 --- a/webpack/webpack-workspace-resolve-plugin/src/WorkspaceResolvePlugin.ts +++ b/webpack/webpack-workspace-resolve-plugin/src/WorkspaceResolvePlugin.ts @@ -31,16 +31,16 @@ export interface IWorkspaceResolvePluginOptions { * @beta */ export class WorkspaceResolvePlugin implements WebpackPluginInstance { - private readonly _cache: WorkspaceLayoutCache; - private readonly _resolverNames: Set; + readonly #cache: WorkspaceLayoutCache; + readonly #resolverNames: Set; public constructor(options: IWorkspaceResolvePluginOptions) { - this._cache = options.cache; - this._resolverNames = new Set(options.resolverNames ?? ['normal', 'context', 'loader']); + this.#cache = options.cache; + this.#resolverNames = new Set(options.resolverNames ?? ['normal', 'context', 'loader']); } public apply(compiler: Compiler): void { - const cache: WorkspaceLayoutCache = this._cache; + const cache: WorkspaceLayoutCache = this.#cache; function handler(resolveOptions: ResolveOptions): ResolveOptions { // Omit default `node_modules` @@ -75,7 +75,7 @@ export class WorkspaceResolvePlugin implements WebpackPluginInstance { return resolveOptions; } - for (const resolverName of this._resolverNames) { + for (const resolverName of this.#resolverNames) { compiler.resolverFactory.hooks.resolveOptions .for(resolverName) .tap(WorkspaceResolvePlugin.name, handler); diff --git a/webpack/webpack4-localization-plugin/src/LocalizationPlugin.ts b/webpack/webpack4-localization-plugin/src/LocalizationPlugin.ts index 2e4a05b7c06..5048eafb45f 100644 --- a/webpack/webpack4-localization-plugin/src/LocalizationPlugin.ts +++ b/webpack/webpack4-localization-plugin/src/LocalizationPlugin.ts @@ -98,32 +98,32 @@ export class LocalizationPlugin implements Webpack.Plugin { */ public stringKeys: Map = new Map(); - private _options: ILocalizationPluginOptions; - private _resolvedTranslatedStringsFromOptions!: ILocalizedStrings; - private _globsToIgnore: string[] | undefined; - private _stringPlaceholderCounter: number = 0; - private _stringPlaceholderMap: Map = new Map< + #options: ILocalizationPluginOptions; + #resolvedTranslatedStringsFromOptions!: ILocalizedStrings; + #globsToIgnore: string[] | undefined; + #stringPlaceholderCounter: number = 0; + #stringPlaceholderMap: Map = new Map< string, IStringSerialNumberData >(); - private _locales: Set = new Set(); - private _passthroughLocaleName!: string; - private _defaultLocale!: string; - private _noStringsLocaleName!: string; - private _fillMissingTranslationStrings!: boolean; - private _pseudolocalizers: Map string> = new Map< + #locales: Set = new Set(); + #passthroughLocaleName!: string; + #defaultLocale!: string; + #noStringsLocaleName!: string; + #fillMissingTranslationStrings!: boolean; + #pseudolocalizers: Map string> = new Map< string, (str: string) => string >(); - private _resxNewlineNormalization: NewlineKind | undefined; - private _ignoreMissingResxComments: boolean | undefined; + #resxNewlineNormalization: NewlineKind | undefined; + #ignoreMissingResxComments: boolean | undefined; /** * The outermost map's keys are the locale names. * The middle map's keys are the resolved, file names. * The innermost map's keys are the string identifiers and its values are the string values. */ - private _resolvedLocalizedStrings: Map>> = new Map< + #resolvedLocalizedStrings: Map>> = new Map< string, Map> >(); @@ -140,7 +140,7 @@ export class LocalizationPlugin implements Webpack.Plugin { ); } - this._options = options; + this.#options = options; } public apply(compiler: Webpack.Compiler): void { @@ -150,29 +150,29 @@ export class LocalizationPlugin implements Webpack.Plugin { throw new Error(`The ${LocalizationPlugin.name} plugin requires Webpack 4`); } - if (this._options.typingsOptions && compiler.context) { + if (this.#options.typingsOptions && compiler.context) { if ( - this._options.typingsOptions.generatedTsFolder && - !path.isAbsolute(this._options.typingsOptions.generatedTsFolder) + this.#options.typingsOptions.generatedTsFolder && + !path.isAbsolute(this.#options.typingsOptions.generatedTsFolder) ) { - this._options.typingsOptions.generatedTsFolder = path.resolve( + this.#options.typingsOptions.generatedTsFolder = path.resolve( compiler.context, - this._options.typingsOptions.generatedTsFolder + this.#options.typingsOptions.generatedTsFolder ); } if ( - this._options.typingsOptions.sourceRoot && - !path.isAbsolute(this._options.typingsOptions.sourceRoot) + this.#options.typingsOptions.sourceRoot && + !path.isAbsolute(this.#options.typingsOptions.sourceRoot) ) { - this._options.typingsOptions.sourceRoot = path.resolve( + this.#options.typingsOptions.sourceRoot = path.resolve( compiler.context, - this._options.typingsOptions.sourceRoot + this.#options.typingsOptions.sourceRoot ); } const secondaryGeneratedTsFolders: string[] | undefined = - this._options.typingsOptions.secondaryGeneratedTsFolders; + this.#options.typingsOptions.secondaryGeneratedTsFolders; if (secondaryGeneratedTsFolders) { for (let i: number = 0; i < secondaryGeneratedTsFolders.length; i++) { const secondaryGeneratedTsFolder: string = secondaryGeneratedTsFolders[i]; @@ -186,18 +186,18 @@ export class LocalizationPlugin implements Webpack.Plugin { // https://github.com/webpack/webpack-dev-server/pull/1929/files#diff-15fb51940da53816af13330d8ce69b4eR66 const isWebpackDevServer: boolean = process.env.WEBPACK_DEV_SERVER === 'true'; - const { errors, warnings } = this._initializeAndValidateOptions(compiler.options, isWebpackDevServer); + const { errors, warnings } = this.#initializeAndValidateOptions(compiler.options, isWebpackDevServer); let typingsPreprocessor: TypingsGenerator | undefined; - if (this._options.typingsOptions) { + if (this.#options.typingsOptions) { typingsPreprocessor = new TypingsGenerator({ - srcFolder: this._options.typingsOptions.sourceRoot || compiler.context, - generatedTsFolder: this._options.typingsOptions.generatedTsFolder, - secondaryGeneratedTsFolders: this._options.typingsOptions.secondaryGeneratedTsFolders, - exportAsDefault: this._options.typingsOptions.exportAsDefault, - globsToIgnore: this._options.globsToIgnore, - ignoreString: this._options.ignoreString, - processComment: this._options.typingsOptions.processComment + srcFolder: this.#options.typingsOptions.sourceRoot || compiler.context, + generatedTsFolder: this.#options.typingsOptions.generatedTsFolder, + secondaryGeneratedTsFolders: this.#options.typingsOptions.secondaryGeneratedTsFolders, + exportAsDefault: this.#options.typingsOptions.exportAsDefault, + globsToIgnore: this.#options.globsToIgnore, + ignoreString: this.#options.ignoreString, + processComment: this.#options.typingsOptions.processComment }); } else { typingsPreprocessor = undefined; @@ -206,11 +206,11 @@ export class LocalizationPlugin implements Webpack.Plugin { const webpackConfigurationUpdaterOptions: IWebpackConfigurationUpdaterOptions = { pluginInstance: this, configuration: compiler.options, - globsToIgnore: this._globsToIgnore, + globsToIgnore: this.#globsToIgnore, localeNameOrPlaceholder: Constants.LOCALE_NAME_PLACEHOLDER, - resxNewlineNormalization: this._resxNewlineNormalization, - ignoreMissingResxComments: this._ignoreMissingResxComments, - ignoreString: this._options.ignoreString + resxNewlineNormalization: this.#resxNewlineNormalization, + ignoreMissingResxComments: this.#ignoreMissingResxComments, + ignoreString: this.#options.ignoreString }; if (errors.length > 0 || warnings.length > 0) { @@ -238,7 +238,7 @@ export class LocalizationPlugin implements Webpack.Plugin { } compiler.options.plugins.push( - new Webpack.WatchIgnorePlugin([this._options.typingsOptions!.generatedTsFolder]) + new Webpack.WatchIgnorePlugin([this.#options.typingsOptions!.generatedTsFolder]) ); } @@ -331,12 +331,12 @@ export class LocalizationPlugin implements Webpack.Plugin { for (const chunk of chunks) { // See if the chunk contains any localized modules or loads any localized chunks - const localizedChunk: boolean = this._chunkHasLocalizedModules(chunk); + const localizedChunk: boolean = this.#chunkHasLocalizedModules(chunk); // Change the chunk's name to include either the locale name or the locale name for chunks without strings const replacementValue: string = localizedChunk ? Constants.LOCALE_NAME_PLACEHOLDER - : this._noStringsLocaleName; + : this.#noStringsLocaleName; if (chunk.hasRuntime()) { chunk.filenameTemplate = (compilation.options.output!.filename as string).replace( Constants.LOCALE_FILENAME_TOKEN_REGEX, @@ -387,7 +387,7 @@ export class LocalizationPlugin implements Webpack.Plugin { } } - if (this._chunkHasLocalizedModules(chunk)) { + if (this.#chunkHasLocalizedModules(chunk)) { processChunkJsFile((chunkFilename) => { if (chunkFilename.indexOf(Constants.LOCALE_NAME_PLACEHOLDER) === -1) { throw new Error( @@ -404,11 +404,11 @@ export class LocalizationPlugin implements Webpack.Plugin { assetName: chunkFilename, asset, chunk, - chunkHasLocalizedModules: this._chunkHasLocalizedModules.bind(this), - locales: this._locales, - noStringsLocaleName: this._noStringsLocaleName, - fillMissingTranslationStrings: this._fillMissingTranslationStrings, - defaultLocale: this._defaultLocale + chunkHasLocalizedModules: this.#chunkHasLocalizedModules.bind(this), + locales: this.#locales, + noStringsLocaleName: this.#noStringsLocaleName, + fillMissingTranslationStrings: this.#fillMissingTranslationStrings, + defaultLocale: this.#defaultLocale }); // Delete the existing asset because it's been renamed @@ -448,8 +448,8 @@ export class LocalizationPlugin implements Webpack.Plugin { assetName: chunkFilename, asset, chunk, - noStringsLocaleName: this._noStringsLocaleName, - chunkHasLocalizedModules: this._chunkHasLocalizedModules.bind(this) + noStringsLocaleName: this.#noStringsLocaleName, + chunkHasLocalizedModules: this.#chunkHasLocalizedModules.bind(this) }); // Delete the existing asset because it's been renamed @@ -464,20 +464,20 @@ export class LocalizationPlugin implements Webpack.Plugin { chunk.files = Array.from(chunkFilesSet); } - if (this._options.localizationStats) { - if (this._options.localizationStats.dropPath) { + if (this.#options.localizationStats) { + if (this.#options.localizationStats.dropPath) { const resolvedLocalizationStatsDropPath: string = path.resolve( compiler.outputPath, - this._options.localizationStats.dropPath + this.#options.localizationStats.dropPath ); JsonFile.save(localizationStats, resolvedLocalizationStatsDropPath, { ensureFolderExists: true }); } - if (this._options.localizationStats.callback) { + if (this.#options.localizationStats.callback) { try { - this._options.localizationStats.callback(localizationStats); + this.#options.localizationStats.callback(localizationStats); } catch (e) { /* swallow errors from the callback */ } @@ -501,8 +501,8 @@ export class LocalizationPlugin implements Webpack.Plugin { const additionalLoadedFilePaths: string[] = []; const errors: Error[] = []; - const locFileData: ILocaleFileData = this._convertLocalizationFileToLocData(localizedResourceData); - this._addLocFile(this._defaultLocale, localizedResourcePath, locFileData); + const locFileData: ILocaleFileData = this.#convertLocalizationFileToLocData(localizedResourceData); + this.#addLocFile(this.#defaultLocale, localizedResourcePath, locFileData); const normalizeLocalizedData: (localizedData: ILocaleFileData | string) => ILocaleFileData = ( localizedData @@ -513,11 +513,11 @@ export class LocalizationPlugin implements Webpack.Plugin { filePath: localizedData, content: FileSystem.readFile(localizedData), terminal: terminal, - resxNewlineNormalization: this._resxNewlineNormalization, - ignoreMissingResxComments: this._ignoreMissingResxComments + resxNewlineNormalization: this.#resxNewlineNormalization, + ignoreMissingResxComments: this.#ignoreMissingResxComments }); - return this._convertLocalizationFileToLocData(localizationFile); + return this.#convertLocalizationFileToLocData(localizationFile); } else { return localizedData; } @@ -525,7 +525,7 @@ export class LocalizationPlugin implements Webpack.Plugin { const missingLocales: string[] = []; for (const [translatedLocaleName, translatedStrings] of Object.entries( - this._resolvedTranslatedStringsFromOptions + this.#resolvedTranslatedStringsFromOptions )) { const translatedLocFileFromOptions: ILocaleFileData | string | undefined = translatedStrings[localizedResourcePath]; @@ -533,14 +533,14 @@ export class LocalizationPlugin implements Webpack.Plugin { missingLocales.push(translatedLocaleName); } else { const translatedLocFileData: ILocaleFileData = normalizeLocalizedData(translatedLocFileFromOptions); - this._addLocFile(translatedLocaleName, localizedResourcePath, translatedLocFileData); + this.#addLocFile(translatedLocaleName, localizedResourcePath, translatedLocFileData); } } - if (missingLocales.length > 0 && this._options.localizedData.resolveMissingTranslatedStrings) { + if (missingLocales.length > 0 && this.#options.localizedData.resolveMissingTranslatedStrings) { let resolvedTranslatedData: IResolvedMissingTranslations | undefined = undefined; try { - resolvedTranslatedData = this._options.localizedData.resolveMissingTranslatedStrings( + resolvedTranslatedData = this.#options.localizedData.resolveMissingTranslatedStrings( missingLocales, localizedResourcePath ); @@ -552,20 +552,20 @@ export class LocalizationPlugin implements Webpack.Plugin { for (const [resolvedLocaleName, resolvedLocaleData] of Object.entries(resolvedTranslatedData)) { if (resolvedLocaleData) { const translatedLocFileData: ILocaleFileData = normalizeLocalizedData(resolvedLocaleData); - this._addLocFile(resolvedLocaleName, localizedResourcePath, translatedLocFileData); + this.#addLocFile(resolvedLocaleName, localizedResourcePath, translatedLocFileData); } } } } - this._pseudolocalizers.forEach((pseudolocalizer: (str: string) => string, pseudolocaleName: string) => { + this.#pseudolocalizers.forEach((pseudolocalizer: (str: string) => string, pseudolocaleName: string) => { const pseudolocFileData: ILocaleFileData = {}; for (const [stringName, stringValue] of Object.entries(locFileData)) { pseudolocFileData[stringName] = pseudolocalizer(stringValue); } - this._addLocFile(pseudolocaleName, localizedResourcePath, pseudolocFileData); + this.#addLocFile(pseudolocaleName, localizedResourcePath, pseudolocFileData); }); return { additionalLoadedFilePaths, errors }; @@ -575,15 +575,15 @@ export class LocalizationPlugin implements Webpack.Plugin { * @internal */ public getDataForSerialNumber(serialNumber: string): IStringSerialNumberData | undefined { - return this._stringPlaceholderMap.get(serialNumber); + return this.#stringPlaceholderMap.get(serialNumber); } - private _addLocFile( + #addLocFile( localeName: string, localizedFilePath: string, localizedFileData: ILocaleFileData ): void { - const filesMap: Map> = this._resolvedLocalizedStrings.get(localeName)!; + const filesMap: Map> = this.#resolvedLocalizedStrings.get(localeName)!; const stringsMap: Map = new Map(); filesMap.set(localizedFilePath, stringsMap); @@ -591,28 +591,28 @@ export class LocalizationPlugin implements Webpack.Plugin { for (const [stringName, stringValue] of Object.entries(localizedFileData)) { const stringKey: string = `${localizedFilePath}?${stringName}`; if (!this.stringKeys.has(stringKey)) { - const placeholder: IStringPlaceholder = this._getPlaceholderString(); + const placeholder: IStringPlaceholder = this.#getPlaceholderString(); this.stringKeys.set(stringKey, placeholder); } const placeholder: IStringPlaceholder = this.stringKeys.get(stringKey)!; - if (!this._stringPlaceholderMap.has(placeholder.suffix)) { - this._stringPlaceholderMap.set(placeholder.suffix, { + if (!this.#stringPlaceholderMap.has(placeholder.suffix)) { + this.#stringPlaceholderMap.set(placeholder.suffix, { values: { - [this._passthroughLocaleName]: stringName + [this.#passthroughLocaleName]: stringName }, locFilePath: localizedFilePath, stringName: stringName }); } - this._stringPlaceholderMap.get(placeholder.suffix)!.values[localeName] = stringValue; + this.#stringPlaceholderMap.get(placeholder.suffix)!.values[localeName] = stringValue; stringsMap.set(stringName, stringValue); } } - private _initializeAndValidateOptions( + #initializeAndValidateOptions( configuration: Webpack.Configuration, isWebpackDevServer: boolean ): { errors: Error[]; warnings: Error[] } { @@ -650,31 +650,31 @@ export class LocalizationPlugin implements Webpack.Plugin { // START misc options // eslint-disable-next-line no-lone-blocks { - this._globsToIgnore = this._options.globsToIgnore; + this.#globsToIgnore = this.#options.globsToIgnore; } // END misc options // START options.localizedData - if (this._options.localizedData) { - this._ignoreMissingResxComments = this._options.localizedData.ignoreMissingResxComments; + if (this.#options.localizedData) { + this.#ignoreMissingResxComments = this.#options.localizedData.ignoreMissingResxComments; // START options.localizedData.passthroughLocale - if (this._options.localizedData.passthroughLocale) { + if (this.#options.localizedData.passthroughLocale) { const { usePassthroughLocale, passthroughLocaleName = 'passthrough' } = - this._options.localizedData.passthroughLocale; + this.#options.localizedData.passthroughLocale; if (usePassthroughLocale) { - this._passthroughLocaleName = passthroughLocaleName; - this._locales.add(passthroughLocaleName); + this.#passthroughLocaleName = passthroughLocaleName; + this.#locales.add(passthroughLocaleName); } } // END options.localizedData.passthroughLocale // START options.localizedData.translatedStrings - const { translatedStrings } = this._options.localizedData; - this._resolvedTranslatedStringsFromOptions = {}; + const { translatedStrings } = this.#options.localizedData; + this.#resolvedTranslatedStringsFromOptions = {}; if (translatedStrings) { for (const [localeName, locale] of Object.entries(translatedStrings)) { - if (this._locales.has(localeName)) { + if (this.#locales.has(localeName)) { errors.push( Error( `The locale "${localeName}" appears multiple times. ` + @@ -688,9 +688,9 @@ export class LocalizationPlugin implements Webpack.Plugin { return { errors, warnings }; } - this._locales.add(localeName); - this._resolvedLocalizedStrings.set(localeName, new Map>()); - this._resolvedTranslatedStringsFromOptions[localeName] = {}; + this.#locales.add(localeName); + this.#resolvedLocalizedStrings.set(localeName, new Map>()); + this.#resolvedTranslatedStringsFromOptions[localeName] = {}; const locFilePathsInLocale: Set = new Set(); @@ -715,7 +715,7 @@ export class LocalizationPlugin implements Webpack.Plugin { ? path.resolve(configuration.context!, locFileDataFromOptions) : locFileDataFromOptions; - this._resolvedTranslatedStringsFromOptions[localeName][normalizedLocFilePath] = + this.#resolvedTranslatedStringsFromOptions[localeName][normalizedLocFilePath] = normalizedLocFileDataFromOptions; } } @@ -724,20 +724,20 @@ export class LocalizationPlugin implements Webpack.Plugin { // END options.localizedData.translatedStrings // START options.localizedData.defaultLocale - if (this._options.localizedData.defaultLocale) { - const { localeName, fillMissingTranslationStrings } = this._options.localizedData.defaultLocale; - if (this._options.localizedData.defaultLocale.localeName) { - if (this._locales.has(localeName)) { + if (this.#options.localizedData.defaultLocale) { + const { localeName, fillMissingTranslationStrings } = this.#options.localizedData.defaultLocale; + if (this.#options.localizedData.defaultLocale.localeName) { + if (this.#locales.has(localeName)) { errors.push(new Error('The default locale is also specified in the translated strings.')); return { errors, warnings }; } else if (!ensureValidLocaleName(localeName)) { return { errors, warnings }; } - this._locales.add(localeName); - this._resolvedLocalizedStrings.set(localeName, new Map>()); - this._defaultLocale = localeName; - this._fillMissingTranslationStrings = !!fillMissingTranslationStrings; + this.#locales.add(localeName); + this.#resolvedLocalizedStrings.set(localeName, new Map>()); + this.#defaultLocale = localeName; + this.#fillMissingTranslationStrings = !!fillMissingTranslationStrings; } else { errors.push(new Error('Missing default locale name')); return { errors, warnings }; @@ -749,18 +749,18 @@ export class LocalizationPlugin implements Webpack.Plugin { // END options.localizedData.defaultLocale // START options.localizedData.pseudoLocales - if (this._options.localizedData.pseudolocales) { + if (this.#options.localizedData.pseudolocales) { for (const [pseudolocaleName, pseudoLocaleOpts] of Object.entries( - this._options.localizedData.pseudolocales + this.#options.localizedData.pseudolocales )) { - if (this._defaultLocale === pseudolocaleName) { + if (this.#defaultLocale === pseudolocaleName) { errors.push( new Error(`A pseudolocale (${pseudolocaleName}) name is also the default locale name.`) ); return { errors, warnings }; } - if (this._locales.has(pseudolocaleName)) { + if (this.#locales.has(pseudolocaleName)) { errors.push( new Error( `A pseudolocale (${pseudolocaleName}) name is also specified in the translated strings.` @@ -769,30 +769,30 @@ export class LocalizationPlugin implements Webpack.Plugin { return { errors, warnings }; } - this._pseudolocalizers.set(pseudolocaleName, getPseudolocalizer(pseudoLocaleOpts)); - this._locales.add(pseudolocaleName); - this._resolvedLocalizedStrings.set(pseudolocaleName, new Map>()); + this.#pseudolocalizers.set(pseudolocaleName, getPseudolocalizer(pseudoLocaleOpts)); + this.#locales.add(pseudolocaleName); + this.#resolvedLocalizedStrings.set(pseudolocaleName, new Map>()); } } // END options.localizedData.pseudoLocales // START options.localizedData.normalizeResxNewlines - if (this._options.localizedData.normalizeResxNewlines) { - switch (this._options.localizedData.normalizeResxNewlines) { + if (this.#options.localizedData.normalizeResxNewlines) { + switch (this.#options.localizedData.normalizeResxNewlines) { case 'crlf': { - this._resxNewlineNormalization = NewlineKind.CrLf; + this.#resxNewlineNormalization = NewlineKind.CrLf; break; } case 'lf': { - this._resxNewlineNormalization = NewlineKind.Lf; + this.#resxNewlineNormalization = NewlineKind.Lf; break; } default: { errors.push( new Error( - `Unexpected value "${this._options.localizedData.normalizeResxNewlines}" for option ` + + `Unexpected value "${this.#options.localizedData.normalizeResxNewlines}" for option ` + '"localizedData.normalizeResxNewlines"' ) ); @@ -808,28 +808,28 @@ export class LocalizationPlugin implements Webpack.Plugin { // START options.noStringsLocaleName if ( - this._options.noStringsLocaleName === undefined || - this._options.noStringsLocaleName === null || - !ensureValidLocaleName(this._options.noStringsLocaleName) + this.#options.noStringsLocaleName === undefined || + this.#options.noStringsLocaleName === null || + !ensureValidLocaleName(this.#options.noStringsLocaleName) ) { - this._noStringsLocaleName = 'none'; + this.#noStringsLocaleName = 'none'; } else { - this._noStringsLocaleName = this._options.noStringsLocaleName; + this.#noStringsLocaleName = this.#options.noStringsLocaleName; } // END options.noStringsLocaleName return { errors, warnings }; } - private _getPlaceholderString(): IStringPlaceholder { - const suffix: string = (this._stringPlaceholderCounter++).toString(); + #getPlaceholderString(): IStringPlaceholder { + const suffix: string = (this.#stringPlaceholderCounter++).toString(); return { value: `${Constants.STRING_PLACEHOLDER_PREFIX}_\\_${Constants.STRING_PLACEHOLDER_LABEL}_${suffix}`, suffix: suffix }; } - private _chunkHasLocalizedModules(chunk: Webpack.compilation.Chunk): boolean { + #chunkHasLocalizedModules(chunk: Webpack.compilation.Chunk): boolean { let chunkHasAnyLocModules: boolean | undefined = EntityMarker.getMark(chunk); if (chunkHasAnyLocModules === undefined) { chunkHasAnyLocModules = false; @@ -847,7 +847,7 @@ export class LocalizationPlugin implements Webpack.Plugin { // the locale name. if (!chunkHasAnyLocModules && chunk.hasRuntime()) { for (const asyncChunk of chunk.getAllAsyncChunks()) { - if (this._chunkHasLocalizedModules(asyncChunk)) { + if (this.#chunkHasLocalizedModules(asyncChunk)) { chunkHasAnyLocModules = true; break; } @@ -860,7 +860,7 @@ export class LocalizationPlugin implements Webpack.Plugin { return chunkHasAnyLocModules; } - private _convertLocalizationFileToLocData(locFile: ILocalizationFile): ILocaleFileData { + #convertLocalizationFileToLocData(locFile: ILocalizationFile): ILocaleFileData { const locFileData: ILocaleFileData = {}; for (const [stringName, locFileEntry] of Object.entries(locFile)) { locFileData[stringName] = locFileEntry.value; diff --git a/webpack/webpack4-module-minifier-plugin/src/AsyncImportCompressionPlugin.ts b/webpack/webpack4-module-minifier-plugin/src/AsyncImportCompressionPlugin.ts index 6bae5be94cc..1a6ef0942dc 100644 --- a/webpack/webpack4-module-minifier-plugin/src/AsyncImportCompressionPlugin.ts +++ b/webpack/webpack4-module-minifier-plugin/src/AsyncImportCompressionPlugin.ts @@ -102,10 +102,10 @@ function needChunkOnDemandLoadingCode(chunk: webpack.compilation.Chunk): boolean * Also ensures that the code seen by the minifier does not contain chunk ids, and is therefore portable across chunks/compilations. */ export class AsyncImportCompressionPlugin implements Plugin { - private readonly _minifierHooks: IModuleMinifierPluginHooks; + readonly #minifierHooks: IModuleMinifierPluginHooks; public constructor(minifierHooks: IModuleMinifierPluginHooks) { - this._minifierHooks = minifierHooks; + this.#minifierHooks = minifierHooks; } public apply(compiler: Compiler): void { @@ -113,7 +113,7 @@ export class AsyncImportCompressionPlugin implements Plugin { const asyncImportGroups: Map = new Map(); let rankedImportGroups: IAsyncImportMetadata[] | undefined; - this._minifierHooks.postProcessCodeFragment.tap( + this.#minifierHooks.postProcessCodeFragment.tap( { name: PLUGIN_NAME, stage: -1 @@ -157,7 +157,7 @@ export class AsyncImportCompressionPlugin implements Plugin { const chunkExpression: string = meta.index < 0 ? JSON.stringify(meta.chunkIds) : `${meta.index}`; - const mapped: string | number | undefined = this._minifierHooks.finalModuleId.call( + const mapped: string | number | undefined = this.#minifierHooks.finalModuleId.call( module.id!, context.compilation ); diff --git a/webpack/webpack4-module-minifier-plugin/src/ModuleMinifierPlugin.ts b/webpack/webpack4-module-minifier-plugin/src/ModuleMinifierPlugin.ts index 40716e76ee6..2687e53237c 100644 --- a/webpack/webpack4-module-minifier-plugin/src/ModuleMinifierPlugin.ts +++ b/webpack/webpack4-module-minifier-plugin/src/ModuleMinifierPlugin.ts @@ -163,10 +163,10 @@ export class ModuleMinifierPlugin implements webpack.Plugin { public readonly hooks: IModuleMinifierPluginHooks; public minifier: IModuleMinifier; - private readonly _enhancers: webpack.Plugin[]; - private readonly _sourceMap: boolean | undefined; + readonly #enhancers: webpack.Plugin[]; + readonly #sourceMap: boolean | undefined; - private readonly _optionsForHash: IOptionsForHash; + readonly #optionsForHash: IOptionsForHash; public constructor(options: IModuleMinifierPluginOptions) { this.hooks = { @@ -179,26 +179,26 @@ export class ModuleMinifierPlugin implements webpack.Plugin { const { minifier, sourceMap, usePortableModules = false, compressAsyncImports = false } = options; - this._optionsForHash = { + this.#optionsForHash = { ...options, minifier: undefined, revision: CODE_GENERATION_REVISION }; - this._enhancers = []; + this.#enhancers = []; if (usePortableModules) { - this._enhancers.push(new PortableMinifierModuleIdsPlugin(this.hooks)); + this.#enhancers.push(new PortableMinifierModuleIdsPlugin(this.hooks)); } if (compressAsyncImports) { - this._enhancers.push(new AsyncImportCompressionPlugin(this.hooks)); + this.#enhancers.push(new AsyncImportCompressionPlugin(this.hooks)); } this.hooks.rehydrateAssets.tap(PLUGIN_NAME, defaultRehydrateAssets); this.minifier = minifier; - this._sourceMap = sourceMap; + this.#sourceMap = sourceMap; } public static getCompilationStatistics( @@ -208,7 +208,7 @@ export class ModuleMinifierPlugin implements webpack.Plugin { } public apply(compiler: webpack.Compiler): void { - for (const enhancer of this._enhancers) { + for (const enhancer of this.#enhancers) { enhancer.apply(compiler); } @@ -217,14 +217,14 @@ export class ModuleMinifierPlugin implements webpack.Plugin { } = compiler; // The explicit setting is preferred due to accuracy, but try to guess based on devtool const useSourceMaps: boolean = - typeof this._sourceMap === 'boolean' - ? this._sourceMap + typeof this.#sourceMap === 'boolean' + ? this.#sourceMap : typeof devtool === 'string' ? devtool.endsWith('source-map') : mode === 'production' && devtool !== false; - this._optionsForHash.sourceMap = useSourceMaps; - const binaryConfig: Uint8Array = Buffer.from(JSON.stringify(this._optionsForHash), 'utf-8'); + this.#optionsForHash.sourceMap = useSourceMaps; + const binaryConfig: Uint8Array = Buffer.from(JSON.stringify(this.#optionsForHash), 'utf-8'); compiler.hooks.thisCompilation.tap( PLUGIN_NAME, diff --git a/webpack/webpack4-module-minifier-plugin/src/PortableMinifierIdsPlugin.ts b/webpack/webpack4-module-minifier-plugin/src/PortableMinifierIdsPlugin.ts index d52230ee6b1..9b467280a19 100644 --- a/webpack/webpack4-module-minifier-plugin/src/PortableMinifierIdsPlugin.ts +++ b/webpack/webpack4-module-minifier-plugin/src/PortableMinifierIdsPlugin.ts @@ -40,10 +40,10 @@ const STABLE_MODULE_ID_REGEX: RegExp = /(? = new Map(); - this._minifierHooks.finalModuleId.tap(PLUGIN_NAME, (id: string | number | undefined) => { + this.#minifierHooks.finalModuleId.tap(PLUGIN_NAME, (id: string | number | undefined) => { return id === undefined ? id : stableIdToFinalId.get(id); }); - this._minifierHooks.postProcessCodeFragment.tap( + this.#minifierHooks.postProcessCodeFragment.tap( PLUGIN_NAME, (source: ReplaceSource, context: IPostProcessFragmentContext) => { const code: string = source.original().source() as string; @@ -83,7 +83,7 @@ export class PortableMinifierModuleIdsPlugin implements Plugin { let match: RegExpExecArray | null = null; while ((match = STABLE_MODULE_ID_REGEX.exec(code))) { const id: string = match[1]; - const mapped: string | number | undefined = this._minifierHooks.finalModuleId.call( + const mapped: string | number | undefined = this.#minifierHooks.finalModuleId.call( id, context.compilation ); diff --git a/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts index e5a54496bad..44b84f34a52 100644 --- a/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts +++ b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts @@ -112,35 +112,35 @@ export function getPluginInstance(compiler: Compiler | undefined): LocalizationP * @public */ export class LocalizationPlugin implements WebpackPluginInstance { - private readonly _locFiles: Map = new Map(); + readonly #locFiles: Map = new Map(); /** * @internal */ public readonly _options: ILocalizationPluginOptions; - private readonly _resolvedTranslatedStringsFromOptions: Map< + readonly #resolvedTranslatedStringsFromOptions: Map< string, Map> > = new Map(); - private readonly _stringPlaceholderBySuffix: Map = new Map(); - private readonly _customDataPlaceholderBySuffix: Map = new Map(); - private readonly _customDataPlaceholderByUniqueId: Map = new Map(); - private _passthroughLocaleName!: string; - private _defaultLocale!: string; - private _noStringsLocaleName!: string; - private _fillMissingTranslationStrings!: boolean; + readonly #stringPlaceholderBySuffix: Map = new Map(); + readonly #customDataPlaceholderBySuffix: Map = new Map(); + readonly #customDataPlaceholderByUniqueId: Map = new Map(); + #passthroughLocaleName!: string; + #defaultLocale!: string; + #noStringsLocaleName!: string; + #fillMissingTranslationStrings!: boolean; /** * @remarks * Include the `chunk` parameter so that the functions arity is the same as the * `ValueForLocaleFn` type. */ - private _formatLocaleForFilename!: (loc: string, chunk: unknown) => string; - private readonly _pseudolocalizers: Map string> = new Map(); + #formatLocaleForFilename!: (loc: string, chunk: unknown) => string; + readonly #pseudolocalizers: Map string> = new Map(); /** * The set of locales that have translations provided. */ - private _translatedLocales: Set = new Set(); + #translatedLocales: Set = new Set(); public constructor(options: ILocalizationPluginOptions) { this._options = options; @@ -155,7 +155,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { // https://github.com/webpack/webpack-dev-server/pull/1929/files#diff-15fb51940da53816af13330d8ce69b4eR66 const isWebpackDevServer: boolean = process.env.WEBPACK_DEV_SERVER === 'true'; - const { errors, warnings } = this._initializeAndValidateOptions(compiler, isWebpackDevServer); + const { errors, warnings } = this.#initializeAndValidateOptions(compiler, isWebpackDevServer); if (errors.length > 0 || warnings.length > 0) { compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation: Compilation) => { @@ -278,7 +278,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { } if (chunkIdsWithStrings.size === 0) { - return this._formatLocaleForFilename(this._noStringsLocaleName, undefined); + return this.#formatLocaleForFilename(this.#noStringsLocaleName, undefined); } else if (chunkIdsWithoutStrings.size === 0) { return `" + ${localeExpression} + "`; } else { @@ -301,7 +301,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { } const noLocaleExpression: string = JSON.stringify( - this._formatLocaleForFilename(this._noStringsLocaleName, undefined) + this.#formatLocaleForFilename(this.#noStringsLocaleName, undefined) ); return `" + (${JSON.stringify(chunkMapping)}[chunkId]?${ @@ -318,11 +318,11 @@ export class LocalizationPlugin implements WebpackPluginInstance { runtimeLocaleExpression ); // Ensure that the initial name maps to a file that should exist in the final output - locale = isLocalized ? this._defaultLocale : this._noStringsLocaleName; + locale = isLocalized ? this.#defaultLocale : this.#noStringsLocaleName; } return assetPath.replace( Constants.LOCALE_FILENAME_TOKEN_REGEX, - this._formatLocaleForFilename(locale, undefined) + this.#formatLocaleForFilename(locale, undefined) ); } } else { @@ -341,7 +341,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING - 1 }, async (): Promise => { - const locales: Set = this._translatedLocales; + const locales: Set = this.#translatedLocales; const { chunkGraph, chunks } = compilation; const { localizationStats: statsOptions } = this._options; @@ -391,10 +391,10 @@ export class LocalizationPlugin implements WebpackPluginInstance { compilation, cache, locales, - defaultLocale: this._defaultLocale, - passthroughLocaleName: this._passthroughLocaleName, - fillMissingTranslationStrings: this._fillMissingTranslationStrings, - formatLocaleForFilenameFn: this._formatLocaleForFilename, + defaultLocale: this.#defaultLocale, + passthroughLocaleName: this.#passthroughLocaleName, + fillMissingTranslationStrings: this.#fillMissingTranslationStrings, + formatLocaleForFilenameFn: this.#formatLocaleForFilename, // Chunk-specific values chunk, asset, @@ -412,8 +412,8 @@ export class LocalizationPlugin implements WebpackPluginInstance { compilation, cache, hasUrlGenerator: chunksWithUrlGenerators.has(chunk), - noStringsLocaleName: this._noStringsLocaleName, - formatLocaleForFilenameFn: this._formatLocaleForFilename, + noStringsLocaleName: this.#noStringsLocaleName, + formatLocaleForFilenameFn: this.#formatLocaleForFilename, // Chunk-specific values chunk, asset, @@ -492,14 +492,14 @@ export class LocalizationPlugin implements WebpackPluginInstance { localizedResourceData: ILocalizationFile ): Promise> { const locFileData: ReadonlyMap = convertLocalizationFileToLocData(localizedResourceData); - const fileInfo: IFileTranslationInfo = this._addLocFileAndGetPlaceholders( - this._defaultLocale, + const fileInfo: IFileTranslationInfo = this.#addLocFileAndGetPlaceholders( + this.#defaultLocale, localizedFileKey, locFileData ); const missingLocales: string[] = []; - for (const [translatedLocaleName, translatedStrings] of this._resolvedTranslatedStringsFromOptions) { + for (const [translatedLocaleName, translatedStrings] of this.#resolvedTranslatedStringsFromOptions) { const translatedLocFileFromOptions: ILocaleFileData | undefined = translatedStrings.get(localizedFileKey); @@ -545,7 +545,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { } } - for (const [pseudolocaleName, pseudolocalizer] of this._pseudolocalizers) { + for (const [pseudolocaleName, pseudolocalizer] of this.#pseudolocalizers) { const pseudolocFileData: Map = new Map(); for (const [stringName, stringValue] of locFileData) { @@ -564,7 +564,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { * @public */ public getPlaceholder(localizedFileKey: string, stringName: string): IStringPlaceholder | undefined { - const file: IFileTranslationInfo | undefined = this._locFiles.get(localizedFileKey); + const file: IFileTranslationInfo | undefined = this.#locFiles.get(localizedFileKey); if (!file) { return undefined; } @@ -579,7 +579,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { placeholderUniqueId: string ): string { let placeholder: ICustomDataPlaceholder | undefined = - this._customDataPlaceholderByUniqueId.get(placeholderUniqueId); + this.#customDataPlaceholderByUniqueId.get(placeholderUniqueId); if (!placeholder) { // Get a hash of the unique ID to make sure its value doesn't interfere with our placeholder tokens const suffix: string = Buffer.from(placeholderUniqueId, 'utf-8').toString('hex'); @@ -588,8 +588,8 @@ export class LocalizationPlugin implements WebpackPluginInstance { suffix, valueForLocaleFn }; - this._customDataPlaceholderBySuffix.set(suffix, placeholder); - this._customDataPlaceholderByUniqueId.set(placeholderUniqueId, placeholder); + this.#customDataPlaceholderBySuffix.set(suffix, placeholder); + this.#customDataPlaceholderByUniqueId.set(placeholderUniqueId, placeholder); } else if (placeholder.valueForLocaleFn !== valueForLocaleFn) { throw new Error( `${this.getCustomDataPlaceholderForValueFunction.name} has already been called with "${placeholderUniqueId}" ` + @@ -604,29 +604,29 @@ export class LocalizationPlugin implements WebpackPluginInstance { * @internal */ public _getStringDataForSerialNumber(suffix: string): IStringPlaceholder | undefined { - return this._stringPlaceholderBySuffix.get(suffix); + return this.#stringPlaceholderBySuffix.get(suffix); } /** * @internal */ public _getCustomDataForSerialNumber(suffix: string): ICustomDataPlaceholder | undefined { - return this._customDataPlaceholderBySuffix.get(suffix); + return this.#customDataPlaceholderBySuffix.get(suffix); } - private _addLocFileAndGetPlaceholders( + #addLocFileAndGetPlaceholders( localeName: string, localizedFileKey: string, localizedFileData: ReadonlyMap ): IFileTranslationInfo { - let fileInfo: IFileTranslationInfo | undefined = this._locFiles.get(localizedFileKey); + let fileInfo: IFileTranslationInfo | undefined = this.#locFiles.get(localizedFileKey); if (!fileInfo) { fileInfo = { placeholders: new Map(), translations: new Map(), renderedPlaceholders: {} }; - this._locFiles.set(localizedFileKey, fileInfo); + this.#locFiles.set(localizedFileKey, fileInfo); } const { placeholders, translations } = fileInfo; const locFilePrefix: string = Buffer.from(localizedFileKey, 'utf-8').toString('hex') + '$'; @@ -646,7 +646,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { }; placeholders.set(stringName, placeholder); - this._stringPlaceholderBySuffix.set(suffix, placeholder); + this.#stringPlaceholderBySuffix.set(suffix, placeholder); } resultObject[stringName] = placeholder.value; @@ -658,7 +658,7 @@ export class LocalizationPlugin implements WebpackPluginInstance { return fileInfo; } - private _initializeAndValidateOptions( + #initializeAndValidateOptions( compiler: Compiler, isWebpackDevServer: boolean ): { errors: WebpackError[]; warnings: WebpackError[] } { @@ -707,8 +707,8 @@ export class LocalizationPlugin implements WebpackPluginInstance { if (passthroughLocale) { const { usePassthroughLocale, passthroughLocaleName = 'passthrough' } = passthroughLocale; if (usePassthroughLocale) { - this._passthroughLocaleName = passthroughLocaleName; - this._translatedLocales.add(passthroughLocaleName); + this.#passthroughLocaleName = passthroughLocaleName; + this.#translatedLocales.add(passthroughLocaleName); } } // END options.localizedData.passthroughLocale @@ -718,10 +718,10 @@ export class LocalizationPlugin implements WebpackPluginInstance { configuration.context?.startsWith('/') ? path.posix.resolve : path.resolve ).bind(0, configuration.context!); const { translatedStrings } = localizedData; - this._resolvedTranslatedStringsFromOptions.clear(); + this.#resolvedTranslatedStringsFromOptions.clear(); if (translatedStrings) { for (const [localeName, locale] of Object.entries(translatedStrings)) { - if (this._translatedLocales.has(localeName)) { + if (this.#translatedLocales.has(localeName)) { errors.push( new WebpackError( `The locale "${localeName}" appears multiple times. ` + @@ -735,9 +735,9 @@ export class LocalizationPlugin implements WebpackPluginInstance { return { errors, warnings }; } - this._translatedLocales.add(localeName); + this.#translatedLocales.add(localeName); const resolvedFromOptionsForLocale: Map = new Map(); - this._resolvedTranslatedStringsFromOptions.set(localeName, resolvedFromOptionsForLocale); + this.#resolvedTranslatedStringsFromOptions.set(localeName, resolvedFromOptionsForLocale); for (const [locFilePath, locFileDataFromOptions] of Object.entries(locale)) { const normalizedLocFilePath: string = resolveRelativeToContext(locFilePath); @@ -768,16 +768,16 @@ export class LocalizationPlugin implements WebpackPluginInstance { if (defaultLocale) { const { localeName, fillMissingTranslationStrings } = defaultLocale; if (localeName) { - if (this._translatedLocales.has(localeName)) { + if (this.#translatedLocales.has(localeName)) { errors.push(new WebpackError('The default locale is also specified in the translated strings.')); return { errors, warnings }; } else if (!ensureValidLocaleName(localeName)) { return { errors, warnings }; } - this._translatedLocales.add(localeName); - this._defaultLocale = localeName; - this._fillMissingTranslationStrings = !!fillMissingTranslationStrings; + this.#translatedLocales.add(localeName); + this.#defaultLocale = localeName; + this.#fillMissingTranslationStrings = !!fillMissingTranslationStrings; } else { errors.push(new WebpackError('Missing default locale name')); return { errors, warnings }; @@ -792,14 +792,14 @@ export class LocalizationPlugin implements WebpackPluginInstance { const { pseudolocales } = localizedData; if (pseudolocales) { for (const [pseudolocaleName, pseudoLocaleOpts] of Object.entries(pseudolocales)) { - if (this._defaultLocale === pseudolocaleName) { + if (this.#defaultLocale === pseudolocaleName) { errors.push( new WebpackError(`A pseudolocale (${pseudolocaleName}) name is also the default locale name.`) ); return { errors, warnings }; } - if (this._translatedLocales.has(pseudolocaleName)) { + if (this.#translatedLocales.has(pseudolocaleName)) { errors.push( new WebpackError( `A pseudolocale (${pseudolocaleName}) name is also specified in the translated strings.` @@ -808,8 +808,8 @@ export class LocalizationPlugin implements WebpackPluginInstance { return { errors, warnings }; } - this._pseudolocalizers.set(pseudolocaleName, getPseudolocalizer(pseudoLocaleOpts)); - this._translatedLocales.add(pseudolocaleName); + this.#pseudolocalizers.set(pseudolocaleName, getPseudolocalizer(pseudoLocaleOpts)); + this.#translatedLocales.add(pseudolocaleName); } } // END options.localizedData.pseudoLocales @@ -825,15 +825,15 @@ export class LocalizationPlugin implements WebpackPluginInstance { noStringsLocaleName === null || !ensureValidLocaleName(noStringsLocaleName) ) { - this._noStringsLocaleName = 'none'; + this.#noStringsLocaleName = 'none'; } else { - this._noStringsLocaleName = noStringsLocaleName; + this.#noStringsLocaleName = noStringsLocaleName; } // END options.noStringsLocaleName // START options.formatLocaleForFilename const { formatLocaleForFilename = (localeName: string) => localeName } = this._options; - this._formatLocaleForFilename = formatLocaleForFilename; + this.#formatLocaleForFilename = formatLocaleForFilename; // END options.formatLocaleForFilename return { errors, warnings }; } diff --git a/webpack/webpack5-localization-plugin/src/TrueHashPlugin.ts b/webpack/webpack5-localization-plugin/src/TrueHashPlugin.ts index 2c208ffce1b..0bd0921524d 100644 --- a/webpack/webpack5-localization-plugin/src/TrueHashPlugin.ts +++ b/webpack/webpack5-localization-plugin/src/TrueHashPlugin.ts @@ -26,17 +26,17 @@ export interface ITrueHashPluginOptions { * @public */ export class TrueHashPlugin implements WebpackPluginInstance { - private readonly _options: ITrueHashPluginOptions; + readonly #options: ITrueHashPluginOptions; public constructor(options: ITrueHashPluginOptions = {}) { - this._options = options; + this.#options = options; } public apply(compiler: Compiler): void { compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation: Compilation) => { const { webpack: thisWebpack } = compiler; const { hashFunction, stageOverride = thisWebpack.Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING - 1 } = - this._options; + this.#options; const hashFn: HashFn = hashFunction ?? getHashFunction({ diff --git a/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeTestBase.ts b/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeTestBase.ts index bb8af0ad213..26cbe8ad36b 100644 --- a/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeTestBase.ts +++ b/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeTestBase.ts @@ -14,15 +14,15 @@ import { type ITrueHashPluginOptions, TrueHashPlugin } from '../TrueHashPlugin'; import { markEntity } from '../utilities/EntityMarker'; class InjectCustomPlaceholderPlugin implements webpack.WebpackPluginInstance { - private readonly _localizationPlugin: LocalizationPlugin; - private readonly _localizedChunkNameByLocaleName: Map>; + readonly #localizationPlugin: LocalizationPlugin; + readonly #localizedChunkNameByLocaleName: Map>; public constructor( localizationPlugin: LocalizationPlugin, localizedChunkNameByLocaleName: Map> ) { - this._localizationPlugin = localizationPlugin; - this._localizedChunkNameByLocaleName = localizedChunkNameByLocaleName; + this.#localizationPlugin = localizationPlugin; + this.#localizedChunkNameByLocaleName = localizedChunkNameByLocaleName; } public apply(compiler: Compiler): void { @@ -30,9 +30,9 @@ class InjectCustomPlaceholderPlugin implements webpack.WebpackPluginInstance { const printLocalizedChunkName: 'printLocalizedChunkName' = 'printLocalizedChunkName'; const { runtime, RuntimeModule, Template, RuntimeGlobals } = compiler.webpack; - const localizationPlugin: LocalizationPlugin = this._localizationPlugin; + const localizationPlugin: LocalizationPlugin = this.#localizationPlugin; const localizedChunkNameByLocaleName: Map> = this - ._localizedChunkNameByLocaleName; + .#localizedChunkNameByLocaleName; function getLocalizedChunkNamesString(locale: string): string { return `/* ${locale} */ ${JSON.stringify(localizedChunkNameByLocaleName.get(locale))}`; diff --git a/webpack/webpack5-localization-plugin/src/test/MemFSPlugin.ts b/webpack/webpack5-localization-plugin/src/test/MemFSPlugin.ts index 5cc4e0508d8..12e77b2e79b 100644 --- a/webpack/webpack5-localization-plugin/src/test/MemFSPlugin.ts +++ b/webpack/webpack5-localization-plugin/src/test/MemFSPlugin.ts @@ -8,10 +8,10 @@ type IntermediateFileSystem = Compiler['intermediateFileSystem']; const PLUGIN_NAME: 'MemFSPlugin' = 'MemFSPlugin'; export class MemFSPlugin implements WebpackPluginInstance { - private readonly _memfs: Volume; + readonly #memfs: Volume; public constructor(memfs: Volume) { - this._memfs = memfs; + this.#memfs = memfs; } public apply(compiler: Compiler): void { @@ -19,9 +19,9 @@ export class MemFSPlugin implements WebpackPluginInstance { if (!nodeFileSystem) { throw new Error('MemFSPlugin requires compiler.inputFileSystem to be defined'); } - compiler.inputFileSystem = this._memfs as unknown as InputFileSystem; - compiler.intermediateFileSystem = this._memfs as unknown as IntermediateFileSystem; - compiler.outputFileSystem = this._memfs as unknown as OutputFileSystem; + compiler.inputFileSystem = this.#memfs as unknown as InputFileSystem; + compiler.intermediateFileSystem = this.#memfs as unknown as IntermediateFileSystem; + compiler.outputFileSystem = this.#memfs as unknown as OutputFileSystem; compiler.resolverFactory.hooks.resolveOptions.for('loader').tap( { stage: 10, diff --git a/webpack/webpack5-module-minifier-plugin/src/ModuleMinifierPlugin.ts b/webpack/webpack5-module-minifier-plugin/src/ModuleMinifierPlugin.ts index b98be12b188..61774c4fe2d 100644 --- a/webpack/webpack5-module-minifier-plugin/src/ModuleMinifierPlugin.ts +++ b/webpack/webpack5-module-minifier-plugin/src/ModuleMinifierPlugin.ts @@ -176,10 +176,10 @@ export class ModuleMinifierPlugin implements WebpackPluginInstance { public readonly hooks: IModuleMinifierPluginHooks; public minifier: IModuleMinifier; - private readonly _enhancers: WebpackPluginInstance[]; - private readonly _sourceMap: boolean | undefined; + readonly #enhancers: WebpackPluginInstance[]; + readonly #sourceMap: boolean | undefined; - private readonly _optionsForHash: IOptionsForHash; + readonly #optionsForHash: IOptionsForHash; public constructor(options: IModuleMinifierPluginOptions) { this.hooks = { @@ -190,18 +190,18 @@ export class ModuleMinifierPlugin implements WebpackPluginInstance { const { minifier, sourceMap } = options; - this._optionsForHash = { + this.#optionsForHash = { ...options, minifier: undefined, revision: CODE_GENERATION_REVISION }; - this._enhancers = []; + this.#enhancers = []; this.hooks.rehydrateAssets.tap(PLUGIN_NAME, defaultRehydrateAssets); this.minifier = minifier; - this._sourceMap = sourceMap; + this.#sourceMap = sourceMap; } public static getCompilationStatistics(compilation: Compilation): IModuleMinifierPluginStats | undefined { @@ -209,7 +209,7 @@ export class ModuleMinifierPlugin implements WebpackPluginInstance { } public apply(compiler: Compiler): void { - for (const enhancer of this._enhancers) { + for (const enhancer of this.#enhancers) { enhancer.apply(compiler); } @@ -223,14 +223,14 @@ export class ModuleMinifierPlugin implements WebpackPluginInstance { const { CachedSource, ConcatSource, RawSource, ReplaceSource, SourceMapSource } = webpack.sources; // The explicit setting is preferred due to accuracy, but try to guess based on devtool const useSourceMaps: boolean = - typeof this._sourceMap === 'boolean' - ? this._sourceMap + typeof this.#sourceMap === 'boolean' + ? this.#sourceMap : typeof devtool === 'string' ? devtool.endsWith('source-map') : mode === 'production' && devtool !== false; - this._optionsForHash.sourceMap = useSourceMaps; - const binaryConfig: Buffer = Buffer.from(JSON.stringify(this._optionsForHash), 'utf-8'); + this.#optionsForHash.sourceMap = useSourceMaps; + const binaryConfig: Buffer = Buffer.from(JSON.stringify(this.#optionsForHash), 'utf-8'); compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation, compilationData) => { const { normalModuleFactory } = compilationData;