diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 9e27f21779f..935ac6772e0 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,17 +1,24 @@
-.github/CODEOWNERS @iclanton @octogonz @patmill @apostolisms
-common/config/**/* @iclanton @octogonz @patmill @apostolisms
+.github/CODEOWNERS @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @patmill
+common/autoinstallers/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @patmill
+common/config/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @patmill
-common/reviews/**/* @iclanton @octogonz @apostolisms
+common/reviews/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
-apps/**/* @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L
-build-tests/**/* @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L
-core-build/**/* @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L
-libraries/**/* @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L
-stack/**/* @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L
-webpack/**/* @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L
-rush.json @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L
-.gitattributes @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L
-.gitignore @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L
-README.md @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L
+apps/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
+build-tests/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
+build-tests-samples/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
+eslint/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
+heft-plugins/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
+libraries/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
+repo-scripts/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
+rigs/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
+rush-plugins/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
+stack/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
+tutorials/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
+webpack/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @TheLarkInn
+rush.json @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
+.gitattributes @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
+.gitignore @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
+README.md @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft
-libraries/load-themed-styles/**/* @iclanton @octogonz @dzearing @apostolisms
+libraries/load-themed-styles/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @dzearing
diff --git a/.github/workflows/file-doc-tickets.yml b/.github/workflows/file-doc-tickets.yml
new file mode 100644
index 00000000000..d9ba3b0f374
--- /dev/null
+++ b/.github/workflows/file-doc-tickets.yml
@@ -0,0 +1,86 @@
+################################################################################
+# When pull requests are merged to the main branch, evaluate the pull request
+# body and file a documentation ticket against the rushstack-websites repo
+# with a corresponding documentation task.
+#
+# The pull request body must contain non-comment, non-whitespace text below
+# the "Impacted documentation" header in the PR template to file a
+# documentation ticket.
+################################################################################
+name: File Doc Tickets
+
+on:
+ pull_request:
+ branches:
+ - main
+ types:
+ - closed
+
+jobs:
+ file-tickets:
+ name: File Tickets
+ if: ${{ github.event.pull_request.merged }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Use nodejs
+ uses: actions/setup-node@v3
+ with:
+ node-version: 16
+ - name: Parse PR body
+ run: |
+ cat <<-"EOF" > event.json
+ ${{ toJson(github.event) }}
+ EOF
+
+ cat <<-"EOF" | node
+ const fs = require('fs');
+
+ const EVENT_FILE = 'event.json';
+ const RESULT_FILE = 'issue.md';
+ const DELIMITER = '## Impacted documentation';
+
+ const event = JSON.parse(fs.readFileSync(EVENT_FILE, 'utf8'));
+ const strippedBody = (event.pull_request.body || '').replace(//g, '');
+ const delimIndex = strippedBody.indexOf(DELIMITER);
+
+ if (delimIndex < 0) {
+ console.log('No documentation tasks detected -- skipping doc ticket.');
+ process.exit(0);
+ }
+
+ const delimBody = strippedBody.substring(delimIndex + DELIMITER.length).trim();
+
+ if (delimBody.length === 0) {
+ console.log('No documentation tasks detected -- skipping doc ticket.');
+ process.exit(0);
+ }
+
+ const quotedBody = delimBody.split('\n').map(line => `> ${line}`).join('\n');
+ fs.writeFileSync(RESULT_FILE, [
+ '### Summary',
+ '',
+ 'Follow up on documentation tasks from ' + event.pull_request.html_url + '.',
+ '',
+ '### Details',
+ '',
+ 'This ticket was generated automatically. Suggested documentation updates:',
+ '',
+ quotedBody,
+ ''
+ ].join('\n'), 'utf8');
+
+ EOF
+
+ if [ -f issue.md ]; then
+ echo "FILE_TICKET=1" >> $GITHUB_ENV
+ fi
+ - name: File ticket
+ if: ${{ env.FILE_TICKET == '1' }}
+ uses: peter-evans/create-issue-from-file@af31b99c72f9e91877aea8a2d96fd613beafac84 # @v4 (locked)
+ with:
+ repository: microsoft/rushstack-websites
+ token: '${{ secrets.RUSHSTACK_WEBSITES_TOKEN }}'
+ title: '[doc] ${{ github.event.pull_request.title }}'
+ content-filepath: ./issue.md
+ labels: |
+ automated
diff --git a/README.md b/README.md
index 1433532a4f7..debe4d8e017 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
-[![Zulip chat room](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://rushstack.zulipchat.com/) [![Build Status](https://github.com/microsoft/rushstack/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/microsoft/rushstack/actions/workflows/ci.yml?query=branch%3Amain) Open in Visual Studio Code
+[![Zulip chat room](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://rushstack.zulipchat.com/) [![Build Status](https://github.com/microsoft/rushstack/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/microsoft/rushstack/actions/workflows/ci.yml?query=branch%3Amain) Open in Visual Studio Code
The home for various projects maintained by the Rush Stack community, whose mission is to develop reusable tooling
for large scale TypeScript monorepos.
@@ -89,6 +89,7 @@ These GitHub repositories provide supplementary resources for Rush Stack:
| [/webpack/loader-raw-script](./webpack/loader-raw-script/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Floader-raw-script.svg)](https://badge.fury.io/js/%40rushstack%2Floader-raw-script) | [changelog](./webpack/loader-raw-script/CHANGELOG.md) | [@rushstack/loader-raw-script](https://www.npmjs.com/package/@rushstack/loader-raw-script) |
| [/webpack/preserve-dynamic-require-plugin](./webpack/preserve-dynamic-require-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fwebpack-preserve-dynamic-require-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fwebpack-preserve-dynamic-require-plugin) | [changelog](./webpack/preserve-dynamic-require-plugin/CHANGELOG.md) | [@rushstack/webpack-preserve-dynamic-require-plugin](https://www.npmjs.com/package/@rushstack/webpack-preserve-dynamic-require-plugin) |
| [/webpack/set-webpack-public-path-plugin](./webpack/set-webpack-public-path-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fset-webpack-public-path-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fset-webpack-public-path-plugin) | [changelog](./webpack/set-webpack-public-path-plugin/CHANGELOG.md) | [@rushstack/set-webpack-public-path-plugin](https://www.npmjs.com/package/@rushstack/set-webpack-public-path-plugin) |
+| [/webpack/webpack-embedded-dependencies-plugin](./webpack/webpack-embedded-dependencies-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fwebpack-embedded-dependencies-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fwebpack-embedded-dependencies-plugin) | [changelog](./webpack/webpack-embedded-dependencies-plugin/CHANGELOG.md) | [@rushstack/webpack-embedded-dependencies-plugin](https://www.npmjs.com/package/@rushstack/webpack-embedded-dependencies-plugin) |
| [/webpack/webpack-plugin-utilities](./webpack/webpack-plugin-utilities/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fwebpack-plugin-utilities.svg)](https://badge.fury.io/js/%40rushstack%2Fwebpack-plugin-utilities) | [changelog](./webpack/webpack-plugin-utilities/CHANGELOG.md) | [@rushstack/webpack-plugin-utilities](https://www.npmjs.com/package/@rushstack/webpack-plugin-utilities) |
| [/webpack/webpack4-localization-plugin](./webpack/webpack4-localization-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fwebpack4-localization-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fwebpack4-localization-plugin) | [changelog](./webpack/webpack4-localization-plugin/CHANGELOG.md) | [@rushstack/webpack4-localization-plugin](https://www.npmjs.com/package/@rushstack/webpack4-localization-plugin) |
| [/webpack/webpack4-module-minifier-plugin](./webpack/webpack4-module-minifier-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fwebpack4-module-minifier-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fwebpack4-module-minifier-plugin) | [changelog](./webpack/webpack4-module-minifier-plugin/CHANGELOG.md) | [@rushstack/webpack4-module-minifier-plugin](https://www.npmjs.com/package/@rushstack/webpack4-module-minifier-plugin) |
diff --git a/apps/api-documenter/CHANGELOG.json b/apps/api-documenter/CHANGELOG.json
index b9b7903d973..29847fe0c2f 100644
--- a/apps/api-documenter/CHANGELOG.json
+++ b/apps/api-documenter/CHANGELOG.json
@@ -1,6 +1,21 @@
{
"name": "@microsoft/api-documenter",
"entries": [
+ {
+ "version": "7.21.6",
+ "tag": "@microsoft/api-documenter_v7.21.6",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
{
"version": "7.21.5",
"tag": "@microsoft/api-documenter_v7.21.5",
diff --git a/apps/api-documenter/CHANGELOG.md b/apps/api-documenter/CHANGELOG.md
index 242e2a0c6f2..d7e13ecf252 100644
--- a/apps/api-documenter/CHANGELOG.md
+++ b/apps/api-documenter/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @microsoft/api-documenter
-This log was last generated on Fri, 10 Feb 2023 01:18:50 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 7.21.6
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 7.21.5
Fri, 10 Feb 2023 01:18:50 GMT
diff --git a/apps/api-documenter/package.json b/apps/api-documenter/package.json
index 7c0d098190f..a69a781e947 100644
--- a/apps/api-documenter/package.json
+++ b/apps/api-documenter/package.json
@@ -1,6 +1,6 @@
{
"name": "@microsoft/api-documenter",
- "version": "7.21.5",
+ "version": "7.21.6",
"description": "Read JSON files from api-extractor, generate documentation pages",
"repository": {
"type": "git",
diff --git a/apps/heft/CHANGELOG.json b/apps/heft/CHANGELOG.json
index 99070b2bd03..7b94432cdb7 100644
--- a/apps/heft/CHANGELOG.json
+++ b/apps/heft/CHANGELOG.json
@@ -1,6 +1,18 @@
{
"name": "@rushstack/heft",
"entries": [
+ {
+ "version": "0.50.0",
+ "tag": "@rushstack/heft_v0.50.0",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "minor": [
+ {
+ "comment": "Remove monkey-patching of TypeScript for compatibility with 5.0. Refactors how the multi-emit logic works."
+ }
+ ]
+ }
+ },
{
"version": "0.49.7",
"tag": "@rushstack/heft_v0.49.7",
diff --git a/apps/heft/CHANGELOG.md b/apps/heft/CHANGELOG.md
index f499698200a..6fbd50ebe89 100644
--- a/apps/heft/CHANGELOG.md
+++ b/apps/heft/CHANGELOG.md
@@ -1,6 +1,13 @@
# Change Log - @rushstack/heft
-This log was last generated on Fri, 10 Feb 2023 01:18:50 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.50.0
+Sat, 18 Mar 2023 00:20:56 GMT
+
+### Minor changes
+
+- Remove monkey-patching of TypeScript for compatibility with 5.0. Refactors how the multi-emit logic works.
## 0.49.7
Fri, 10 Feb 2023 01:18:50 GMT
diff --git a/apps/heft/package.json b/apps/heft/package.json
index f588954bc11..42096b5c232 100644
--- a/apps/heft/package.json
+++ b/apps/heft/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/heft",
- "version": "0.49.7",
+ "version": "0.50.0",
"description": "Build all your JavaScript projects the same way: A way that works.",
"keywords": [
"toolchain",
diff --git a/apps/heft/src/plugins/TypeScriptPlugin/EmitFilesPatch.ts b/apps/heft/src/plugins/TypeScriptPlugin/EmitFilesPatch.ts
deleted file mode 100644
index ffbf8bf9d07..00000000000
--- a/apps/heft/src/plugins/TypeScriptPlugin/EmitFilesPatch.ts
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
-// See LICENSE in the project root for license information.
-
-import { InternalError } from '@rushstack/node-core-library';
-import type * as TTypescript from 'typescript';
-import {
- ExtendedTypeScript,
- IEmitResolver,
- IEmitHost,
- IEmitTransformers,
- IExtendedSourceFile
-} from './internalTypings/TypeScriptInternals';
-
-export interface ICachedEmitModuleKind {
- moduleKind: TTypescript.ModuleKind;
-
- outFolderPath: string;
-
- /**
- * File extension to use instead of '.js' for emitted ECMAScript files.
- * For example, '.cjs' to indicate commonjs content, or '.mjs' to indicate ECMAScript modules.
- */
- jsExtensionOverride: string | undefined;
-
- /**
- * Set to true if this is the emit kind that is specified in the tsconfig.json.
- * Declarations are only emitted for the primary module kind.
- */
- isPrimary: boolean;
-}
-
-export class EmitFilesPatch {
- private static _patchedTs: ExtendedTypeScript | undefined = undefined;
-
- private static _baseEmitFiles: any | undefined = undefined; // eslint-disable-line
-
- public static install(
- ts: ExtendedTypeScript,
- tsconfig: TTypescript.ParsedCommandLine,
- moduleKindsToEmit: ICachedEmitModuleKind[],
- changedFiles?: Set
- ): void {
- if (EmitFilesPatch._patchedTs === ts) {
- // We already patched this instance of TS
- return;
- }
-
- if (EmitFilesPatch._patchedTs !== undefined) {
- throw new InternalError(
- 'EmitFilesPatch.install() cannot be called without first uninstalling the existing patch'
- );
- }
-
- EmitFilesPatch._patchedTs = ts;
- EmitFilesPatch._baseEmitFiles = ts.emitFiles;
-
- let foundPrimary: boolean = false;
- let defaultModuleKind: TTypescript.ModuleKind;
-
- for (const moduleKindToEmit of moduleKindsToEmit) {
- if (moduleKindToEmit.isPrimary) {
- if (foundPrimary) {
- throw new Error('Multiple primary module emit kinds encountered.');
- } else {
- foundPrimary = true;
- }
-
- defaultModuleKind = moduleKindToEmit.moduleKind;
- }
- }
-
- // Override the underlying file emitter to run itself once for each flavor
- // This is a rather inelegant way to convince the TypeScript compiler not to duplicate parse/link/check
- ts.emitFiles = (
- resolver: IEmitResolver,
- host: IEmitHost,
- targetSourceFile: IExtendedSourceFile | undefined,
- emitTransformers: IEmitTransformers,
- emitOnlyDtsFiles?: boolean,
- onlyBuildInfo?: boolean,
- forceDtsEmit?: boolean
- ): TTypescript.EmitResult => {
- if (onlyBuildInfo || emitOnlyDtsFiles) {
- // There should only be one tsBuildInfo and one set of declaration files
- return EmitFilesPatch._baseEmitFiles(
- resolver,
- host,
- targetSourceFile,
- emitTransformers,
- emitOnlyDtsFiles,
- onlyBuildInfo,
- forceDtsEmit
- );
- } else {
- if (targetSourceFile && changedFiles) {
- changedFiles.add(targetSourceFile);
- }
-
- let defaultModuleKindResult: TTypescript.EmitResult;
- const diagnostics: TTypescript.Diagnostic[] = [];
- let emitSkipped: boolean = false;
- for (const moduleKindToEmit of moduleKindsToEmit) {
- const compilerOptions: TTypescript.CompilerOptions = moduleKindToEmit.isPrimary
- ? {
- ...tsconfig.options
- }
- : {
- ...tsconfig.options,
- module: moduleKindToEmit.moduleKind,
- outDir: moduleKindToEmit.outFolderPath,
-
- // Don't emit declarations for secondary module kinds
- declaration: false,
- declarationMap: false
- };
-
- if (!compilerOptions.outDir) {
- throw new InternalError('Expected compilerOptions.outDir to be assigned');
- }
-
- const flavorResult: TTypescript.EmitResult = EmitFilesPatch._baseEmitFiles(
- resolver,
- {
- ...host,
- writeFile: EmitFilesPatch.wrapWriteFile(host.writeFile, moduleKindToEmit.jsExtensionOverride),
- getCompilerOptions: () => compilerOptions
- },
- targetSourceFile,
- ts.getTransformers(compilerOptions, undefined, emitOnlyDtsFiles),
- emitOnlyDtsFiles,
- onlyBuildInfo,
- forceDtsEmit
- );
-
- emitSkipped = emitSkipped || flavorResult.emitSkipped;
- for (const diagnostic of flavorResult.diagnostics) {
- diagnostics.push(diagnostic);
- }
-
- if (moduleKindToEmit.moduleKind === defaultModuleKind) {
- defaultModuleKindResult = flavorResult;
- }
- // Should results be aggregated, in case for whatever reason the diagnostics are not the same?
- }
-
- const mergedDiagnostics: readonly TTypescript.Diagnostic[] =
- ts.sortAndDeduplicateDiagnostics(diagnostics);
-
- return {
- ...defaultModuleKindResult!,
- diagnostics: mergedDiagnostics,
- emitSkipped
- };
- }
- };
- }
-
- public static get isInstalled(): boolean {
- return this._patchedTs !== undefined;
- }
-
- /**
- * Wraps the writeFile callback on the IEmitHost to override the .js extension, if applicable
- */
- public static wrapWriteFile(
- baseWriteFile: TTypescript.WriteFileCallback,
- jsExtensionOverride: string | undefined
- ): TTypescript.WriteFileCallback {
- if (!jsExtensionOverride) {
- return baseWriteFile;
- }
-
- const replacementExtension: string = `${jsExtensionOverride}$1`;
- return (
- fileName: string,
- data: string,
- writeBOM: boolean,
- onError?: ((message: string) => void) | undefined,
- sourceFiles?: readonly TTypescript.SourceFile[] | undefined
- ) => {
- return baseWriteFile(
- fileName.replace(/\.js(\.map)?$/g, replacementExtension),
- data,
- writeBOM,
- onError,
- sourceFiles
- );
- };
- }
-
- public static uninstall(ts: ExtendedTypeScript): void {
- if (EmitFilesPatch._patchedTs === undefined) {
- throw new InternalError('EmitFilesPatch.uninstall() cannot be called if no patch was installed');
- }
- if (ts !== EmitFilesPatch._patchedTs) {
- throw new InternalError('EmitFilesPatch.uninstall() called for the wrong object');
- }
-
- ts.emitFiles = EmitFilesPatch._baseEmitFiles;
-
- EmitFilesPatch._patchedTs = undefined;
- EmitFilesPatch._baseEmitFiles = undefined;
- }
-}
diff --git a/apps/heft/src/plugins/TypeScriptPlugin/TypeScriptBuilder.ts b/apps/heft/src/plugins/TypeScriptPlugin/TypeScriptBuilder.ts
index d9f6ea48938..a918def6328 100644
--- a/apps/heft/src/plugins/TypeScriptPlugin/TypeScriptBuilder.ts
+++ b/apps/heft/src/plugins/TypeScriptPlugin/TypeScriptBuilder.ts
@@ -5,12 +5,11 @@ import * as crypto from 'crypto';
import * as path from 'path';
import * as semver from 'semver';
import {
- FileSystemStats,
ITerminal,
JsonFile,
IPackageJson,
ITerminalProvider,
- FileSystem,
+ InternalError,
Path,
Async,
FileError
@@ -31,13 +30,30 @@ import { Tslint } from './Tslint';
import { Eslint } from './Eslint';
import { IScopedLogger } from '../../pluginFramework/logging/ScopedLogger';
-import { EmitFilesPatch, ICachedEmitModuleKind } from './EmitFilesPatch';
-import { HeftSession } from '../../pluginFramework/HeftSession';
+import type { HeftSession } from '../../pluginFramework/HeftSession';
import { EmitCompletedCallbackManager } from './EmitCompletedCallbackManager';
import { ISharedTypeScriptConfiguration } from './TypeScriptPlugin';
import { TypeScriptCachedFileSystem } from '../../utilities/fileSystem/TypeScriptCachedFileSystem';
import { LinterBase } from './LinterBase';
+interface ICachedEmitModuleKind {
+ moduleKind: TTypescript.ModuleKind;
+
+ outFolderPath: string;
+
+ /**
+ * File extension to use instead of '.js' for emitted ECMAScript files.
+ * For example, '.cjs' to indicate commonjs content, or '.mjs' to indicate ECMAScript modules.
+ */
+ jsExtensionOverride: string | undefined;
+
+ /**
+ * Set to true if this is the emit kind that is specified in the tsconfig.json.
+ * Declarations are only emitted for the primary module kind.
+ */
+ isPrimary: boolean;
+}
+
interface ILinterWrapper {
ts: ExtendedTypeScript;
logger: IScopedLogger;
@@ -78,8 +94,6 @@ type TSolutionHost = TTypescript.SolutionBuilderHost;
-const EMPTY_JSON: object = {};
-
interface ICompilerCapabilities {
/**
* Support for incremental compilation via `ts.createIncrementalProgram()`.
@@ -114,8 +128,12 @@ interface IExtendedEmitResult extends TTypescript.EmitResult {
const OLDEST_SUPPORTED_TS_MAJOR_VERSION: number = 2;
const OLDEST_SUPPORTED_TS_MINOR_VERSION: number = 9;
-const NEWEST_SUPPORTED_TS_MAJOR_VERSION: number = 4;
-const NEWEST_SUPPORTED_TS_MINOR_VERSION: number = 8;
+const NEWEST_SUPPORTED_TS_MAJOR_VERSION: number = 5;
+const NEWEST_SUPPORTED_TS_MINOR_VERSION: number = 0;
+
+// symbols for attaching hidden metadata to ts.Program instances.
+const INNER_GET_COMPILER_OPTIONS_SYMBOL: unique symbol = Symbol('getCompilerOptions');
+const INNER_EMIT_SYMBOL: unique symbol = Symbol('emit');
export class TypeScriptBuilder extends SubprocessRunnerBase {
private _typescriptVersion!: string;
@@ -132,9 +150,9 @@ export class TypeScriptBuilder extends SubprocessRunnerBase = new Set();
private __tsCacheFilePath: string | undefined;
- private _tsReadJsonCache: Map = new Map();
private _cachedFileSystem: TypeScriptCachedFileSystem = new TypeScriptCachedFileSystem();
public get filename(): string {
@@ -260,6 +278,18 @@ export class TypeScriptBuilder extends SubprocessRunnerBase(
measurementName: string,
fn: () => TResult
@@ -305,6 +335,215 @@ export class TypeScriptBuilder extends SubprocessRunnerBase {
+ const createMultiEmitBuilderProgram: TTypescript.CreateProgram<
+ TTypescript.EmitAndSemanticDiagnosticsBuilderProgram
+ > = (
+ fileNames: readonly string[] | undefined,
+ compilerOptions: TTypescript.CompilerOptions | undefined,
+ host: TTypescript.CompilerHost | undefined,
+ oldProgram: TTypescript.EmitAndSemanticDiagnosticsBuilderProgram | undefined,
+ configFileParsingDiagnostics: readonly TTypescript.Diagnostic[] | undefined,
+ projectReferences: readonly TTypescript.ProjectReference[] | undefined
+ ): TTypescript.EmitAndSemanticDiagnosticsBuilderProgram => {
+ // Reset performance counters
+ ts.performance.disable();
+ ts.performance.enable();
+
+ this._typescriptTerminal.writeVerboseLine(`Reading program "${compilerOptions!.configFilePath}"`);
+
+ const newProgram: TTypescript.EmitAndSemanticDiagnosticsBuilderProgram =
+ ts.createEmitAndSemanticDiagnosticsBuilderProgram(
+ fileNames,
+ compilerOptions,
+ host,
+ oldProgram,
+ configFileParsingDiagnostics,
+ projectReferences
+ );
+
+ this._logReadPerformance(ts);
+
+ const { emit: originalEmit } = newProgram;
+
+ const emit: TTypescript.Program['emit'] = (
+ outerTargetSourceFile?: TTypescript.SourceFile,
+ outerWriteFile?: TTypescript.WriteFileCallback,
+ outerCancellationToken?: TTypescript.CancellationToken,
+ outerEmitOnlyDtsFiles?: boolean,
+ outerCustomTransformers?: TTypescript.CustomTransformers
+ ) => {
+ const innerProgram: TTypescript.Program = newProgram.getProgram();
+
+ const innerCompilerOptions: TTypescript.CompilerOptions = innerProgram.getCompilerOptions();
+
+ const { changedFiles } = this._configureProgramForMultiEmit(innerProgram, ts);
+
+ const result: TTypescript.EmitResult = originalEmit.call(
+ newProgram,
+ outerTargetSourceFile,
+ outerWriteFile,
+ outerCancellationToken,
+ outerEmitOnlyDtsFiles,
+ outerCustomTransformers
+ );
+
+ (result as IExtendedEmitResult).changedSourceFiles = changedFiles;
+
+ this._typescriptTerminal.writeVerboseLine(
+ `Emitting program "${innerCompilerOptions!.configFilePath}"`
+ );
+
+ this._logEmitPerformance(ts);
+
+ // Reset performance counters
+ ts.performance.disable();
+ ts.performance.enable();
+
+ return result;
+ };
+
+ newProgram.emit = emit;
+
+ return newProgram;
+ };
+
+ return createMultiEmitBuilderProgram;
+ }
+
+ private _configureProgramForMultiEmit(
+ innerProgram: TTypescript.Program,
+ ts: ExtendedTypeScript
+ ): { changedFiles: Set } {
+ interface IProgramWithMultiEmit extends TTypescript.Program {
+ // Attach the originals to the Program instance to avoid modifying the same Program twice.
+ // Don't use WeakMap because this Program could theoretically get a { ... } applied to it.
+ [INNER_GET_COMPILER_OPTIONS_SYMBOL]?: TTypescript.Program['getCompilerOptions'];
+ [INNER_EMIT_SYMBOL]?: TTypescript.Program['emit'];
+ }
+
+ const program: IProgramWithMultiEmit = innerProgram;
+
+ // Check to see if this Program has already been modified.
+ let { [INNER_EMIT_SYMBOL]: innerEmit, [INNER_GET_COMPILER_OPTIONS_SYMBOL]: innerGetCompilerOptions } =
+ program;
+
+ if (!innerGetCompilerOptions) {
+ program[INNER_GET_COMPILER_OPTIONS_SYMBOL] = innerGetCompilerOptions = program.getCompilerOptions;
+ }
+
+ if (!innerEmit) {
+ program[INNER_EMIT_SYMBOL] = innerEmit = program.emit;
+ }
+
+ let foundPrimary: boolean = false;
+ let defaultModuleKind: TTypescript.ModuleKind;
+
+ const multiEmitMap: Map = new Map();
+ for (const moduleKindToEmit of this._moduleKindsToEmit) {
+ const kindCompilerOptions: TTypescript.CompilerOptions = moduleKindToEmit.isPrimary
+ ? {
+ ...innerGetCompilerOptions()
+ }
+ : {
+ ...innerGetCompilerOptions(),
+ module: moduleKindToEmit.moduleKind,
+ outDir: moduleKindToEmit.outFolderPath,
+
+ // Don't emit declarations for secondary module kinds
+ declaration: false,
+ declarationMap: false
+ };
+ if (!kindCompilerOptions.outDir) {
+ throw new InternalError('Expected compilerOptions.outDir to be assigned');
+ }
+ multiEmitMap.set(moduleKindToEmit, kindCompilerOptions);
+
+ if (moduleKindToEmit.isPrimary) {
+ if (foundPrimary) {
+ throw new Error('Multiple primary module emit kinds encountered.');
+ } else {
+ foundPrimary = true;
+ }
+
+ defaultModuleKind = moduleKindToEmit.moduleKind;
+ }
+ }
+
+ const changedFiles: Set = new Set();
+
+ program.emit = (
+ targetSourceFile?: TTypescript.SourceFile,
+ writeFile?: TTypescript.WriteFileCallback,
+ cancellationToken?: TTypescript.CancellationToken,
+ emitOnlyDtsFiles?: boolean,
+ customTransformers?: TTypescript.CustomTransformers
+ ) => {
+ if (emitOnlyDtsFiles) {
+ return program[INNER_EMIT_SYMBOL]!(
+ targetSourceFile,
+ writeFile,
+ cancellationToken,
+ emitOnlyDtsFiles,
+ customTransformers
+ );
+ }
+
+ if (targetSourceFile && changedFiles) {
+ changedFiles.add(targetSourceFile as IExtendedSourceFile);
+ }
+
+ const originalCompilerOptions: TTypescript.CompilerOptions =
+ program[INNER_GET_COMPILER_OPTIONS_SYMBOL]!();
+
+ let defaultModuleKindResult: TTypescript.EmitResult;
+ const diagnostics: TTypescript.Diagnostic[] = [];
+ let emitSkipped: boolean = false;
+ try {
+ for (const [moduleKindToEmit, kindCompilerOptions] of multiEmitMap) {
+ program.getCompilerOptions = () => kindCompilerOptions;
+ // Need to mutate the compiler options for the `module` field specifically, because emitWorker() captures
+ // options in the closure and passes it to `ts.getTransformers()`
+ originalCompilerOptions.module = moduleKindToEmit.moduleKind;
+ const flavorResult: TTypescript.EmitResult = program[INNER_EMIT_SYMBOL]!(
+ targetSourceFile,
+ writeFile && wrapWriteFile(writeFile, moduleKindToEmit.jsExtensionOverride),
+ cancellationToken,
+ emitOnlyDtsFiles,
+ customTransformers
+ );
+
+ emitSkipped = emitSkipped || flavorResult.emitSkipped;
+ // Need to aggregate diagnostics because some are impacted by the target module type
+ for (const diagnostic of flavorResult.diagnostics) {
+ diagnostics.push(diagnostic);
+ }
+
+ if (moduleKindToEmit.moduleKind === defaultModuleKind) {
+ defaultModuleKindResult = flavorResult;
+ }
+ }
+
+ const mergedDiagnostics: readonly TTypescript.Diagnostic[] =
+ ts.sortAndDeduplicateDiagnostics(diagnostics);
+
+ return {
+ ...defaultModuleKindResult!,
+ changedSourceFiles: changedFiles,
+ diagnostics: mergedDiagnostics,
+ emitSkipped
+ };
+ } finally {
+ // Restore the original compiler options and module kind for future calls
+ program.getCompilerOptions = program[INNER_GET_COMPILER_OPTIONS_SYMBOL]!;
+ originalCompilerOptions.module = defaultModuleKind;
+ }
+ };
+ return { changedFiles };
+ }
+
private _resolveEslintConfigFilePath(eslintEnabled: boolean): string {
const defaultPath: string = path.resolve(this._configuration.buildFolder, '.eslintrc.js');
if (!eslintEnabled) {
@@ -324,7 +563,6 @@ export class TypeScriptBuilder extends SubprocessRunnerBase {
const _tsconfig: TTypescript.ParsedCommandLine = this._loadTsconfig(ts);
this._validateTsconfig(ts, _tsconfig);
- EmitFilesPatch.install(ts, _tsconfig, this._moduleKindsToEmit);
return {
tsconfig: _tsconfig
@@ -360,7 +598,6 @@ export class TypeScriptBuilder extends SubprocessRunnerBase {
- this._overrideTypeScriptReadJson(ts);
const _tsconfig: TTypescript.ParsedCommandLine = this._loadTsconfig(ts);
this._validateTsconfig(ts, _tsconfig);
@@ -377,19 +614,20 @@ export class TypeScriptBuilder extends SubprocessRunnerBase {
+ filesToWrite.push({ filePath, data });
+ };
+
+ const { changedFiles } = this._configureProgramForMultiEmit(innerProgram, ts);
+
+ const emitResult: TTypescript.EmitResult = genericProgram.emit(undefined, writeFileCallback);
//#endregion
this._logEmitPerformance(ts);
@@ -437,7 +683,7 @@ export class TypeScriptBuilder extends SubprocessRunnerBase = measureTsPerformanceAsync('Write', () =>
Async.forEachAsync(
- emitResult.filesToWrite,
+ filesToWrite,
async ({ filePath, data }: { filePath: string; data: string }) =>
this._cachedFileSystem.writeFile(filePath, data, { ensureFolderExists: true }),
{ concurrency: this._configuration.maxWriteParallelism }
@@ -451,23 +697,21 @@ export class TypeScriptBuilder extends SubprocessRunnerBase>[] = [];
- const extendedProgram: IExtendedProgram = tsProgram as IExtendedProgram;
+ const extendedProgram: IExtendedProgram = innerProgram as IExtendedProgram;
//#region ESLINT
if (eslint) {
- lintPromises.push(this._runESlintAsync(eslint, extendedProgram, emitResult.changedSourceFiles));
+ lintPromises.push(this._runESlintAsync(eslint, extendedProgram, changedFiles));
}
//#endregion
//#region TSLINT
if (tslint) {
- lintPromises.push(this._runTSlintAsync(tslint, extendedProgram, emitResult.changedSourceFiles));
+ lintPromises.push(this._runTSlintAsync(tslint, extendedProgram, changedFiles));
}
//#endregion
const { duration: writeDuration } = await writePromise;
- this._typescriptTerminal.writeVerboseLine(
- `I/O Write: ${writeDuration}ms (${emitResult.filesToWrite.length} files)`
- );
+ this._typescriptTerminal.writeVerboseLine(`I/O Write: ${writeDuration}ms (${filesToWrite.length} files)`);
// In non-watch mode, notify EmitCompletedCallbackManager once after we complete the compile step
this._emitCompletedCallbackManager.callback();
@@ -492,7 +736,6 @@ export class TypeScriptBuilder extends SubprocessRunnerBase {
- this._overrideTypeScriptReadJson(ts);
const _tsconfig: TTypescript.ParsedCommandLine = this._loadTsconfig(ts);
this._validateTsconfig(ts, _tsconfig);
@@ -506,9 +749,6 @@ export class TypeScriptBuilder extends SubprocessRunnerBase[] = await Promise.all(lintPromises);
this._logDiagnostics(ts, rawDiagnostics, linters);
-
- EmitFilesPatch.uninstall(ts);
}
private _logDiagnostics(
@@ -783,45 +1021,13 @@ export class TypeScriptBuilder extends SubprocessRunnerBase = new Set();
- EmitFilesPatch.install(ts, tsconfig, this._moduleKindsToEmit, changedFiles);
-
- const writeFileCallback: TTypescript.WriteFileCallback = (filePath: string, data: string) => {
- filesToWrite.push({ filePath, data });
- };
-
- const result: TTypescript.EmitResult = genericProgram.emit(
- undefined, // Target source file
- writeFileCallback
- );
-
- EmitFilesPatch.uninstall(ts);
-
- return {
- ...result,
- changedSourceFiles: changedFiles,
- filesToWrite
- };
- }
-
private _validateTsconfig(ts: ExtendedTypeScript, tsconfig: TTypescript.ParsedCommandLine): void {
if (
(tsconfig.options.module && !tsconfig.options.outDir) ||
@@ -1061,8 +1267,8 @@ export class TypeScriptBuilder extends SubprocessRunnerBase =
ts.createSolutionBuilderHost(
- this._getCachingTypeScriptSystem(ts),
- ts.createEmitAndSemanticDiagnosticsBuilderProgram,
+ ts.sys,
+ this._getCreateBuilderProgram(ts),
reportDiagnostic,
reportSolutionBuilderStatus,
reportEmitErrorSummary
@@ -1076,53 +1282,12 @@ export class TypeScriptBuilder extends SubprocessRunnerBase {
- try {
- const stats: FileSystemStats = this._cachedFileSystem.getStatistics(directoryPath);
- return stats.isDirectory() || stats.isSymbolicLink();
- } catch (error) {
- if (FileSystem.isNotExistError(error as Error)) {
- return false;
- } else {
- throw error;
- }
- }
- },
- /** Check if the path exists and is a file */
- fileExists: (filePath: string) => {
- try {
- const stats: FileSystemStats = this._cachedFileSystem.getStatistics(filePath);
- return stats.isFile();
- } catch (error) {
- if (FileSystem.isNotExistError(error as Error)) {
- return false;
- } else {
- throw error;
- }
- }
- },
- /* Use the Heft config's build folder because it has corrected casing */
- getCurrentDirectory: () => this._configuration.buildFolder,
- getDirectories: (folderPath: string) => {
- return this._cachedFileSystem.readFolderFilesAndDirectories(folderPath).directories;
- },
- realpath: this._cachedFileSystem.getRealPath.bind(this._cachedFileSystem)
- };
-
- return sys;
- }
-
private _buildWatchCompilerHost(
ts: ExtendedTypeScript,
tsconfig: TTypescript.ParsedCommandLine
@@ -1145,8 +1310,8 @@ export class TypeScriptBuilder extends SubprocessRunnerBase {
- let jsonData: object | undefined = this._tsReadJsonCache.get(filePath);
- if (jsonData) {
- return jsonData;
- } else {
- try {
- const fileContents: string = this._cachedFileSystem.readFile(filePath);
- if (!fileContents) {
- jsonData = EMPTY_JSON;
- } else {
- const parsedFile: ReturnType = ts.parseConfigFileTextToJson(
- filePath,
- fileContents
- );
- if (parsedFile.error) {
- jsonData = EMPTY_JSON;
- } else {
- jsonData = parsedFile.config as object;
- }
- }
- } catch (error) {
- jsonData = EMPTY_JSON;
- }
-
- this._tsReadJsonCache.set(filePath, jsonData);
- return jsonData;
- }
- };
- }
-
private _parseModuleKind(ts: ExtendedTypeScript, moduleKindName: string): TTypescript.ModuleKind {
switch (moduleKindName.toLowerCase()) {
case 'commonjs':
@@ -1235,3 +1369,31 @@ export class TypeScriptBuilder extends SubprocessRunnerBase void) | undefined,
+ sourceFiles?: readonly TTypescript.SourceFile[] | undefined
+ ) => {
+ return baseWriteFile(
+ fileName.replace(JS_EXTENSION_REGEX, replacementExtension),
+ data,
+ writeBOM,
+ onError,
+ sourceFiles
+ );
+ };
+}
diff --git a/apps/heft/src/plugins/TypeScriptPlugin/internalTypings/TypeScriptInternals.ts b/apps/heft/src/plugins/TypeScriptPlugin/internalTypings/TypeScriptInternals.ts
index 95320db78b7..bfbb6d10209 100644
--- a/apps/heft/src/plugins/TypeScriptPlugin/internalTypings/TypeScriptInternals.ts
+++ b/apps/heft/src/plugins/TypeScriptPlugin/internalTypings/TypeScriptInternals.ts
@@ -3,24 +3,6 @@
import type * as TTypescript from 'typescript';
-// The specifics of these types aren't important
-/**
- * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/types.ts#L3969-L4010
- */
-export interface IEmitResolver {}
-
-/**
- * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/types.ts#L5969-L5988
- */
-export interface IEmitHost {
- writeFile: TTypescript.WriteFileCallback;
-}
-
-/**
- * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/types.ts#L3338-L3341
- */
-export interface IEmitTransformers {}
-
export interface IExtendedProgram extends TTypescript.Program {
/**
* https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/types.ts#L3205
@@ -39,20 +21,16 @@ export interface IExtendedSourceFile extends TTypescript.SourceFile {
version: string;
}
-/**
- * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/utilities.ts#L3799-L3803
- */
-export interface IResolveModuleNameResolutionHost {
- getCanonicalFileName(p: string): string;
- getCommonSourceDirectory(): string;
- getCurrentDirectory(): string;
-}
-
export interface IExtendedTypeScript {
/**
* https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/performance.ts#L3
*/
performance: {
+ /**
+ * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/performance.ts#L119-L121
+ */
+ disable(): void;
+
/**
* https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/performance.ts#L110-L116
*/
@@ -79,11 +57,6 @@ export interface IExtendedTypeScript {
getCount(measureName: string): number;
};
- /**
- * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/utilities.ts#L4720-L4734
- */
- readJson(filePath: string): object;
-
/**
* https://github.com/microsoft/TypeScript/blob/782c09d783e006a697b4ba6d1e7ec2f718ce8393/src/compiler/utilities.ts#L6540
*/
@@ -103,42 +76,6 @@ export interface IExtendedTypeScript {
directoryExists: (path: string) => boolean
): string[];
- /**
- * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/emitter.ts#L261-L614
- */
- emitFiles(
- resolver: IEmitResolver,
- host: IEmitHost,
- targetSourceFile: TTypescript.SourceFile | undefined,
- emitTransformers: IEmitTransformers,
- emitOnlyDtsFiles?: boolean,
- onlyBuildInfo?: boolean,
- forceDtsEmit?: boolean
- ): TTypescript.EmitResult;
-
- /**
- * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/transformer.ts#L30-L35
- */
- getTransformers(
- compilerOptions: TTypescript.CompilerOptions,
- customTransformers?: TTypescript.CustomTransformers,
- emitOnlyDtsFiles?: boolean
- ): IEmitTransformers;
-
- /**
- * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/utilities.ts#L6100-L6108
- */
- removeFileExtension(path: string): string;
-
- /**
- * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/utilities.ts#L3826-L3833
- */
- getExternalModuleNameFromPath(
- host: IResolveModuleNameResolutionHost,
- fileName: string,
- referencePath?: string
- ): string;
-
Diagnostics: {
// https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/diagnosticMessages.json#L4252-L4255
// eslint-disable-next-line @typescript-eslint/naming-convention
diff --git a/apps/lockfile-explorer/CHANGELOG.json b/apps/lockfile-explorer/CHANGELOG.json
index efc7fd8e593..635c791aefc 100644
--- a/apps/lockfile-explorer/CHANGELOG.json
+++ b/apps/lockfile-explorer/CHANGELOG.json
@@ -1,6 +1,21 @@
{
"name": "@rushstack/lockfile-explorer",
"entries": [
+ {
+ "version": "1.0.9",
+ "tag": "@rushstack/lockfile-explorer_v1.0.9",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ }
+ ]
+ }
+ },
{
"version": "1.0.8",
"tag": "@rushstack/lockfile-explorer_v1.0.8",
diff --git a/apps/lockfile-explorer/CHANGELOG.md b/apps/lockfile-explorer/CHANGELOG.md
index 8a3256b2c0b..e942ef4e1d5 100644
--- a/apps/lockfile-explorer/CHANGELOG.md
+++ b/apps/lockfile-explorer/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/lockfile-explorer
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 1.0.9
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 1.0.8
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/apps/lockfile-explorer/package.json b/apps/lockfile-explorer/package.json
index 8c408eaa664..29cbeb93bcc 100644
--- a/apps/lockfile-explorer/package.json
+++ b/apps/lockfile-explorer/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/lockfile-explorer",
- "version": "1.0.8",
+ "version": "1.0.9",
"description": "Rush Lockfile Explorer: The UI for solving version conflicts quickly in a large monorepo",
"keywords": [
"conflict",
diff --git a/apps/rundown/CHANGELOG.json b/apps/rundown/CHANGELOG.json
index 491e7bc895c..6ccf81f46b6 100644
--- a/apps/rundown/CHANGELOG.json
+++ b/apps/rundown/CHANGELOG.json
@@ -1,6 +1,21 @@
{
"name": "@rushstack/rundown",
"entries": [
+ {
+ "version": "1.0.243",
+ "tag": "@rushstack/rundown_v1.0.243",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
{
"version": "1.0.242",
"tag": "@rushstack/rundown_v1.0.242",
diff --git a/apps/rundown/CHANGELOG.md b/apps/rundown/CHANGELOG.md
index af95789e281..33d112b7250 100644
--- a/apps/rundown/CHANGELOG.md
+++ b/apps/rundown/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/rundown
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 1.0.243
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 1.0.242
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/apps/rundown/package.json b/apps/rundown/package.json
index 7997f298181..f4855e8f6c5 100644
--- a/apps/rundown/package.json
+++ b/apps/rundown/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/rundown",
- "version": "1.0.242",
+ "version": "1.0.243",
"description": "Detect load time regressions by running an app, tracing require() calls, and generating a deterministic report",
"repository": {
"type": "git",
diff --git a/apps/rush/CHANGELOG.json b/apps/rush/CHANGELOG.json
index 1870a671886..c5dcde255fc 100644
--- a/apps/rush/CHANGELOG.json
+++ b/apps/rush/CHANGELOG.json
@@ -1,6 +1,81 @@
{
"name": "@microsoft/rush",
"entries": [
+ {
+ "version": "5.96.0",
+ "tag": "@microsoft/rush_v5.96.0",
+ "date": "Fri, 31 Mar 2023 00:27:51 GMT",
+ "comments": {
+ "none": [
+ {
+ "comment": "Fix an issue where rush-sdk sometimes failed to load if the globally installed Rush version was older than rushVersion in rush.json (GitHub #4039)"
+ },
+ {
+ "comment": "Modify the scheduling behavior of phased commands to schedule only the expressly enumerated phases in all selected projects, adding additional phases only where needed to satisfy dependencies."
+ }
+ ]
+ }
+ },
+ {
+ "version": "5.95.0",
+ "tag": "@microsoft/rush_v5.95.0",
+ "date": "Fri, 24 Mar 2023 08:53:43 GMT",
+ "comments": {
+ "none": [
+ {
+ "comment": "Add experiment `printEventHooksOutputToConsole` to allow printing outputs from event hooks to the console."
+ }
+ ]
+ }
+ },
+ {
+ "version": "5.94.1",
+ "tag": "@microsoft/rush_v5.94.1",
+ "date": "Wed, 22 Mar 2023 20:48:48 GMT",
+ "comments": {
+ "none": [
+ {
+ "comment": "Fix an issue where rush plugin autoinstallers would fail to install because the Rush global folder had not yet been initialized."
+ },
+ {
+ "comment": "Fix an issue with `rush update-autoinstaller` where it may fail with an `Cannot install with \"frozen-lockfile\" because pnpm-lock.yaml is not up to date with package.json` error."
+ }
+ ]
+ }
+ },
+ {
+ "version": "5.94.0",
+ "tag": "@microsoft/rush_v5.94.0",
+ "date": "Mon, 20 Mar 2023 20:14:36 GMT",
+ "comments": {
+ "none": [
+ {
+ "comment": "Update the `nodeSupportedVersionRange` in `rush.json` generated by `rush init` to remove Node 12 as it is no longer supported and include Node 18 as it is the current LTS version."
+ },
+ {
+ "comment": "Extend LookupByPath to also be able to obtain the index of the remainder of the matched path."
+ },
+ {
+ "comment": "Include some more hooks to allow plugins to monitor phased command execution in real-time."
+ },
+ {
+ "comment": "Fix an issue where running `rush update-autoinstaller` without having run `rush install` or `rush update` first would cause a crash with an unhelpful error message."
+ }
+ ]
+ }
+ },
+ {
+ "version": "5.93.2",
+ "tag": "@microsoft/rush_v5.93.2",
+ "date": "Mon, 06 Mar 2023 20:18:01 GMT",
+ "comments": {
+ "none": [
+ {
+ "comment": "Do not delete the local pnpm store after all install attempts has failed. `rush purge` will still delete a local store."
+ }
+ ]
+ }
+ },
{
"version": "5.93.1",
"tag": "@microsoft/rush_v5.93.1",
diff --git a/apps/rush/CHANGELOG.md b/apps/rush/CHANGELOG.md
index 39ea008752a..65d96cbcde3 100644
--- a/apps/rush/CHANGELOG.md
+++ b/apps/rush/CHANGELOG.md
@@ -1,6 +1,46 @@
# Change Log - @microsoft/rush
-This log was last generated on Fri, 17 Feb 2023 14:46:59 GMT and should not be manually modified.
+This log was last generated on Fri, 31 Mar 2023 00:27:51 GMT and should not be manually modified.
+
+## 5.96.0
+Fri, 31 Mar 2023 00:27:51 GMT
+
+### Updates
+
+- Fix an issue where rush-sdk sometimes failed to load if the globally installed Rush version was older than rushVersion in rush.json (GitHub #4039)
+- Modify the scheduling behavior of phased commands to schedule only the expressly enumerated phases in all selected projects, adding additional phases only where needed to satisfy dependencies.
+
+## 5.95.0
+Fri, 24 Mar 2023 08:53:43 GMT
+
+### Updates
+
+- Add experiment `printEventHooksOutputToConsole` to allow printing outputs from event hooks to the console.
+
+## 5.94.1
+Wed, 22 Mar 2023 20:48:48 GMT
+
+### Updates
+
+- Fix an issue where rush plugin autoinstallers would fail to install because the Rush global folder had not yet been initialized.
+- Fix an issue with `rush update-autoinstaller` where it may fail with an `Cannot install with "frozen-lockfile" because pnpm-lock.yaml is not up to date with package.json` error.
+
+## 5.94.0
+Mon, 20 Mar 2023 20:14:36 GMT
+
+### Updates
+
+- Update the `nodeSupportedVersionRange` in `rush.json` generated by `rush init` to remove Node 12 as it is no longer supported and include Node 18 as it is the current LTS version.
+- Extend LookupByPath to also be able to obtain the index of the remainder of the matched path.
+- Include some more hooks to allow plugins to monitor phased command execution in real-time.
+- Fix an issue where running `rush update-autoinstaller` without having run `rush install` or `rush update` first would cause a crash with an unhelpful error message.
+
+## 5.93.2
+Mon, 06 Mar 2023 20:18:01 GMT
+
+### Updates
+
+- Do not delete the local pnpm store after all install attempts has failed. `rush purge` will still delete a local store.
## 5.93.1
Fri, 17 Feb 2023 14:46:59 GMT
diff --git a/apps/rush/package.json b/apps/rush/package.json
index 0a155075a3f..7b4edc67692 100644
--- a/apps/rush/package.json
+++ b/apps/rush/package.json
@@ -1,6 +1,6 @@
{
"name": "@microsoft/rush",
- "version": "5.93.1",
+ "version": "5.96.0",
"description": "A professional solution for consolidating all your JavaScript projects in one Git repo",
"keywords": [
"install",
diff --git a/apps/trace-import/CHANGELOG.json b/apps/trace-import/CHANGELOG.json
index 4d0829db660..457bdd023fd 100644
--- a/apps/trace-import/CHANGELOG.json
+++ b/apps/trace-import/CHANGELOG.json
@@ -1,6 +1,21 @@
{
"name": "@rushstack/trace-import",
"entries": [
+ {
+ "version": "0.1.12",
+ "tag": "@rushstack/trace-import_v0.1.12",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
{
"version": "0.1.11",
"tag": "@rushstack/trace-import_v0.1.11",
diff --git a/apps/trace-import/CHANGELOG.md b/apps/trace-import/CHANGELOG.md
index a1f5e093ef7..2da252e03ef 100644
--- a/apps/trace-import/CHANGELOG.md
+++ b/apps/trace-import/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/trace-import
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.1.12
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 0.1.11
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/apps/trace-import/package.json b/apps/trace-import/package.json
index 8923e230865..86dd74203c7 100644
--- a/apps/trace-import/package.json
+++ b/apps/trace-import/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/trace-import",
- "version": "0.1.11",
+ "version": "0.1.12",
"description": "CLI tool for understanding how require() and \"import\" statements get resolved",
"repository": {
"type": "git",
diff --git a/common/config/rush/experiments.json b/common/config/rush/experiments.json
index 0182df63eb9..fef826208c3 100644
--- a/common/config/rush/experiments.json
+++ b/common/config/rush/experiments.json
@@ -46,5 +46,10 @@
* If true, perform a clean install after when running `rush install` or `rush update` if the
* `.npmrc` file has changed since the last install.
*/
- // "cleanInstallAfterNpmrcChanges": true
+ // "cleanInstallAfterNpmrcChanges": true,
+
+ /**
+ * If true, print the outputs of shell commands defined in event hooks to the console.
+ */
+ // "printEventHooksOutputToConsole": true
}
diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml
index 38a8e3b685c..917706492a5 100644
--- a/common/config/rush/pnpm-lock.yaml
+++ b/common/config/rush/pnpm-lock.yaml
@@ -2605,6 +2605,29 @@ importers:
'@types/node': 14.18.36
webpack: 5.75.0
+ ../../webpack/webpack-embedded-dependencies-plugin:
+ specifiers:
+ '@rushstack/eslint-config': workspace:*
+ '@rushstack/heft': workspace:*
+ '@rushstack/heft-node-rig': workspace:*
+ '@rushstack/node-core-library': workspace:*
+ '@rushstack/webpack-plugin-utilities': workspace:*
+ '@types/heft-jest': 1.0.1
+ '@types/node': 14.18.36
+ memfs: 3.4.3
+ webpack: ~5.75.0
+ dependencies:
+ '@rushstack/node-core-library': link:../../libraries/node-core-library
+ devDependencies:
+ '@rushstack/eslint-config': link:../../eslint/eslint-config
+ '@rushstack/heft': link:../../apps/heft
+ '@rushstack/heft-node-rig': link:../../rigs/heft-node-rig
+ '@rushstack/webpack-plugin-utilities': link:../webpack-plugin-utilities
+ '@types/heft-jest': 1.0.1
+ '@types/node': 14.18.36
+ memfs: 3.4.3
+ webpack: 5.75.0
+
../../webpack/webpack-plugin-utilities:
specifiers:
'@rushstack/eslint-config': workspace:*
@@ -2613,7 +2636,12 @@ importers:
'@types/heft-jest': 1.0.1
'@types/node': 14.18.36
'@types/tapable': 1.0.6
+ memfs: 3.4.3
webpack: ~5.75.0
+ webpack-merge: ~5.8.0
+ dependencies:
+ memfs: 3.4.3
+ webpack-merge: 5.8.0
devDependencies:
'@rushstack/eslint-config': link:../../eslint/eslint-config
'@rushstack/heft': link:../../apps/heft
diff --git a/common/config/rush/version-policies.json b/common/config/rush/version-policies.json
index 2aecd6e6077..a03639f590a 100644
--- a/common/config/rush/version-policies.json
+++ b/common/config/rush/version-policies.json
@@ -102,8 +102,8 @@
{
"policyName": "rush",
"definitionName": "lockStepVersion",
- "version": "5.93.1",
- "nextBump": "patch",
+ "version": "5.96.0",
+ "nextBump": "minor",
"mainProject": "@microsoft/rush"
}
]
diff --git a/common/reviews/api/rush-lib.api.md b/common/reviews/api/rush-lib.api.md
index 206bc26cc51..cbf4bb27366 100644
--- a/common/reviews/api/rush-lib.api.md
+++ b/common/reviews/api/rush-lib.api.md
@@ -263,6 +263,7 @@ export interface ICreateOperationsContext {
readonly isIncrementalBuildAllowed: boolean;
readonly isInitial: boolean;
readonly isWatch: boolean;
+ readonly phaseOriginal: ReadonlySet;
readonly phaseSelection: ReadonlySet;
readonly projectChangeAnalyzer: ProjectChangeAnalyzer;
readonly projectSelection: ReadonlySet;
@@ -305,6 +306,7 @@ export interface IExperimentsJson {
noChmodFieldInTarHeaderNormalization?: boolean;
omitImportersFromPreventManualShrinkwrapChanges?: boolean;
phasedCommands?: boolean;
+ printEventHooksOutputToConsole?: boolean;
usePnpmFrozenLockfileForRushInstall?: boolean;
usePnpmPreferFrozenLockfileForRushUpdate?: boolean;
}
@@ -494,6 +496,14 @@ export interface _IPnpmOptionsJson extends IPackageManagerOptionsJsonBase {
useWorkspaces?: boolean;
}
+// @beta
+export interface IPrefixMatch {
+ // (undocumented)
+ index: number;
+ // (undocumented)
+ value: TItem;
+}
+
// @beta
export interface IRushCommand {
readonly actionName: string;
@@ -610,6 +620,7 @@ export class LookupByPath {
readonly delimiter: string;
findChildPath(childPath: string): TItem | undefined;
findChildPathFromSegments(childPathSegments: Iterable): TItem | undefined;
+ findLongestPrefixMatch(query: string): IPrefixMatch | undefined;
static iteratePathSegments(serializedPath: string, delimiter?: string): Iterable;
setItem(serializedPath: string, value: TItem): this;
setItemFromSegments(pathSegments: Iterable, value: TItem): this;
@@ -744,7 +755,9 @@ export abstract class PackageManagerOptionsConfigurationBase implements IPackage
// @alpha
export class PhasedCommandHooks {
readonly afterExecuteOperations: AsyncSeriesHook<[IExecutionResult, ICreateOperationsContext]>;
+ readonly beforeExecuteOperations: AsyncSeriesHook<[Map]>;
readonly createOperations: AsyncSeriesWaterfallHook<[Set, ICreateOperationsContext]>;
+ readonly onOperationStatusChanged: SyncHook<[IOperationExecutionResult]>;
readonly waitingForChanges: SyncHook;
}
diff --git a/common/reviews/api/webpack-embedded-dependencies-plugin.api.md b/common/reviews/api/webpack-embedded-dependencies-plugin.api.md
new file mode 100644
index 00000000000..1fa9db5337d
--- /dev/null
+++ b/common/reviews/api/webpack-embedded-dependencies-plugin.api.md
@@ -0,0 +1,46 @@
+## API Report File for "@rushstack/webpack-embedded-dependencies-plugin"
+
+> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
+
+```ts
+
+import type { Compiler } from 'webpack';
+import type { IPackageJson } from '@rushstack/node-core-library';
+import type { WebpackPluginInstance } from 'webpack';
+
+// @beta
+class EmbeddedDependenciesWebpackPlugin implements WebpackPluginInstance {
+ constructor(options?: IEmbeddedDependenciesWebpackPluginOptions);
+ apply(compiler: Compiler): void;
+}
+export default EmbeddedDependenciesWebpackPlugin;
+
+// @beta
+export interface IEmbeddedDependenciesWebpackPluginOptions {
+ generatedLicenseFilename?: LicenseFileName;
+ generateLicenseFile?: boolean;
+ generateLicenseFileFunction?: LicenseFileGeneratorFunction;
+ outputFileName?: string;
+ packageFilterPredicate?: (packageJson: IPackageData, filePath: string) => boolean;
+}
+
+// @beta
+export interface IPackageData extends IPackageJson {
+ author?: string | {
+ name?: string;
+ };
+ copyright: string | undefined;
+ licenses?: {
+ type: string;
+ url: string;
+ }[];
+ licenseSource?: string;
+}
+
+// @beta
+export type LicenseFileGeneratorFunction = (packages: IPackageData[]) => string;
+
+// @beta
+export type LicenseFileName = `${string}.${'html' | 'md' | 'txt'}`;
+
+```
diff --git a/common/reviews/api/webpack-plugin-utilities.api.md b/common/reviews/api/webpack-plugin-utilities.api.md
index cbf1cc93af3..3b2bf0ac56f 100644
--- a/common/reviews/api/webpack-plugin-utilities.api.md
+++ b/common/reviews/api/webpack-plugin-utilities.api.md
@@ -4,8 +4,15 @@
```ts
+import type { Configuration } from 'webpack';
+import { IFs } from 'memfs';
+import type { MultiStats } from 'webpack';
+import type { Stats } from 'webpack';
import type * as Webpack from 'webpack';
+// @public
+function getTestingWebpackCompilerAsync(entry: string, additionalConfig?: Configuration, memFs?: IFs): Promise<(Stats | MultiStats) | undefined>;
+
// @public
function isWebpack3OrEarlier(compiler: Webpack.Compiler): boolean;
@@ -15,6 +22,13 @@ function isWebpack4(compiler: Webpack.Compiler): boolean;
// @public
function isWebpack5(compiler: Webpack.Compiler): boolean;
+declare namespace Testing {
+ export {
+ getTestingWebpackCompilerAsync
+ }
+}
+export { Testing }
+
declare namespace VersionDetection {
export {
isWebpack3OrEarlier,
diff --git a/heft-plugins/heft-dev-cert-plugin/CHANGELOG.json b/heft-plugins/heft-dev-cert-plugin/CHANGELOG.json
index eb3c7db8f30..e18d2fac841 100644
--- a/heft-plugins/heft-dev-cert-plugin/CHANGELOG.json
+++ b/heft-plugins/heft-dev-cert-plugin/CHANGELOG.json
@@ -1,6 +1,51 @@
{
"name": "@rushstack/heft-dev-cert-plugin",
"entries": [
+ {
+ "version": "0.2.20",
+ "tag": "@rushstack/heft-dev-cert-plugin_v0.2.20",
+ "date": "Mon, 20 Mar 2023 20:14:20 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.19`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.2.19",
+ "tag": "@rushstack/heft-dev-cert-plugin_v0.2.19",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.18`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.2.18",
+ "tag": "@rushstack/heft-dev-cert-plugin_v0.2.18",
+ "date": "Fri, 03 Mar 2023 04:11:20 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.17`"
+ }
+ ]
+ }
+ },
{
"version": "0.2.17",
"tag": "@rushstack/heft-dev-cert-plugin_v0.2.17",
diff --git a/heft-plugins/heft-dev-cert-plugin/CHANGELOG.md b/heft-plugins/heft-dev-cert-plugin/CHANGELOG.md
index ab58dbfcd99..31f084f05a5 100644
--- a/heft-plugins/heft-dev-cert-plugin/CHANGELOG.md
+++ b/heft-plugins/heft-dev-cert-plugin/CHANGELOG.md
@@ -1,6 +1,21 @@
# Change Log - @rushstack/heft-dev-cert-plugin
-This log was last generated on Fri, 10 Feb 2023 01:18:50 GMT and should not be manually modified.
+This log was last generated on Mon, 20 Mar 2023 20:14:20 GMT and should not be manually modified.
+
+## 0.2.20
+Mon, 20 Mar 2023 20:14:20 GMT
+
+_Version update only_
+
+## 0.2.19
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
+
+## 0.2.18
+Fri, 03 Mar 2023 04:11:20 GMT
+
+_Version update only_
## 0.2.17
Fri, 10 Feb 2023 01:18:50 GMT
diff --git a/heft-plugins/heft-dev-cert-plugin/package.json b/heft-plugins/heft-dev-cert-plugin/package.json
index 08146549491..1431b5ab26f 100644
--- a/heft-plugins/heft-dev-cert-plugin/package.json
+++ b/heft-plugins/heft-dev-cert-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/heft-dev-cert-plugin",
- "version": "0.2.17",
+ "version": "0.2.20",
"description": "A Heft plugin for generating and using local development certificates",
"repository": {
"type": "git",
@@ -18,7 +18,7 @@
"_phase:test": "heft test --no-build"
},
"peerDependencies": {
- "@rushstack/heft": "^0.49.7"
+ "@rushstack/heft": "^0.50.0"
},
"dependencies": {
"@rushstack/debug-certificate-manager": "workspace:*",
diff --git a/heft-plugins/heft-jest-plugin/CHANGELOG.json b/heft-plugins/heft-jest-plugin/CHANGELOG.json
index d9905484c18..d1565b29ef8 100644
--- a/heft-plugins/heft-jest-plugin/CHANGELOG.json
+++ b/heft-plugins/heft-jest-plugin/CHANGELOG.json
@@ -1,6 +1,21 @@
{
"name": "@rushstack/heft-jest-plugin",
"entries": [
+ {
+ "version": "0.5.5",
+ "tag": "@rushstack/heft-jest-plugin_v0.5.5",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`"
+ }
+ ]
+ }
+ },
{
"version": "0.5.4",
"tag": "@rushstack/heft-jest-plugin_v0.5.4",
diff --git a/heft-plugins/heft-jest-plugin/CHANGELOG.md b/heft-plugins/heft-jest-plugin/CHANGELOG.md
index cbf33b09560..debf9c0542a 100644
--- a/heft-plugins/heft-jest-plugin/CHANGELOG.md
+++ b/heft-plugins/heft-jest-plugin/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/heft-jest-plugin
-This log was last generated on Fri, 10 Feb 2023 01:18:50 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.5.5
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 0.5.4
Fri, 10 Feb 2023 01:18:50 GMT
diff --git a/heft-plugins/heft-jest-plugin/package.json b/heft-plugins/heft-jest-plugin/package.json
index da8dd2216e8..ff207e28202 100644
--- a/heft-plugins/heft-jest-plugin/package.json
+++ b/heft-plugins/heft-jest-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/heft-jest-plugin",
- "version": "0.5.4",
+ "version": "0.5.5",
"description": "Heft plugin for Jest",
"repository": {
"type": "git",
@@ -18,7 +18,7 @@
"_phase:test": "heft test --no-build"
},
"peerDependencies": {
- "@rushstack/heft": "^0.49.7"
+ "@rushstack/heft": "^0.50.0"
},
"dependencies": {
"@jest/core": "~29.3.1",
diff --git a/heft-plugins/heft-sass-plugin/CHANGELOG.json b/heft-plugins/heft-sass-plugin/CHANGELOG.json
index e10c647bbad..038196f0743 100644
--- a/heft-plugins/heft-sass-plugin/CHANGELOG.json
+++ b/heft-plugins/heft-sass-plugin/CHANGELOG.json
@@ -1,6 +1,27 @@
{
"name": "@rushstack/heft-sass-plugin",
"entries": [
+ {
+ "version": "0.8.4",
+ "tag": "@rushstack/heft-sass-plugin_v0.8.4",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.3`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`"
+ }
+ ]
+ }
+ },
{
"version": "0.8.3",
"tag": "@rushstack/heft-sass-plugin_v0.8.3",
diff --git a/heft-plugins/heft-sass-plugin/CHANGELOG.md b/heft-plugins/heft-sass-plugin/CHANGELOG.md
index e79737d18db..603873737a7 100644
--- a/heft-plugins/heft-sass-plugin/CHANGELOG.md
+++ b/heft-plugins/heft-sass-plugin/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/heft-sass-plugin
-This log was last generated on Fri, 10 Feb 2023 01:18:50 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.8.4
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 0.8.3
Fri, 10 Feb 2023 01:18:50 GMT
diff --git a/heft-plugins/heft-sass-plugin/package.json b/heft-plugins/heft-sass-plugin/package.json
index dce8672edd4..1a3ed85557d 100644
--- a/heft-plugins/heft-sass-plugin/package.json
+++ b/heft-plugins/heft-sass-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/heft-sass-plugin",
- "version": "0.8.3",
+ "version": "0.8.4",
"description": "Heft plugin for SASS",
"repository": {
"type": "git",
@@ -18,7 +18,7 @@
"_phase:test": "heft test --no-build"
},
"peerDependencies": {
- "@rushstack/heft": "^0.49.7"
+ "@rushstack/heft": "^0.50.0"
},
"dependencies": {
"@rushstack/heft-config-file": "workspace:*",
diff --git a/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.json b/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.json
index a7d6c1d81d4..f4702bec789 100644
--- a/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.json
+++ b/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.json
@@ -1,6 +1,24 @@
{
"name": "@rushstack/heft-serverless-stack-plugin",
"entries": [
+ {
+ "version": "0.1.69",
+ "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.69",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`"
+ }
+ ]
+ }
+ },
{
"version": "0.1.68",
"tag": "@rushstack/heft-serverless-stack-plugin_v0.1.68",
diff --git a/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.md b/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.md
index 9aa52305d64..771d8e97e7c 100644
--- a/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.md
+++ b/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/heft-serverless-stack-plugin
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.1.69
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 0.1.68
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/heft-plugins/heft-serverless-stack-plugin/package.json b/heft-plugins/heft-serverless-stack-plugin/package.json
index 29ad889697d..064ab94effe 100644
--- a/heft-plugins/heft-serverless-stack-plugin/package.json
+++ b/heft-plugins/heft-serverless-stack-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/heft-serverless-stack-plugin",
- "version": "0.1.68",
+ "version": "0.1.69",
"description": "Heft plugin for building apps using the Serverless Stack (SST) framework",
"repository": {
"type": "git",
@@ -17,7 +17,7 @@
"_phase:test": "heft test --no-build"
},
"peerDependencies": {
- "@rushstack/heft": "^0.49.7"
+ "@rushstack/heft": "^0.50.0"
},
"dependencies": {
"@rushstack/node-core-library": "workspace:*"
diff --git a/heft-plugins/heft-storybook-plugin/CHANGELOG.json b/heft-plugins/heft-storybook-plugin/CHANGELOG.json
index 3490b1c3445..a63222a7ad3 100644
--- a/heft-plugins/heft-storybook-plugin/CHANGELOG.json
+++ b/heft-plugins/heft-storybook-plugin/CHANGELOG.json
@@ -1,6 +1,24 @@
{
"name": "@rushstack/heft-storybook-plugin",
"entries": [
+ {
+ "version": "0.2.4",
+ "tag": "@rushstack/heft-storybook-plugin_v0.2.4",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`"
+ }
+ ]
+ }
+ },
{
"version": "0.2.3",
"tag": "@rushstack/heft-storybook-plugin_v0.2.3",
diff --git a/heft-plugins/heft-storybook-plugin/CHANGELOG.md b/heft-plugins/heft-storybook-plugin/CHANGELOG.md
index 71d0a1b06a3..de2e055ce76 100644
--- a/heft-plugins/heft-storybook-plugin/CHANGELOG.md
+++ b/heft-plugins/heft-storybook-plugin/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/heft-storybook-plugin
-This log was last generated on Wed, 22 Feb 2023 16:26:55 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.2.4
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 0.2.3
Wed, 22 Feb 2023 16:26:55 GMT
diff --git a/heft-plugins/heft-storybook-plugin/package.json b/heft-plugins/heft-storybook-plugin/package.json
index efe111ecfa4..fe59406f3c8 100644
--- a/heft-plugins/heft-storybook-plugin/package.json
+++ b/heft-plugins/heft-storybook-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/heft-storybook-plugin",
- "version": "0.2.3",
+ "version": "0.2.4",
"description": "Heft plugin for supporting UI development using Storybook",
"repository": {
"type": "git",
@@ -18,7 +18,7 @@
"_phase:test": "heft test --no-build"
},
"peerDependencies": {
- "@rushstack/heft": "^0.49.7"
+ "@rushstack/heft": "^0.50.0"
},
"dependencies": {
"@rushstack/node-core-library": "workspace:*"
diff --git a/heft-plugins/heft-webpack4-plugin/CHANGELOG.json b/heft-plugins/heft-webpack4-plugin/CHANGELOG.json
index 8f1a0e99c00..3a225f70358 100644
--- a/heft-plugins/heft-webpack4-plugin/CHANGELOG.json
+++ b/heft-plugins/heft-webpack4-plugin/CHANGELOG.json
@@ -1,6 +1,24 @@
{
"name": "@rushstack/heft-webpack4-plugin",
"entries": [
+ {
+ "version": "0.5.40",
+ "tag": "@rushstack/heft-webpack4-plugin_v0.5.40",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`"
+ }
+ ]
+ }
+ },
{
"version": "0.5.39",
"tag": "@rushstack/heft-webpack4-plugin_v0.5.39",
diff --git a/heft-plugins/heft-webpack4-plugin/CHANGELOG.md b/heft-plugins/heft-webpack4-plugin/CHANGELOG.md
index 5371b17438d..8929c037c4d 100644
--- a/heft-plugins/heft-webpack4-plugin/CHANGELOG.md
+++ b/heft-plugins/heft-webpack4-plugin/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/heft-webpack4-plugin
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.5.40
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 0.5.39
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/heft-plugins/heft-webpack4-plugin/package.json b/heft-plugins/heft-webpack4-plugin/package.json
index f50afe20372..6c783f34679 100644
--- a/heft-plugins/heft-webpack4-plugin/package.json
+++ b/heft-plugins/heft-webpack4-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/heft-webpack4-plugin",
- "version": "0.5.39",
+ "version": "0.5.40",
"description": "Heft plugin for Webpack 4",
"repository": {
"type": "git",
@@ -23,7 +23,7 @@
}
},
"peerDependencies": {
- "@rushstack/heft": "^0.49.7",
+ "@rushstack/heft": "^0.50.0",
"@types/webpack": "^4",
"webpack": "~4.44.2"
},
diff --git a/heft-plugins/heft-webpack5-plugin/CHANGELOG.json b/heft-plugins/heft-webpack5-plugin/CHANGELOG.json
index f9939b6422d..0d6c31b2095 100644
--- a/heft-plugins/heft-webpack5-plugin/CHANGELOG.json
+++ b/heft-plugins/heft-webpack5-plugin/CHANGELOG.json
@@ -1,6 +1,36 @@
{
"name": "@rushstack/heft-webpack5-plugin",
"entries": [
+ {
+ "version": "0.6.1",
+ "tag": "@rushstack/heft-webpack5-plugin_v0.6.1",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.6.0",
+ "tag": "@rushstack/heft-webpack5-plugin_v0.6.0",
+ "date": "Sat, 11 Mar 2023 01:24:51 GMT",
+ "comments": {
+ "minor": [
+ {
+ "comment": "Add support for `.cjs` and `.mjs` file extensions for webpack config files, in addition to the `.js` file extension."
+ }
+ ]
+ }
+ },
{
"version": "0.5.73",
"tag": "@rushstack/heft-webpack5-plugin_v0.5.73",
diff --git a/heft-plugins/heft-webpack5-plugin/CHANGELOG.md b/heft-plugins/heft-webpack5-plugin/CHANGELOG.md
index 1988ed3feec..da2cf4b3988 100644
--- a/heft-plugins/heft-webpack5-plugin/CHANGELOG.md
+++ b/heft-plugins/heft-webpack5-plugin/CHANGELOG.md
@@ -1,6 +1,18 @@
# Change Log - @rushstack/heft-webpack5-plugin
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.6.1
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
+
+## 0.6.0
+Sat, 11 Mar 2023 01:24:51 GMT
+
+### Minor changes
+
+- Add support for `.cjs` and `.mjs` file extensions for webpack config files, in addition to the `.js` file extension.
## 0.5.73
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/heft-plugins/heft-webpack5-plugin/package.json b/heft-plugins/heft-webpack5-plugin/package.json
index de83c73d514..0430ef0ff51 100644
--- a/heft-plugins/heft-webpack5-plugin/package.json
+++ b/heft-plugins/heft-webpack5-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/heft-webpack5-plugin",
- "version": "0.5.73",
+ "version": "0.6.1",
"description": "Heft plugin for Webpack 5",
"repository": {
"type": "git",
@@ -18,7 +18,7 @@
"_phase:test": "heft test --no-build"
},
"peerDependencies": {
- "@rushstack/heft": "^0.49.7",
+ "@rushstack/heft": "^0.50.0",
"webpack": "~5.75.0"
},
"dependencies": {
diff --git a/heft-plugins/heft-webpack5-plugin/src/WebpackConfigurationLoader.ts b/heft-plugins/heft-webpack5-plugin/src/WebpackConfigurationLoader.ts
index 0c9d3ffd027..80b9fe27470 100644
--- a/heft-plugins/heft-webpack5-plugin/src/WebpackConfigurationLoader.ts
+++ b/heft-plugins/heft-webpack5-plugin/src/WebpackConfigurationLoader.ts
@@ -2,7 +2,7 @@
// See LICENSE in the project root for license information.
import * as path from 'path';
-import { FileSystem } from '@rushstack/node-core-library';
+import { type FolderItem, FileSystem } from '@rushstack/node-core-library';
import type * as webpack from 'webpack';
import type { IBuildStageProperties, ScopedLogger } from '@rushstack/heft';
@@ -24,8 +24,10 @@ type IWebpackConfigJsExport =
| ((env: IWebpackConfigFunctionEnv) => Promise);
type IWebpackConfigJs = IWebpackConfigJsExport | { default: IWebpackConfigJsExport };
-const WEBPACK_CONFIG_FILENAME: string = 'webpack.config.js';
-const WEBPACK_DEV_CONFIG_FILENAME: string = 'webpack.dev.config.js';
+interface IWebpackConfigFileNames {
+ dev: string | undefined;
+ prod: string | undefined;
+}
export class WebpackConfigurationLoader {
public static async tryLoadWebpackConfigAsync(
@@ -36,26 +38,30 @@ export class WebpackConfigurationLoader {
// TODO: Eventually replace this custom logic with a call to this utility in in webpack-cli:
// https://github.com/webpack/webpack-cli/blob/next/packages/webpack-cli/lib/groups/ConfigGroup.js
+ const webpackConfigFiles: IWebpackConfigFileNames | undefined = await findWebpackConfigAsync(buildFolder);
+ const webpackDevConfigFilename: string | undefined = webpackConfigFiles.dev;
+ const webpackConfigFilename: string | undefined = webpackConfigFiles.prod;
+
let webpackConfigJs: IWebpackConfigJs | undefined;
try {
- if (buildProperties.serveMode) {
+ if (buildProperties.serveMode && webpackDevConfigFilename) {
logger.terminal.writeVerboseLine(
- `Attempting to load webpack configuration from "${WEBPACK_DEV_CONFIG_FILENAME}".`
+ `Attempting to load webpack configuration from "${webpackDevConfigFilename}".`
);
webpackConfigJs = WebpackConfigurationLoader._tryLoadWebpackConfiguration(
buildFolder,
- WEBPACK_DEV_CONFIG_FILENAME
+ webpackDevConfigFilename
);
}
- if (!webpackConfigJs) {
+ if (!webpackConfigJs && webpackConfigFilename) {
logger.terminal.writeVerboseLine(
- `Attempting to load webpack configuration from "${WEBPACK_CONFIG_FILENAME}".`
+ `Attempting to load webpack configuration from "${webpackConfigFilename}".`
);
webpackConfigJs = WebpackConfigurationLoader._tryLoadWebpackConfiguration(
buildFolder,
- WEBPACK_CONFIG_FILENAME
+ webpackConfigFilename
);
}
} catch (error) {
@@ -92,3 +98,34 @@ export class WebpackConfigurationLoader {
}
}
}
+
+async function findWebpackConfigAsync(buildFolder: string): Promise {
+ try {
+ const folderItems: FolderItem[] = await FileSystem.readFolderItemsAsync(buildFolder);
+ const dev: string[] = [];
+ const prod: string[] = [];
+
+ for (const folderItem of folderItems) {
+ if (folderItem.isFile()) {
+ if (folderItem.name.match(/^webpack.dev.config\.(cjs|js|mjs)$/)) {
+ dev.push(folderItem.name);
+ } else if (folderItem.name.match(/^webpack.config\.(cjs|js|mjs)$/)) {
+ prod.push(folderItem.name);
+ }
+ }
+ }
+
+ if (dev.length > 1) {
+ throw new Error(`Error: Found more than one dev webpack configuration file.`);
+ } else if (prod.length > 1) {
+ throw new Error(`Error: Found more than one non-dev webpack configuration file.`);
+ }
+
+ return {
+ dev: dev[0],
+ prod: prod[0]
+ };
+ } catch (e) {
+ throw new Error(`Error finding webpack configuration: ${e}`);
+ }
+}
diff --git a/libraries/debug-certificate-manager/CHANGELOG.json b/libraries/debug-certificate-manager/CHANGELOG.json
index 890faa55426..cdd41917cb1 100644
--- a/libraries/debug-certificate-manager/CHANGELOG.json
+++ b/libraries/debug-certificate-manager/CHANGELOG.json
@@ -1,6 +1,45 @@
{
"name": "@rushstack/debug-certificate-manager",
"entries": [
+ {
+ "version": "1.2.19",
+ "tag": "@rushstack/debug-certificate-manager_v1.2.19",
+ "date": "Mon, 20 Mar 2023 20:14:20 GMT",
+ "comments": {
+ "patch": [
+ {
+ "comment": "Force certificates with a validity period longer than the expected validity period to be refreshed."
+ }
+ ]
+ }
+ },
+ {
+ "version": "1.2.18",
+ "tag": "@rushstack/debug-certificate-manager_v1.2.18",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "1.2.17",
+ "tag": "@rushstack/debug-certificate-manager_v1.2.17",
+ "date": "Fri, 03 Mar 2023 04:11:20 GMT",
+ "comments": {
+ "patch": [
+ {
+ "comment": "Fix an issue where certificate expiration was calculated incorrectly and certificates were set to expire too late."
+ }
+ ]
+ }
+ },
{
"version": "1.2.16",
"tag": "@rushstack/debug-certificate-manager_v1.2.16",
diff --git a/libraries/debug-certificate-manager/CHANGELOG.md b/libraries/debug-certificate-manager/CHANGELOG.md
index b4537cda20c..355714dd147 100644
--- a/libraries/debug-certificate-manager/CHANGELOG.md
+++ b/libraries/debug-certificate-manager/CHANGELOG.md
@@ -1,6 +1,25 @@
# Change Log - @rushstack/debug-certificate-manager
-This log was last generated on Fri, 10 Feb 2023 01:18:50 GMT and should not be manually modified.
+This log was last generated on Mon, 20 Mar 2023 20:14:20 GMT and should not be manually modified.
+
+## 1.2.19
+Mon, 20 Mar 2023 20:14:20 GMT
+
+### Patches
+
+- Force certificates with a validity period longer than the expected validity period to be refreshed.
+
+## 1.2.18
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
+
+## 1.2.17
+Fri, 03 Mar 2023 04:11:20 GMT
+
+### Patches
+
+- Fix an issue where certificate expiration was calculated incorrectly and certificates were set to expire too late.
## 1.2.16
Fri, 10 Feb 2023 01:18:50 GMT
diff --git a/libraries/debug-certificate-manager/package.json b/libraries/debug-certificate-manager/package.json
index f840473b9dc..c8a265cf339 100644
--- a/libraries/debug-certificate-manager/package.json
+++ b/libraries/debug-certificate-manager/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/debug-certificate-manager",
- "version": "1.2.16",
+ "version": "1.2.19",
"description": "Cross-platform functionality to create debug ssl certificates.",
"main": "lib/index.js",
"typings": "dist/debug-certificate-manager.d.ts",
diff --git a/libraries/debug-certificate-manager/src/CertificateManager.ts b/libraries/debug-certificate-manager/src/CertificateManager.ts
index 6838c2019ac..aa92262143a 100644
--- a/libraries/debug-certificate-manager/src/CertificateManager.ts
+++ b/libraries/debug-certificate-manager/src/CertificateManager.ts
@@ -15,6 +15,7 @@ const FRIENDLY_NAME: string = 'debug-certificate-manager Development Certificate
const MAC_KEYCHAIN: string = '/Library/Keychains/System.keychain';
const CERTUTIL_EXE_NAME: string = 'certutil';
const CA_ALT_NAME: string = 'rushstack-certificate-manager.localhost';
+const ONE_DAY_IN_MILLISECONDS: number = 24 * 60 * 60 * 1000;
/**
* The set of names the certificate should be generated for, by default.
@@ -85,6 +86,8 @@ export interface ICertificateGenerationOptions {
validityInDays?: number;
}
+const MAX_CERTIFICATE_VALIDITY_DAYS: 365 = 365;
+
/**
* A utility class to handle generating, trusting, and untrustring a debug certificate.
* Contains two public methods to `ensureCertificate` and `untrustCertificate`.
@@ -142,6 +145,24 @@ export class CertificateManager {
);
}
+ now.setUTCDate(now.getUTCDate() + optionsWithDefaults.validityInDays);
+ if (notAfter > now) {
+ messages.push(
+ `The existing development certificate's expiration date ${notAfter} exceeds the allowed limit ${now}. ` +
+ `This will be rejected by many browsers.`
+ );
+ }
+
+ if (
+ notBefore.getTime() - notAfter.getTime() >
+ optionsWithDefaults.validityInDays * ONE_DAY_IN_MILLISECONDS
+ ) {
+ messages.push(
+ "The existing development certificate's validity period is longer " +
+ `than ${optionsWithDefaults.validityInDays} days.`
+ );
+ }
+
const { caCertificateData } = this._certificateStore;
if (!caCertificateData) {
@@ -279,9 +300,11 @@ export class CertificateManager {
certificate.serialNumber = CA_SERIAL_NUMBER;
- const now: Date = new Date();
- certificate.validity.notBefore = now;
- certificate.validity.notAfter.setUTCDate(certificate.validity.notBefore.getUTCDate() + validityInDays);
+ const notBefore: Date = new Date();
+ const notAfter: Date = new Date(notBefore);
+ notAfter.setUTCDate(notBefore.getUTCDate() + validityInDays);
+ certificate.validity.notBefore = notBefore;
+ certificate.validity.notAfter = notAfter;
const attrs: pki.CertificateField[] = [
{
@@ -359,9 +382,11 @@ export class CertificateManager {
forge
);
- const now: Date = new Date();
- certificate.validity.notBefore = now;
- certificate.validity.notAfter.setUTCDate(certificate.validity.notBefore.getUTCDate() + validityInDays);
+ const notBefore: Date = new Date();
+ const notAfter: Date = new Date(notBefore);
+ notAfter.setUTCDate(notBefore.getUTCDate() + validityInDays);
+ certificate.validity.notBefore = notBefore;
+ certificate.validity.notAfter = notAfter;
const subjectAttrs: pki.CertificateField[] = [
{
@@ -709,6 +734,9 @@ function applyDefaultOptions(
const subjectNames: ReadonlyArray | undefined = options?.subjectAltNames;
return {
subjectAltNames: subjectNames?.length ? subjectNames : DEFAULT_CERTIFICATE_SUBJECT_NAMES,
- validityInDays: options?.validityInDays ?? 365
+ validityInDays: Math.min(
+ MAX_CERTIFICATE_VALIDITY_DAYS,
+ options?.validityInDays ?? MAX_CERTIFICATE_VALIDITY_DAYS
+ )
};
}
diff --git a/libraries/load-themed-styles/CHANGELOG.json b/libraries/load-themed-styles/CHANGELOG.json
index 6b9b28c8b64..1cc51f8cdfb 100644
--- a/libraries/load-themed-styles/CHANGELOG.json
+++ b/libraries/load-themed-styles/CHANGELOG.json
@@ -1,6 +1,33 @@
{
"name": "@microsoft/load-themed-styles",
"entries": [
+ {
+ "version": "2.0.31",
+ "tag": "@microsoft/load-themed-styles_v2.0.31",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.7`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "2.0.30",
+ "tag": "@microsoft/load-themed-styles_v2.0.30",
+ "date": "Sat, 11 Mar 2023 01:24:51 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.6`"
+ }
+ ]
+ }
+ },
{
"version": "2.0.29",
"tag": "@microsoft/load-themed-styles_v2.0.29",
diff --git a/libraries/load-themed-styles/CHANGELOG.md b/libraries/load-themed-styles/CHANGELOG.md
index d4ca84dca9d..0a7ddc5e899 100644
--- a/libraries/load-themed-styles/CHANGELOG.md
+++ b/libraries/load-themed-styles/CHANGELOG.md
@@ -1,6 +1,16 @@
# Change Log - @microsoft/load-themed-styles
-This log was last generated on Fri, 10 Feb 2023 01:18:50 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 2.0.31
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
+
+## 2.0.30
+Sat, 11 Mar 2023 01:24:51 GMT
+
+_Version update only_
## 2.0.29
Fri, 10 Feb 2023 01:18:50 GMT
diff --git a/libraries/load-themed-styles/package.json b/libraries/load-themed-styles/package.json
index ecee5bdd3c8..4f873751c59 100644
--- a/libraries/load-themed-styles/package.json
+++ b/libraries/load-themed-styles/package.json
@@ -1,6 +1,6 @@
{
"name": "@microsoft/load-themed-styles",
- "version": "2.0.29",
+ "version": "2.0.31",
"description": "Loads themed styles.",
"license": "MIT",
"repository": {
diff --git a/libraries/localization-utilities/CHANGELOG.json b/libraries/localization-utilities/CHANGELOG.json
index 44f2109f232..1915a617959 100644
--- a/libraries/localization-utilities/CHANGELOG.json
+++ b/libraries/localization-utilities/CHANGELOG.json
@@ -1,6 +1,24 @@
{
"name": "@rushstack/localization-utilities",
"entries": [
+ {
+ "version": "0.8.47",
+ "tag": "@rushstack/localization-utilities_v0.8.47",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.3`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
{
"version": "0.8.46",
"tag": "@rushstack/localization-utilities_v0.8.46",
diff --git a/libraries/localization-utilities/CHANGELOG.md b/libraries/localization-utilities/CHANGELOG.md
index 585018c2c93..56ca9b67e0f 100644
--- a/libraries/localization-utilities/CHANGELOG.md
+++ b/libraries/localization-utilities/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/localization-utilities
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.8.47
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 0.8.46
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/libraries/localization-utilities/package.json b/libraries/localization-utilities/package.json
index b63e41d0dab..acac9b7cee7 100644
--- a/libraries/localization-utilities/package.json
+++ b/libraries/localization-utilities/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/localization-utilities",
- "version": "0.8.46",
+ "version": "0.8.47",
"description": "This plugin contains some useful functions for localization.",
"main": "lib/index.js",
"typings": "dist/localization-utilities.d.ts",
diff --git a/libraries/module-minifier/CHANGELOG.json b/libraries/module-minifier/CHANGELOG.json
index 56a02b8eaa6..3d03bb415e9 100644
--- a/libraries/module-minifier/CHANGELOG.json
+++ b/libraries/module-minifier/CHANGELOG.json
@@ -1,6 +1,24 @@
{
"name": "@rushstack/module-minifier",
"entries": [
+ {
+ "version": "0.3.3",
+ "tag": "@rushstack/module-minifier_v0.3.3",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.3`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
{
"version": "0.3.2",
"tag": "@rushstack/module-minifier_v0.3.2",
diff --git a/libraries/module-minifier/CHANGELOG.md b/libraries/module-minifier/CHANGELOG.md
index 2cfd27c76e5..7433d1b0416 100644
--- a/libraries/module-minifier/CHANGELOG.md
+++ b/libraries/module-minifier/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/module-minifier
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.3.3
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 0.3.2
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/libraries/module-minifier/package.json b/libraries/module-minifier/package.json
index 19480825262..8c9d3317c91 100644
--- a/libraries/module-minifier/package.json
+++ b/libraries/module-minifier/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/module-minifier",
- "version": "0.3.2",
+ "version": "0.3.3",
"description": "Wrapper for terser to support bulk parallel minification.",
"main": "lib/index.js",
"typings": "dist/module-minifier.d.ts",
diff --git a/libraries/package-deps-hash/CHANGELOG.json b/libraries/package-deps-hash/CHANGELOG.json
index 3570e3c1f96..e23a8fa08dd 100644
--- a/libraries/package-deps-hash/CHANGELOG.json
+++ b/libraries/package-deps-hash/CHANGELOG.json
@@ -1,6 +1,21 @@
{
"name": "@rushstack/package-deps-hash",
"entries": [
+ {
+ "version": "4.0.10",
+ "tag": "@rushstack/package-deps-hash_v4.0.10",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
{
"version": "4.0.9",
"tag": "@rushstack/package-deps-hash_v4.0.9",
diff --git a/libraries/package-deps-hash/CHANGELOG.md b/libraries/package-deps-hash/CHANGELOG.md
index dbae2d23b99..06cb9f0ba50 100644
--- a/libraries/package-deps-hash/CHANGELOG.md
+++ b/libraries/package-deps-hash/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/package-deps-hash
-This log was last generated on Fri, 24 Feb 2023 01:24:17 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 4.0.10
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 4.0.9
Fri, 24 Feb 2023 01:24:17 GMT
diff --git a/libraries/package-deps-hash/package.json b/libraries/package-deps-hash/package.json
index 39fe69194b8..ed7fce576e1 100644
--- a/libraries/package-deps-hash/package.json
+++ b/libraries/package-deps-hash/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/package-deps-hash",
- "version": "4.0.9",
+ "version": "4.0.10",
"description": "",
"main": "lib/index.js",
"typings": "dist/package-deps-hash.d.ts",
diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/experiments.json b/libraries/rush-lib/assets/rush-init/common/config/rush/experiments.json
index 29539c4876b..151718a75fd 100644
--- a/libraries/rush-lib/assets/rush-init/common/config/rush/experiments.json
+++ b/libraries/rush-lib/assets/rush-init/common/config/rush/experiments.json
@@ -46,5 +46,10 @@
* If true, perform a clean install after when running `rush install` or `rush update` if the
* `.npmrc` file has changed since the last install.
*/
- /*[LINE "HYPOTHETICAL"]*/ "cleanInstallAfterNpmrcChanges": true
+ /*[LINE "HYPOTHETICAL"]*/ "cleanInstallAfterNpmrcChanges": true,
+
+ /**
+ * If true, print the outputs of shell commands defined in event hooks to the console.
+ */
+ /*[LINE "HYPOTHETICAL"]*/ "printEventHooksOutputToConsole": true
}
diff --git a/libraries/rush-lib/assets/rush-init/rush.json b/libraries/rush-lib/assets/rush-init/rush.json
index 9842c4bd120..12012e5c9f5 100644
--- a/libraries/rush-lib/assets/rush-init/rush.json
+++ b/libraries/rush-lib/assets/rush-init/rush.json
@@ -42,7 +42,7 @@
* LTS schedule: https://nodejs.org/en/about/releases/
* LTS versions: https://nodejs.org/en/download/releases/
*/
- "nodeSupportedVersionRange": ">=12.13.0 <13.0.0 || >=14.15.0 <15.0.0 || >=16.13.0 <17.0.0",
+ "nodeSupportedVersionRange": ">=14.15.0 <15.0.0 || >=16.13.0 <17.0.0 || >=18.15.0 <19.0.0",
/**
* If the version check above fails, Rush will display a message showing the current
diff --git a/libraries/rush-lib/package.json b/libraries/rush-lib/package.json
index 9448989d1eb..b0982dd302d 100644
--- a/libraries/rush-lib/package.json
+++ b/libraries/rush-lib/package.json
@@ -1,6 +1,6 @@
{
"name": "@microsoft/rush-lib",
- "version": "5.93.1",
+ "version": "5.96.0",
"description": "A library for writing scripts that interact with the Rush tool",
"repository": {
"type": "git",
diff --git a/libraries/rush-lib/src/api/CommandLineConfiguration.ts b/libraries/rush-lib/src/api/CommandLineConfiguration.ts
index 462ffc8f180..b8366ba0da6 100644
--- a/libraries/rush-lib/src/api/CommandLineConfiguration.ts
+++ b/libraries/rush-lib/src/api/CommandLineConfiguration.ts
@@ -96,6 +96,10 @@ export interface IPhasedCommandConfig extends IPhasedCommandWithoutPhasesJson, I
isSynthetic: boolean;
disableBuildCache?: boolean;
+ originalPhases: Set;
+ /**
+ * Include upstream and self phases.
+ */
phases: Set;
/**
@@ -297,6 +301,7 @@ export class CommandLineConfiguration {
const commandsJson: ICommandLineJson['commands'] = commandLineJson?.commands;
let buildCommandPhases: IPhasedCommandConfig['phases'] | undefined;
+ let buildCommandOriginalPhases: IPhasedCommandConfig['phases'] | undefined;
if (commandsJson) {
for (const command of commandsJson) {
if (this.commands.has(command.name)) {
@@ -309,6 +314,7 @@ export class CommandLineConfiguration {
let normalizedCommand: Command;
switch (command.commandKind) {
case RushConstants.phasedCommandKind: {
+ const originalPhases: Set = new Set();
const commandPhases: Set = new Set();
const watchPhases: Set = new Set();
@@ -316,6 +322,7 @@ export class CommandLineConfiguration {
...command,
isSynthetic: false,
associatedParameters: new Set(),
+ originalPhases,
phases: commandPhases,
watchPhases,
alwaysWatch: false,
@@ -331,6 +338,7 @@ export class CommandLineConfiguration {
);
}
+ originalPhases.add(phase);
commandPhases.add(phase);
}
@@ -407,6 +415,7 @@ export class CommandLineConfiguration {
} else if (normalizedCommand.name === RushConstants.buildCommandName) {
// Record the build command phases in case we need to construct a synthetic "rebuild" command
buildCommandPhases = normalizedCommand.phases;
+ buildCommandOriginalPhases = normalizedCommand.originalPhases;
}
}
@@ -421,12 +430,13 @@ export class CommandLineConfiguration {
buildCommand = this._translateBulkCommandToPhasedCommand(DEFAULT_BUILD_COMMAND_JSON);
buildCommand.disableBuildCache = DEFAULT_BUILD_COMMAND_JSON.disableBuildCache;
buildCommandPhases = buildCommand.phases;
+ buildCommandOriginalPhases = buildCommand.originalPhases;
this.commands.set(buildCommand.name, buildCommand);
}
if (!this.commands.has(RushConstants.rebuildCommandName)) {
// If a rebuild command was not specified in the config file, add the default rebuild command
- if (!buildCommandPhases) {
+ if (!buildCommandPhases || !buildCommandOriginalPhases) {
throw new Error(`Phases for the "${RushConstants.buildCommandName}" were not found.`);
}
@@ -437,6 +447,7 @@ export class CommandLineConfiguration {
phases: buildCommandPhases,
disableBuildCache: DEFAULT_REBUILD_COMMAND_JSON.disableBuildCache,
associatedParameters: buildCommand.associatedParameters, // rebuild should share build's parameters in this case,
+ originalPhases: buildCommandOriginalPhases,
watchPhases: new Set(),
alwaysWatch: false,
alwaysInstall: undefined
@@ -689,6 +700,7 @@ export class CommandLineConfiguration {
isSynthetic: true,
associatedParameters: new Set(),
phases,
+ originalPhases: phases,
// Bulk commands used the same phases for watch as for regular execution. Preserve behavior.
watchPhases: command.watchForChanges ? phases : new Set(),
alwaysWatch: !!command.watchForChanges,
diff --git a/libraries/rush-lib/src/api/ExperimentsConfiguration.ts b/libraries/rush-lib/src/api/ExperimentsConfiguration.ts
index 17fddb8d731..b428d50d1f3 100644
--- a/libraries/rush-lib/src/api/ExperimentsConfiguration.ts
+++ b/libraries/rush-lib/src/api/ExperimentsConfiguration.ts
@@ -53,6 +53,11 @@ export interface IExperimentsJson {
* `.npmrc` file has changed since the last install.
*/
cleanInstallAfterNpmrcChanges?: boolean;
+
+ /**
+ * If true, print the outputs of shell commands defined in event hooks to the console.
+ */
+ printEventHooksOutputToConsole?: boolean;
}
/**
diff --git a/libraries/rush-lib/src/cli/RushCommandLineParser.ts b/libraries/rush-lib/src/cli/RushCommandLineParser.ts
index 2f027d1f09e..3f483e054f1 100644
--- a/libraries/rush-lib/src/cli/RushCommandLineParser.ts
+++ b/libraries/rush-lib/src/cli/RushCommandLineParser.ts
@@ -66,7 +66,7 @@ export interface IRushCommandLineParserOptions {
export class RushCommandLineParser extends CommandLineParser {
public telemetry: Telemetry | undefined;
- public rushGlobalFolder!: RushGlobalFolder;
+ public rushGlobalFolder: RushGlobalFolder;
public readonly rushConfiguration!: RushConfiguration;
public readonly rushSession: RushSession;
public readonly pluginManager: PluginManager;
@@ -127,6 +127,8 @@ export class RushCommandLineParser extends CommandLineParser {
rushConfiguration: this.rushConfiguration
});
+ this.rushGlobalFolder = new RushGlobalFolder();
+
this.rushSession = new RushSession({
getIsDebugMode: () => this.isDebug,
terminalProvider: this._terminalProvider
@@ -136,7 +138,8 @@ export class RushCommandLineParser extends CommandLineParser {
rushConfiguration: this.rushConfiguration,
terminal: this._terminal,
builtInPluginConfigurations: this._rushOptions.builtInPluginConfigurations,
- restrictConsoleOutput: this._restrictConsoleOutput
+ restrictConsoleOutput: this._restrictConsoleOutput,
+ rushGlobalFolder: this.rushGlobalFolder
});
this._populateActions();
@@ -238,8 +241,6 @@ export class RushCommandLineParser extends CommandLineParser {
private _populateActions(): void {
try {
- this.rushGlobalFolder = new RushGlobalFolder();
-
// Alphabetical order
this.addAction(new AddAction(this));
this.addAction(new ChangeAction(this));
@@ -394,6 +395,7 @@ export class RushCommandLineParser extends CommandLineParser {
disableBuildCache: command.disableBuildCache || false,
initialPhases: command.phases,
+ originalPhases: command.originalPhases,
watchPhases: command.watchPhases,
watchDebounceMs: command.watchDebounceMs ?? RushConstants.defaultWatchDebounceMs,
phases: commandLineConfiguration.phases,
diff --git a/libraries/rush-lib/src/cli/actions/InitAutoinstallerAction.ts b/libraries/rush-lib/src/cli/actions/InitAutoinstallerAction.ts
index 76e2ee4edc2..83a30f7996d 100644
--- a/libraries/rush-lib/src/cli/actions/InitAutoinstallerAction.ts
+++ b/libraries/rush-lib/src/cli/actions/InitAutoinstallerAction.ts
@@ -38,7 +38,8 @@ export class InitAutoinstallerAction extends BaseRushAction {
const autoinstaller: Autoinstaller = new Autoinstaller({
autoinstallerName,
- rushConfiguration: this.rushConfiguration
+ rushConfiguration: this.rushConfiguration,
+ rushGlobalFolder: this.rushGlobalFolder
});
if (FileSystem.exists(autoinstaller.folderFullPath)) {
diff --git a/libraries/rush-lib/src/cli/actions/UpdateAutoinstallerAction.ts b/libraries/rush-lib/src/cli/actions/UpdateAutoinstallerAction.ts
index d6d836898f4..54aa48dab80 100644
--- a/libraries/rush-lib/src/cli/actions/UpdateAutoinstallerAction.ts
+++ b/libraries/rush-lib/src/cli/actions/UpdateAutoinstallerAction.ts
@@ -32,9 +32,15 @@ export class UpdateAutoinstallerAction extends BaseRushAction {
const autoinstaller: Autoinstaller = new Autoinstaller({
autoinstallerName,
- rushConfiguration: this.rushConfiguration
+ rushConfiguration: this.rushConfiguration,
+ rushGlobalFolder: this.rushGlobalFolder
});
- autoinstaller.update();
+
+ // Do not run `autoinstaller.prepareAsync` here. It tries to install the autoinstaller with
+ // --frozen-lockfile or equivalent, which will fail if the autoinstaller's dependencies
+ // have been changed.
+
+ await autoinstaller.updateAsync();
console.log('\nSuccess.');
}
diff --git a/libraries/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts b/libraries/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts
index f5b033601e0..e2d0f393851 100644
--- a/libraries/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts
+++ b/libraries/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts
@@ -88,7 +88,8 @@ export class GlobalScriptAction extends BaseScriptAction {
private async _prepareAutoinstallerName(): Promise {
const autoInstaller: Autoinstaller = new Autoinstaller({
autoinstallerName: this._autoinstallerName,
- rushConfiguration: this.rushConfiguration
+ rushConfiguration: this.rushConfiguration,
+ rushGlobalFolder: this.rushGlobalFolder
});
await autoInstaller.prepareAsync();
diff --git a/libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts b/libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts
index 67c14ff22a5..7b29b4f8326 100644
--- a/libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts
+++ b/libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts
@@ -28,6 +28,7 @@ import { BuildCacheConfiguration } from '../../api/BuildCacheConfiguration';
import { SelectionParameterSet } from '../parsing/SelectionParameterSet';
import type { IPhase, IPhasedCommandConfig } from '../../api/CommandLineConfiguration';
import { Operation } from '../../logic/operations/Operation';
+import { OperationExecutionRecord } from '../../logic/operations/OperationExecutionRecord';
import { PhasedOperationPlugin } from '../../logic/operations/PhasedOperationPlugin';
import { ShellOperationRunnerPlugin } from '../../logic/operations/ShellOperationRunnerPlugin';
import { Event } from '../../api/EventHooks';
@@ -46,6 +47,7 @@ export interface IPhasedScriptActionOptions extends IBaseScriptActionOptions;
initialPhases: Set;
watchPhases: Set;
phases: Map;
@@ -102,6 +104,7 @@ export class PhasedScriptAction extends BaseScriptAction {
private readonly _enableParallelism: boolean;
private readonly _isIncrementalBuildAllowed: boolean;
private readonly _disableBuildCache: boolean;
+ private readonly _originalPhases: ReadonlySet;
private readonly _initialPhases: ReadonlySet;
private readonly _watchPhases: ReadonlySet;
private readonly _watchDebounceMs: number;
@@ -124,6 +127,7 @@ export class PhasedScriptAction extends BaseScriptAction {
this._enableParallelism = options.enableParallelism;
this._isIncrementalBuildAllowed = options.incremental;
this._disableBuildCache = options.disableBuildCache;
+ this._originalPhases = options.originalPhases;
this._initialPhases = options.initialPhases;
this._watchPhases = options.watchPhases;
this._watchDebounceMs = options.watchDebounceMs ?? RushConstants.defaultWatchDebounceMs;
@@ -330,6 +334,7 @@ export class PhasedScriptAction extends BaseScriptAction {
isInitial: true,
isWatch,
rushConfiguration: this.rushConfiguration,
+ phaseOriginal: new Set(this._originalPhases),
phaseSelection: new Set(this._initialPhases),
projectChangeAnalyzer,
projectSelection,
@@ -340,7 +345,13 @@ export class PhasedScriptAction extends BaseScriptAction {
quietMode: isQuietMode,
debugMode: this.parser.isDebug,
parallelism,
- changedProjectsOnly
+ changedProjectsOnly,
+ beforeExecuteOperations: async (records: Map) => {
+ await this.hooks.beforeExecuteOperations.promise(records);
+ },
+ onOperationStatusChanged: (record: OperationExecutionRecord) => {
+ this.hooks.onOperationStatusChanged.call(record);
+ }
};
const internalOptions: IRunPhasesOptions = {
@@ -400,6 +411,7 @@ export class PhasedScriptAction extends BaseScriptAction {
private async _runWatchPhases(options: IRunPhasesOptions): Promise {
const { initialCreateOperationsContext, executionManagerOptions, stopwatch, terminal } = options;
+ const phaseOriginal: Set = new Set(this._watchPhases);
const phaseSelection: Set = new Set(this._watchPhases);
const { projectChangeAnalyzer: initialState, projectSelection: projectsToWatch } =
@@ -457,6 +469,7 @@ export class PhasedScriptAction extends BaseScriptAction {
isInitial: false,
projectChangeAnalyzer: state,
projectsInUnknownState: changedProjects,
+ phaseOriginal,
phaseSelection
};
diff --git a/libraries/rush-lib/src/index.ts b/libraries/rush-lib/src/index.ts
index c98c9d20d56..d1860e96034 100644
--- a/libraries/rush-lib/src/index.ts
+++ b/libraries/rush-lib/src/index.ts
@@ -63,7 +63,7 @@ export { PackageJsonEditor, PackageJsonDependency, DependencyType } from './api/
export { RepoStateFile } from './logic/RepoStateFile';
-export { LookupByPath } from './logic/LookupByPath';
+export { LookupByPath, IPrefixMatch } from './logic/LookupByPath';
export { EventHooks, Event } from './api/EventHooks';
export { ChangeManager } from './api/ChangeManager';
diff --git a/libraries/rush-lib/src/logic/Autoinstaller.ts b/libraries/rush-lib/src/logic/Autoinstaller.ts
index ec3d869bc5d..879bee9fcf8 100644
--- a/libraries/rush-lib/src/logic/Autoinstaller.ts
+++ b/libraries/rush-lib/src/logic/Autoinstaller.ts
@@ -11,7 +11,7 @@ import { PackageName, IParsedPackageNameOrError } from '@rushstack/node-core-lib
import { RushConfiguration } from '../api/RushConfiguration';
import { PackageJsonEditor } from '../api/PackageJsonEditor';
import { InstallHelpers } from './installManager/InstallHelpers';
-import { RushGlobalFolder } from '../api/RushGlobalFolder';
+import type { RushGlobalFolder } from '../api/RushGlobalFolder';
import { RushConstants } from './RushConstants';
import { LastInstallFlag } from '../api/LastInstallFlag';
import { RushCommandLineParser } from '../cli/RushCommandLineParser';
@@ -19,6 +19,7 @@ import { RushCommandLineParser } from '../cli/RushCommandLineParser';
interface IAutoinstallerOptions {
autoinstallerName: string;
rushConfiguration: RushConfiguration;
+ rushGlobalFolder: RushGlobalFolder;
restrictConsoleOutput?: boolean;
}
@@ -26,11 +27,13 @@ export class Autoinstaller {
public readonly name: string;
private readonly _rushConfiguration: RushConfiguration;
+ private readonly _rushGlobalFolder: RushGlobalFolder;
private readonly _restrictConsoleOutput: boolean;
public constructor(options: IAutoinstallerOptions) {
this.name = options.autoinstallerName;
this._rushConfiguration = options.rushConfiguration;
+ this._rushGlobalFolder = options.rushGlobalFolder;
this._restrictConsoleOutput =
options.restrictConsoleOutput ?? RushCommandLineParser.shouldRestrictConsoleOutput();
@@ -75,10 +78,9 @@ export class Autoinstaller {
);
}
- const rushGlobalFolder: RushGlobalFolder = new RushGlobalFolder();
await InstallHelpers.ensureLocalPackageManager(
this._rushConfiguration,
- rushGlobalFolder,
+ this._rushGlobalFolder,
RushConstants.defaultMaxInstallAttempts,
this._restrictConsoleOutput
);
@@ -155,7 +157,14 @@ export class Autoinstaller {
}
}
- public update(): void {
+ public async updateAsync(): Promise {
+ await InstallHelpers.ensureLocalPackageManager(
+ this._rushConfiguration,
+ this._rushGlobalFolder,
+ RushConstants.defaultMaxInstallAttempts,
+ this._restrictConsoleOutput
+ );
+
const autoinstallerPackageJsonPath: string = path.join(this.folderFullPath, 'package.json');
if (!FileSystem.exists(autoinstallerPackageJsonPath)) {
diff --git a/libraries/rush-lib/src/logic/EventHooksManager.ts b/libraries/rush-lib/src/logic/EventHooksManager.ts
index d950c7ffd9b..7156466e403 100644
--- a/libraries/rush-lib/src/logic/EventHooksManager.ts
+++ b/libraries/rush-lib/src/logic/EventHooksManager.ts
@@ -34,13 +34,17 @@ export class EventHooksManager {
const stopwatch: Stopwatch = Stopwatch.start();
console.log('\n' + colors.green(`Executing event hooks for ${Event[event]}`));
+
+ const printEventHooksOutputToConsole: boolean | undefined =
+ isDebug ||
+ this._rushConfiguration.experimentsConfiguration.configuration.printEventHooksOutputToConsole;
scripts.forEach((script) => {
try {
Utilities.executeLifecycleCommand(script, {
rushConfiguration: this._rushConfiguration,
workingDirectory: this._rushConfiguration.rushJsonFolder,
initCwd: this._commonTempFolder,
- handleOutput: !isDebug,
+ handleOutput: !printEventHooksOutputToConsole,
environmentPathOptions: {
includeRepoBin: true
}
diff --git a/libraries/rush-lib/src/logic/LookupByPath.ts b/libraries/rush-lib/src/logic/LookupByPath.ts
index 0fbaf994108..a848949f216 100644
--- a/libraries/rush-lib/src/logic/LookupByPath.ts
+++ b/libraries/rush-lib/src/logic/LookupByPath.ts
@@ -15,6 +15,21 @@ interface IPathTreeNode {
children: Map> | undefined;
}
+interface IPrefixEntry {
+ prefix: string;
+ index: number;
+}
+
+/**
+ * Object containing both the matched item and the start index of the remainder of the query.
+ *
+ * @beta
+ */
+export interface IPrefixMatch {
+ value: TItem;
+ index: number;
+}
+
/**
* This class is used to associate POSIX relative paths, such as those returned by `git` commands,
* with entities that correspond with ancestor folders, such as Rush Projects.
@@ -24,11 +39,11 @@ interface IPathTreeNode {
* @example
* ```ts
* const tree = new LookupByPath([['foo', 1], ['bar', 2], ['foo/bar', 3]]);
- * tree.getNearestAncestor('foo'); // returns 1
- * tree.getNearestAncestor('foo/baz'); // returns 1
- * tree.getNearestAncestor('baz'); // returns undefined
- * tree.getNearestAncestor('foo/bar/baz'); returns 3
- * tree.getNearestAncestor('bar/foo/bar'); returns 2
+ * tree.findChildPath('foo'); // returns 1
+ * tree.findChildPath('foo/baz'); // returns 1
+ * tree.findChildPath('baz'); // returns undefined
+ * tree.findChildPath('foo/bar/baz'); returns 3
+ * tree.findChildPath('bar/foo/bar'); returns 2
* ```
* @beta
*/
@@ -72,21 +87,35 @@ export class LookupByPath {
* `LookupByPath.iteratePathSegments('foo\\bar\\baz', '\\')` yields 'foo', 'bar', 'baz'
*/
public static *iteratePathSegments(serializedPath: string, delimiter: string = '/'): Iterable {
- if (!serializedPath) {
+ for (const prefixMatch of this._iteratePrefixes(serializedPath, delimiter)) {
+ yield prefixMatch.prefix;
+ }
+ }
+
+ private static *_iteratePrefixes(input: string, delimiter: string = '/'): Iterable {
+ if (!input) {
return;
}
- let nextIndex: number = serializedPath.indexOf(delimiter);
let previousIndex: number = 0;
- while (nextIndex >= 0) {
- yield serializedPath.slice(previousIndex, nextIndex);
+ let nextIndex: number = input.indexOf(delimiter);
+ // Leading segments
+ while (nextIndex >= 0) {
+ yield {
+ prefix: input.slice(previousIndex, nextIndex),
+ index: nextIndex
+ };
previousIndex = nextIndex + 1;
- nextIndex = serializedPath.indexOf(delimiter, previousIndex);
+ nextIndex = input.indexOf(delimiter, previousIndex);
}
- if (previousIndex + 1 < serializedPath.length) {
- yield serializedPath.slice(previousIndex);
+ // Last segment
+ if (previousIndex + 1 < input.length) {
+ yield {
+ prefix: input.slice(previousIndex, input.length),
+ index: input.length
+ };
}
}
@@ -146,6 +175,24 @@ export class LookupByPath {
return this.findChildPathFromSegments(LookupByPath.iteratePathSegments(childPath, this.delimiter));
}
+ /**
+ * Searches for the item for which the recorded prefix is the longest matching prefix of `query`.
+ * Obtains both the item and the length of the matched prefix, so that the remainder of the path can be
+ * extracted.
+ *
+ * @returns the found item and the length of the matched prefix, or `undefined` if no item was found
+ *
+ * @example
+ * ```ts
+ * const tree = new LookupByPath([['foo', 1], ['foo/bar', 2]]);
+ * tree.findLongestPrefixMatch('foo/baz'); // returns { item: 1, index: 3 }
+ * tree.findLongestPrefixMatch('foo/bar/baz'); // returns { item: 2, index: 7 }
+ * ```
+ */
+ public findLongestPrefixMatch(query: string): IPrefixMatch | undefined {
+ return this._findLongestPrefixMatch(LookupByPath._iteratePrefixes(query, this.delimiter));
+ }
+
/**
* Searches for the item associated with `childPathSegments`, or the nearest ancestor of that path that
* has an associated item.
@@ -179,4 +226,43 @@ export class LookupByPath {
return best;
}
+
+ /**
+ * Iterates through progressively longer prefixes of a given string and returns as soon
+ * as the number of candidate items that match the prefix are 1 or 0.
+ *
+ * If a match is present, returns the matched itme and the length of the matched prefix.
+ *
+ * @returns the found item, or `undefined` if no item was found
+ */
+ private _findLongestPrefixMatch(prefixes: Iterable): IPrefixMatch | undefined {
+ let node: IPathTreeNode = this._root;
+ let best: IPrefixMatch | undefined = node.value
+ ? {
+ value: node.value,
+ index: 0
+ }
+ : undefined;
+ // Trivial cases
+ if (node.children) {
+ for (const { prefix: hash, index } of prefixes) {
+ const child: IPathTreeNode | undefined = node.children.get(hash);
+ if (!child) {
+ break;
+ }
+ node = child;
+ if (node.value !== undefined) {
+ best = {
+ value: node.value,
+ index
+ };
+ }
+ if (!node.children) {
+ break;
+ }
+ }
+ }
+
+ return best;
+ }
}
diff --git a/libraries/rush-lib/src/logic/installManager/RushInstallManager.ts b/libraries/rush-lib/src/logic/installManager/RushInstallManager.ts
index 9889de84da1..14847602cab 100644
--- a/libraries/rush-lib/src/logic/installManager/RushInstallManager.ts
+++ b/libraries/rush-lib/src/logic/installManager/RushInstallManager.ts
@@ -575,45 +575,28 @@ export class RushInstallManager extends BaseInstallManager {
);
}
- try {
- Utilities.executeCommandWithRetry(
- {
- command: packageManagerFilename,
- args: installArgs,
- workingDirectory: this.rushConfiguration.commonTempFolder,
- environment: packageManagerEnv,
- suppressOutput: false
- },
- this.options.maxInstallAttempts,
- () => {
- if (this.rushConfiguration.packageManager === 'pnpm') {
- console.log(colors.yellow(`Deleting the "node_modules" folder`));
- this.installRecycler.moveFolder(commonNodeModulesFolder);
-
- // Leave the pnpm-store as is for the retry. This ensures that packages that have already
- // been downloaded need not be downloaded again, thereby potentially increasing the chances
- // of a subsequent successful install.
-
- Utilities.createFolderWithRetry(commonNodeModulesFolder);
- }
+ Utilities.executeCommandWithRetry(
+ {
+ command: packageManagerFilename,
+ args: installArgs,
+ workingDirectory: this.rushConfiguration.commonTempFolder,
+ environment: packageManagerEnv,
+ suppressOutput: false
+ },
+ this.options.maxInstallAttempts,
+ () => {
+ if (this.rushConfiguration.packageManager === 'pnpm') {
+ console.log(colors.yellow(`Deleting the "node_modules" folder`));
+ this.installRecycler.moveFolder(commonNodeModulesFolder);
+
+ // Leave the pnpm-store as is for the retry. This ensures that packages that have already
+ // been downloaded need not be downloaded again, thereby potentially increasing the chances
+ // of a subsequent successful install.
+
+ Utilities.createFolderWithRetry(commonNodeModulesFolder);
}
- );
- } catch (error) {
- // All the install attempts failed.
-
- if (
- this.rushConfiguration.packageManager === 'pnpm' &&
- this.rushConfiguration.pnpmOptions.pnpmStore === 'local'
- ) {
- // If the installation has failed even after the retries, then pnpm store may
- // have got into a corrupted, irrecoverable state. Delete the store so that a
- // future install can create the store afresh.
- console.log(colors.yellow(`Deleting the "pnpm-store" folder`));
- this.installRecycler.moveFolder(this.rushConfiguration.pnpmOptions.pnpmStorePath);
}
-
- throw error;
- }
+ );
if (this.rushConfiguration.packageManager === 'npm') {
console.log('\n' + colors.bold('Running "npm shrinkwrap"...'));
diff --git a/libraries/rush-lib/src/logic/operations/OperationExecutionManager.ts b/libraries/rush-lib/src/logic/operations/OperationExecutionManager.ts
index a84a0cb67d6..4cc9847e9f9 100644
--- a/libraries/rush-lib/src/logic/operations/OperationExecutionManager.ts
+++ b/libraries/rush-lib/src/logic/operations/OperationExecutionManager.ts
@@ -18,6 +18,9 @@ export interface IOperationExecutionManagerOptions {
parallelism: number;
changedProjectsOnly: boolean;
destination?: TerminalWritable;
+
+ onOperationStatusChanged?: (record: OperationExecutionRecord) => void;
+ beforeExecuteOperations?: (records: Map) => Promise;
}
/**
@@ -44,13 +47,25 @@ export class OperationExecutionManager {
private readonly _terminal: CollatedTerminal;
+ private readonly _onOperationStatusChanged?: (record: OperationExecutionRecord) => void;
+ private readonly _beforeExecuteOperations?: (
+ records: Map
+ ) => Promise;
+
// Variables for current status
private _hasAnyFailures: boolean;
private _hasAnyNonAllowedWarnings: boolean;
private _completedOperations: number;
public constructor(operations: Set, options: IOperationExecutionManagerOptions) {
- const { quietMode, debugMode, parallelism, changedProjectsOnly } = options;
+ const {
+ quietMode,
+ debugMode,
+ parallelism,
+ changedProjectsOnly,
+ onOperationStatusChanged,
+ beforeExecuteOperations
+ } = options;
this._completedOperations = 0;
this._quietMode = quietMode;
this._hasAnyFailures = false;
@@ -58,6 +73,9 @@ export class OperationExecutionManager {
this._changedProjectsOnly = changedProjectsOnly;
this._parallelism = parallelism;
+ this._beforeExecuteOperations = beforeExecuteOperations;
+ this._onOperationStatusChanged = onOperationStatusChanged;
+
// TERMINAL PIPELINE:
//
// streamCollator --> colorsNewlinesTransform --> StdioWritable
@@ -77,6 +95,7 @@ export class OperationExecutionManager {
// Convert the developer graph to the mutable execution graph
const executionRecordContext: IOperationExecutionRecordContext = {
streamCollator: this._streamCollator,
+ onOperationStatusChanged,
debugMode,
quietMode
};
@@ -183,6 +202,8 @@ export class OperationExecutionManager {
prioritySort
);
+ await this._beforeExecuteOperations?.(this._executionRecords);
+
// This function is a callback because it may write to the collatedWriter before
// operation.executeAsync returns (and cleans up the writer)
const onOperationComplete: (record: OperationExecutionRecord) => void = (
@@ -250,6 +271,7 @@ export class OperationExecutionManager {
terminal.writeStdoutLine(`"${blockedRecord.name}" is blocked by "${name}".`);
}
blockedRecord.status = OperationStatus.Blocked;
+ this._onOperationStatusChanged?.(blockedRecord);
for (const dependent of blockedRecord.consumers) {
blockedQueue.add(dependent);
diff --git a/libraries/rush-lib/src/logic/operations/OperationExecutionRecord.ts b/libraries/rush-lib/src/logic/operations/OperationExecutionRecord.ts
index 11cd208e8bd..3c97bbc574a 100644
--- a/libraries/rush-lib/src/logic/operations/OperationExecutionRecord.ts
+++ b/libraries/rush-lib/src/logic/operations/OperationExecutionRecord.ts
@@ -13,6 +13,7 @@ import { OperationMetadataManager } from './OperationMetadataManager';
export interface IOperationExecutionRecordContext {
streamCollator: StreamCollator;
+ onOperationStatusChanged?: (record: OperationExecutionRecord) => void;
debugMode: boolean;
quietMode: boolean;
@@ -135,6 +136,7 @@ export class OperationExecutionRecord implements IOperationRunnerContext {
public async executeAsync(onResult: (record: OperationExecutionRecord) => void): Promise {
this.status = OperationStatus.Executing;
this.stopwatch.start();
+ this._context.onOperationStatusChanged?.(this);
try {
this.status = await this.runner.executeAsync(this);
@@ -149,6 +151,7 @@ export class OperationExecutionRecord implements IOperationRunnerContext {
this._collatedWriter?.close();
this.stdioSummarizer.close();
this.stopwatch.stop();
+ this._context.onOperationStatusChanged?.(this);
}
}
}
diff --git a/libraries/rush-lib/src/logic/operations/PhasedOperationPlugin.ts b/libraries/rush-lib/src/logic/operations/PhasedOperationPlugin.ts
index f07984f2a6e..17de0854eaf 100644
--- a/libraries/rush-lib/src/logic/operations/PhasedOperationPlugin.ts
+++ b/libraries/rush-lib/src/logic/operations/PhasedOperationPlugin.ts
@@ -29,13 +29,18 @@ function createOperations(
existingOperations: Set,
context: ICreateOperationsContext
): Set {
- const { projectsInUnknownState: changedProjects, phaseSelection, projectSelection } = context;
+ const {
+ projectsInUnknownState: changedProjects,
+ phaseOriginal,
+ phaseSelection,
+ projectSelection
+ } = context;
const operationsWithWork: Set = new Set();
const operations: Map = new Map();
// Create tasks for selected phases and projects
- for (const phase of phaseSelection) {
+ for (const phase of phaseOriginal) {
for (const project of projectSelection) {
getOrCreateOperation(phase, project);
}
diff --git a/libraries/rush-lib/src/logic/operations/test/PhasedOperationPlugin.test.ts b/libraries/rush-lib/src/logic/operations/test/PhasedOperationPlugin.test.ts
index 62b2a308a18..2d5b46c79ec 100644
--- a/libraries/rush-lib/src/logic/operations/test/PhasedOperationPlugin.test.ts
+++ b/libraries/rush-lib/src/logic/operations/test/PhasedOperationPlugin.test.ts
@@ -68,8 +68,9 @@ describe(PhasedOperationPlugin.name, () => {
const context: Pick<
ICreateOperationsContext,
- 'phaseSelection' | 'projectSelection' | 'projectsInUnknownState'
+ 'phaseOriginal' | 'phaseSelection' | 'projectSelection' | 'projectsInUnknownState'
> = {
+ phaseOriginal: phaseSelection,
phaseSelection,
projectSelection,
projectsInUnknownState: changedProjects
diff --git a/libraries/rush-lib/src/logic/operations/test/ShellOperationRunnerPlugin.test.ts b/libraries/rush-lib/src/logic/operations/test/ShellOperationRunnerPlugin.test.ts
index 66f95ffec73..96fe059ee21 100644
--- a/libraries/rush-lib/src/logic/operations/test/ShellOperationRunnerPlugin.test.ts
+++ b/libraries/rush-lib/src/logic/operations/test/ShellOperationRunnerPlugin.test.ts
@@ -44,8 +44,9 @@ describe(ShellOperationRunnerPlugin.name, () => {
const fakeCreateOperationsContext: Pick<
ICreateOperationsContext,
- 'phaseSelection' | 'projectSelection' | 'projectsInUnknownState'
+ 'phaseOriginal' | 'phaseSelection' | 'projectSelection' | 'projectsInUnknownState'
> = {
+ phaseOriginal: echoCommand.phases,
phaseSelection: echoCommand.phases,
projectSelection: new Set(rushConfiguration.projects),
projectsInUnknownState: new Set(rushConfiguration.projects)
@@ -86,8 +87,9 @@ describe(ShellOperationRunnerPlugin.name, () => {
const fakeCreateOperationsContext: Pick<
ICreateOperationsContext,
- 'phaseSelection' | 'projectSelection' | 'projectsInUnknownState'
+ 'phaseOriginal' | 'phaseSelection' | 'projectSelection' | 'projectsInUnknownState'
> = {
+ phaseOriginal: echoCommand.phases,
phaseSelection: echoCommand.phases,
projectSelection: new Set(rushConfiguration.projects),
projectsInUnknownState: new Set(rushConfiguration.projects)
diff --git a/libraries/rush-lib/src/logic/test/LookupByPath.test.ts b/libraries/rush-lib/src/logic/test/LookupByPath.test.ts
index 0329ac2315c..5b4cbeed881 100644
--- a/libraries/rush-lib/src/logic/test/LookupByPath.test.ts
+++ b/libraries/rush-lib/src/logic/test/LookupByPath.test.ts
@@ -101,3 +101,37 @@ describe(LookupByPath.prototype.findChildPath.name, () => {
expect(tree.findChildPathFromSegments(['foo', 'bar', 'baz'])).toEqual(1);
});
});
+
+describe(LookupByPath.prototype.findLongestPrefixMatch.name, () => {
+ it('returns empty for an empty tree', () => {
+ expect(new LookupByPath().findLongestPrefixMatch('foo')).toEqual(undefined);
+ });
+ it('returns the matching node for a trivial tree', () => {
+ expect(new LookupByPath([['foo', 1]]).findLongestPrefixMatch('foo')).toEqual({ value: 1, index: 3 });
+ });
+ it('returns the matching node for a single-layer tree', () => {
+ const tree: LookupByPath = new LookupByPath([
+ ['foo', 1],
+ ['barbar', 2],
+ ['baz', 3]
+ ]);
+
+ expect(tree.findLongestPrefixMatch('foo')).toEqual({ value: 1, index: 3 });
+ expect(tree.findLongestPrefixMatch('barbar')).toEqual({ value: 2, index: 6 });
+ expect(tree.findLongestPrefixMatch('baz')).toEqual({ value: 3, index: 3 });
+ expect(tree.findLongestPrefixMatch('buzz')).toEqual(undefined);
+ });
+ it('returns the matching parent for multi-layer queries', () => {
+ const tree: LookupByPath = new LookupByPath([
+ ['foo', 1],
+ ['barbar', 2],
+ ['baz', 3],
+ ['foo/bar', 4]
+ ]);
+
+ expect(tree.findLongestPrefixMatch('foo/bar')).toEqual({ value: 4, index: 7 });
+ expect(tree.findLongestPrefixMatch('barbar/baz')).toEqual({ value: 2, index: 6 });
+ expect(tree.findLongestPrefixMatch('baz/foo')).toEqual({ value: 3, index: 3 });
+ expect(tree.findLongestPrefixMatch('foo/foo')).toEqual({ value: 1, index: 3 });
+ });
+});
diff --git a/libraries/rush-lib/src/pluginFramework/PhasedCommandHooks.ts b/libraries/rush-lib/src/pluginFramework/PhasedCommandHooks.ts
index 1c2e893b67d..a38b9870135 100644
--- a/libraries/rush-lib/src/pluginFramework/PhasedCommandHooks.ts
+++ b/libraries/rush-lib/src/pluginFramework/PhasedCommandHooks.ts
@@ -11,7 +11,7 @@ import type { RushConfigurationProject } from '../api/RushConfigurationProject';
import type { Operation } from '../logic/operations/Operation';
import type { ProjectChangeAnalyzer } from '../logic/ProjectChangeAnalyzer';
-import { IExecutionResult } from '../logic/operations/IOperationExecutionResult';
+import { IExecutionResult, IOperationExecutionResult } from '../logic/operations/IOperationExecutionResult';
/**
* A plugin that interacts with a phased commands.
@@ -52,6 +52,10 @@ export interface ICreateOperationsContext {
* If true, the command is running in watch mode.
*/
readonly isWatch: boolean;
+ /**
+ * The set of phases original for the current command execution.
+ */
+ readonly phaseOriginal: ReadonlySet;
/**
* The set of phases selected for the current command execution.
*/
@@ -87,6 +91,19 @@ export class PhasedCommandHooks {
public readonly createOperations: AsyncSeriesWaterfallHook<[Set, ICreateOperationsContext]> =
new AsyncSeriesWaterfallHook(['operations', 'context'], 'createOperations');
+ /**
+ * Hook invoked before operation start
+ * Hook is series for stable output.
+ */
+ public readonly beforeExecuteOperations: AsyncSeriesHook<[Map]> =
+ new AsyncSeriesHook(['records']);
+
+ /**
+ * Hook invoked when operation status changed
+ * Hook is series for stable output.
+ */
+ public readonly onOperationStatusChanged: SyncHook<[IOperationExecutionResult]> = new SyncHook(['record']);
+
/**
* Hook invoked after executing a set of operations.
* Use the context to distinguish between the initial run and phased runs.
diff --git a/libraries/rush-lib/src/pluginFramework/PluginLoader/AutoinstallerPluginLoader.ts b/libraries/rush-lib/src/pluginFramework/PluginLoader/AutoinstallerPluginLoader.ts
index adcfac85586..07a8d165247 100644
--- a/libraries/rush-lib/src/pluginFramework/PluginLoader/AutoinstallerPluginLoader.ts
+++ b/libraries/rush-lib/src/pluginFramework/PluginLoader/AutoinstallerPluginLoader.ts
@@ -13,9 +13,11 @@ import {
IRushPluginManifestJson,
PluginLoaderBase
} from './PluginLoaderBase';
+import type { RushGlobalFolder } from '../../api/RushGlobalFolder';
interface IAutoinstallerPluginLoaderOptions extends IPluginLoaderOptions {
restrictConsoleOutput: boolean;
+ rushGlobalFolder: RushGlobalFolder;
}
/**
@@ -31,7 +33,8 @@ export class AutoinstallerPluginLoader extends PluginLoaderBase;
private readonly _loadedPluginNames: Set = new Set();
+ private readonly _rushGlobalFolder: RushGlobalFolder;
private _error: Error | undefined;
@@ -42,6 +45,7 @@ export class PluginManager {
this._rushConfiguration = options.rushConfiguration;
this._rushSession = options.rushSession;
this._restrictConsoleOutput = options.restrictConsoleOutput;
+ this._rushGlobalFolder = options.rushGlobalFolder;
this._installedAutoinstallerNames = new Set();
@@ -99,7 +103,8 @@ export class PluginManager {
pluginConfiguration,
rushConfiguration: this._rushConfiguration,
terminal: this._terminal,
- restrictConsoleOutput: this._restrictConsoleOutput
+ restrictConsoleOutput: this._restrictConsoleOutput,
+ rushGlobalFolder: this._rushGlobalFolder
});
});
}
diff --git a/libraries/rush-lib/src/schemas/experiments.schema.json b/libraries/rush-lib/src/schemas/experiments.schema.json
index caff117b104..bb1e8e92602 100644
--- a/libraries/rush-lib/src/schemas/experiments.schema.json
+++ b/libraries/rush-lib/src/schemas/experiments.schema.json
@@ -37,6 +37,10 @@
"cleanInstallAfterNpmrcChanges": {
"description": "If true, perform a clean install after when running `rush install` or `rush update` if the `.npmrc` file has changed since the last install.",
"type": "boolean"
+ },
+ "printEventHooksOutputToConsole": {
+ "description": "If true, print the outputs of shell commands defined in event hooks to the console.",
+ "type": "boolean"
}
},
"additionalProperties": false
diff --git a/libraries/rush-lib/src/utilities/SetRushLibPath.ts b/libraries/rush-lib/src/utilities/SetRushLibPath.ts
index ec18843e67b..236a8b89f25 100644
--- a/libraries/rush-lib/src/utilities/SetRushLibPath.ts
+++ b/libraries/rush-lib/src/utilities/SetRushLibPath.ts
@@ -2,11 +2,9 @@ import { PackageJsonLookup } from '@rushstack/node-core-library';
import { EnvironmentVariableNames } from '../api/EnvironmentConfiguration';
-if (!process.env[EnvironmentVariableNames.RUSH_LIB_PATH]) {
- const rootDir: string | undefined = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname);
- if (rootDir) {
- // Route to the 'main' field of package.json
- const rushLibIndex: string = require.resolve(rootDir, { paths: [] });
- process.env[EnvironmentVariableNames.RUSH_LIB_PATH] = rushLibIndex;
- }
+const rootDir: string | undefined = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname);
+if (rootDir) {
+ // Route to the 'main' field of package.json
+ const rushLibIndex: string = require.resolve(rootDir, { paths: [] });
+ process.env[EnvironmentVariableNames.RUSH_LIB_PATH] = rushLibIndex;
}
diff --git a/libraries/rush-sdk/.npmignore b/libraries/rush-sdk/.npmignore
index 302dbc5b019..d64437e0b4e 100644
--- a/libraries/rush-sdk/.npmignore
+++ b/libraries/rush-sdk/.npmignore
@@ -27,4 +27,6 @@
# DO NOT MODIFY THE TEMPLATE ABOVE THIS LINE
#--------------------------------------------
+/lib-shim/generate-stubs*
+
# (Add your project-specific overrides here)
\ No newline at end of file
diff --git a/libraries/rush-sdk/package.json b/libraries/rush-sdk/package.json
index a0cc5ae8868..165d6788ede 100644
--- a/libraries/rush-sdk/package.json
+++ b/libraries/rush-sdk/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/rush-sdk",
- "version": "5.93.1",
+ "version": "5.96.0",
"description": "An API for interacting with the Rush engine",
"repository": {
"type": "git",
diff --git a/libraries/stream-collator/CHANGELOG.json b/libraries/stream-collator/CHANGELOG.json
index a06dffd96d7..7875df97ef7 100644
--- a/libraries/stream-collator/CHANGELOG.json
+++ b/libraries/stream-collator/CHANGELOG.json
@@ -1,6 +1,24 @@
{
"name": "@rushstack/stream-collator",
"entries": [
+ {
+ "version": "4.0.228",
+ "tag": "@rushstack/stream-collator_v4.0.228",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.3`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
{
"version": "4.0.227",
"tag": "@rushstack/stream-collator_v4.0.227",
diff --git a/libraries/stream-collator/CHANGELOG.md b/libraries/stream-collator/CHANGELOG.md
index 1a15e0f3470..9b92d1aa5c4 100644
--- a/libraries/stream-collator/CHANGELOG.md
+++ b/libraries/stream-collator/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/stream-collator
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 4.0.228
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 4.0.227
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/libraries/stream-collator/package.json b/libraries/stream-collator/package.json
index f68ff17bfd0..0cf2674c5d8 100644
--- a/libraries/stream-collator/package.json
+++ b/libraries/stream-collator/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/stream-collator",
- "version": "4.0.227",
+ "version": "4.0.228",
"description": "Display intelligible realtime output from concurrent processes",
"repository": {
"type": "git",
diff --git a/libraries/terminal/CHANGELOG.json b/libraries/terminal/CHANGELOG.json
index df2c1479cc1..74c00fefa1b 100644
--- a/libraries/terminal/CHANGELOG.json
+++ b/libraries/terminal/CHANGELOG.json
@@ -1,6 +1,21 @@
{
"name": "@rushstack/terminal",
"entries": [
+ {
+ "version": "0.5.3",
+ "tag": "@rushstack/terminal_v0.5.3",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
{
"version": "0.5.2",
"tag": "@rushstack/terminal_v0.5.2",
diff --git a/libraries/terminal/CHANGELOG.md b/libraries/terminal/CHANGELOG.md
index c1980c3cfa5..5b27dc479bd 100644
--- a/libraries/terminal/CHANGELOG.md
+++ b/libraries/terminal/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/terminal
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.5.3
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 0.5.2
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/libraries/terminal/package.json b/libraries/terminal/package.json
index ac514e364a6..89021c97ced 100644
--- a/libraries/terminal/package.json
+++ b/libraries/terminal/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/terminal",
- "version": "0.5.2",
+ "version": "0.5.3",
"description": "User interface primitives for console applications",
"main": "lib/index.js",
"typings": "dist/terminal.d.ts",
diff --git a/libraries/typings-generator/CHANGELOG.json b/libraries/typings-generator/CHANGELOG.json
index ee5a4183589..632031058d8 100644
--- a/libraries/typings-generator/CHANGELOG.json
+++ b/libraries/typings-generator/CHANGELOG.json
@@ -1,6 +1,21 @@
{
"name": "@rushstack/typings-generator",
"entries": [
+ {
+ "version": "0.10.3",
+ "tag": "@rushstack/typings-generator_v0.10.3",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
{
"version": "0.10.2",
"tag": "@rushstack/typings-generator_v0.10.2",
diff --git a/libraries/typings-generator/CHANGELOG.md b/libraries/typings-generator/CHANGELOG.md
index e6ea1e21d79..d6302b9bbfb 100644
--- a/libraries/typings-generator/CHANGELOG.md
+++ b/libraries/typings-generator/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/typings-generator
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.10.3
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 0.10.2
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/libraries/typings-generator/package.json b/libraries/typings-generator/package.json
index 26839a955a7..78def4ebb28 100644
--- a/libraries/typings-generator/package.json
+++ b/libraries/typings-generator/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/typings-generator",
- "version": "0.10.2",
+ "version": "0.10.3",
"description": "This library provides functionality for automatically generating typings for non-TS files.",
"keywords": [
"dts",
diff --git a/libraries/worker-pool/CHANGELOG.json b/libraries/worker-pool/CHANGELOG.json
index aea2f72e4cf..0ee39d30968 100644
--- a/libraries/worker-pool/CHANGELOG.json
+++ b/libraries/worker-pool/CHANGELOG.json
@@ -1,6 +1,21 @@
{
"name": "@rushstack/worker-pool",
"entries": [
+ {
+ "version": "0.3.3",
+ "tag": "@rushstack/worker-pool_v0.3.3",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
{
"version": "0.3.2",
"tag": "@rushstack/worker-pool_v0.3.2",
diff --git a/libraries/worker-pool/CHANGELOG.md b/libraries/worker-pool/CHANGELOG.md
index 27135555323..024073ef1fd 100644
--- a/libraries/worker-pool/CHANGELOG.md
+++ b/libraries/worker-pool/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/worker-pool
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.3.3
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 0.3.2
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/libraries/worker-pool/package.json b/libraries/worker-pool/package.json
index 63f3e179092..ccf6b11321f 100644
--- a/libraries/worker-pool/package.json
+++ b/libraries/worker-pool/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/worker-pool",
- "version": "0.3.2",
+ "version": "0.3.3",
"description": "Lightweight worker pool using NodeJS worker_threads",
"main": "lib/index.js",
"typings": "dist/worker-pool.d.ts",
diff --git a/rigs/heft-node-rig/CHANGELOG.json b/rigs/heft-node-rig/CHANGELOG.json
index 7133d950093..9fe99d93ba9 100644
--- a/rigs/heft-node-rig/CHANGELOG.json
+++ b/rigs/heft-node-rig/CHANGELOG.json
@@ -1,6 +1,24 @@
{
"name": "@rushstack/heft-node-rig",
"entries": [
+ {
+ "version": "1.12.5",
+ "tag": "@rushstack/heft-node-rig_v1.12.5",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.5`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`"
+ }
+ ]
+ }
+ },
{
"version": "1.12.4",
"tag": "@rushstack/heft-node-rig_v1.12.4",
diff --git a/rigs/heft-node-rig/CHANGELOG.md b/rigs/heft-node-rig/CHANGELOG.md
index 84897734d9a..3958a97b810 100644
--- a/rigs/heft-node-rig/CHANGELOG.md
+++ b/rigs/heft-node-rig/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/heft-node-rig
-This log was last generated on Fri, 10 Feb 2023 01:18:50 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 1.12.5
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 1.12.4
Fri, 10 Feb 2023 01:18:50 GMT
diff --git a/rigs/heft-node-rig/package.json b/rigs/heft-node-rig/package.json
index c41489f6f15..6ff63c5f4a3 100644
--- a/rigs/heft-node-rig/package.json
+++ b/rigs/heft-node-rig/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/heft-node-rig",
- "version": "1.12.4",
+ "version": "1.12.5",
"description": "A rig package for Node.js projects that build using Heft",
"license": "MIT",
"scripts": {
@@ -13,7 +13,7 @@
"directory": "rigs/heft-node-rig"
},
"peerDependencies": {
- "@rushstack/heft": "^0.49.7"
+ "@rushstack/heft": "^0.50.0"
},
"dependencies": {
"@microsoft/api-extractor": "workspace:*",
diff --git a/rigs/heft-web-rig/CHANGELOG.json b/rigs/heft-web-rig/CHANGELOG.json
index 86e9a8b9554..0e2f1967b76 100644
--- a/rigs/heft-web-rig/CHANGELOG.json
+++ b/rigs/heft-web-rig/CHANGELOG.json
@@ -1,6 +1,42 @@
{
"name": "@rushstack/heft-web-rig",
"entries": [
+ {
+ "version": "0.14.7",
+ "tag": "@rushstack/heft-web-rig_v0.14.7",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.5`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.8.4`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.1`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.14.6",
+ "tag": "@rushstack/heft-web-rig_v0.14.6",
+ "date": "Sat, 11 Mar 2023 01:24:51 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.0`"
+ }
+ ]
+ }
+ },
{
"version": "0.14.5",
"tag": "@rushstack/heft-web-rig_v0.14.5",
diff --git a/rigs/heft-web-rig/CHANGELOG.md b/rigs/heft-web-rig/CHANGELOG.md
index 556df8ef6a7..496b61c8458 100644
--- a/rigs/heft-web-rig/CHANGELOG.md
+++ b/rigs/heft-web-rig/CHANGELOG.md
@@ -1,6 +1,16 @@
# Change Log - @rushstack/heft-web-rig
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.14.7
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
+
+## 0.14.6
+Sat, 11 Mar 2023 01:24:51 GMT
+
+_Version update only_
## 0.14.5
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/rigs/heft-web-rig/package.json b/rigs/heft-web-rig/package.json
index 23aec65f877..edb447d3086 100644
--- a/rigs/heft-web-rig/package.json
+++ b/rigs/heft-web-rig/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/heft-web-rig",
- "version": "0.14.5",
+ "version": "0.14.7",
"description": "A rig package for web browser projects that build using Heft",
"license": "MIT",
"scripts": {
@@ -13,7 +13,7 @@
"directory": "rigs/heft-web-rig"
},
"peerDependencies": {
- "@rushstack/heft": "^0.49.7"
+ "@rushstack/heft": "^0.50.0"
},
"dependencies": {
"@microsoft/api-extractor": "workspace:*",
diff --git a/rush-plugins/rush-amazon-s3-build-cache-plugin/package.json b/rush-plugins/rush-amazon-s3-build-cache-plugin/package.json
index f6f1d939f3c..6722f86fc5e 100644
--- a/rush-plugins/rush-amazon-s3-build-cache-plugin/package.json
+++ b/rush-plugins/rush-amazon-s3-build-cache-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/rush-amazon-s3-build-cache-plugin",
- "version": "5.93.1",
+ "version": "5.96.0",
"description": "Rush plugin for Amazon S3 cloud build cache",
"repository": {
"type": "git",
diff --git a/rush-plugins/rush-azure-storage-build-cache-plugin/package.json b/rush-plugins/rush-azure-storage-build-cache-plugin/package.json
index 17f538dabfb..091156f5538 100644
--- a/rush-plugins/rush-azure-storage-build-cache-plugin/package.json
+++ b/rush-plugins/rush-azure-storage-build-cache-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/rush-azure-storage-build-cache-plugin",
- "version": "5.93.1",
+ "version": "5.96.0",
"description": "Rush plugin for Azure storage cloud build cache",
"repository": {
"type": "git",
diff --git a/rush-plugins/rush-serve-plugin/CHANGELOG.json b/rush-plugins/rush-serve-plugin/CHANGELOG.json
index 524e535a447..3644b6d02c6 100644
--- a/rush-plugins/rush-serve-plugin/CHANGELOG.json
+++ b/rush-plugins/rush-serve-plugin/CHANGELOG.json
@@ -1,6 +1,48 @@
{
"name": "@rushstack/rush-serve-plugin",
"entries": [
+ {
+ "version": "0.4.5",
+ "tag": "@rushstack/rush-serve-plugin_v0.4.5",
+ "date": "Mon, 20 Mar 2023 20:14:20 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.19`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.4.4",
+ "tag": "@rushstack/rush-serve-plugin_v0.4.4",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.18`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.4.3",
+ "tag": "@rushstack/rush-serve-plugin_v0.4.3",
+ "date": "Fri, 03 Mar 2023 04:11:20 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.17`"
+ }
+ ]
+ }
+ },
{
"version": "0.4.2",
"tag": "@rushstack/rush-serve-plugin_v0.4.2",
diff --git a/rush-plugins/rush-serve-plugin/CHANGELOG.md b/rush-plugins/rush-serve-plugin/CHANGELOG.md
index 5ce0fa9af11..1f27f0e025c 100644
--- a/rush-plugins/rush-serve-plugin/CHANGELOG.md
+++ b/rush-plugins/rush-serve-plugin/CHANGELOG.md
@@ -1,6 +1,21 @@
# Change Log - @rushstack/rush-serve-plugin
-This log was last generated on Fri, 10 Feb 2023 01:18:50 GMT and should not be manually modified.
+This log was last generated on Mon, 20 Mar 2023 20:14:20 GMT and should not be manually modified.
+
+## 0.4.5
+Mon, 20 Mar 2023 20:14:20 GMT
+
+_Version update only_
+
+## 0.4.4
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
+
+## 0.4.3
+Fri, 03 Mar 2023 04:11:20 GMT
+
+_Version update only_
## 0.4.2
Fri, 10 Feb 2023 01:18:50 GMT
diff --git a/rush-plugins/rush-serve-plugin/package.json b/rush-plugins/rush-serve-plugin/package.json
index 7f22cd01582..aaf7f4c1664 100644
--- a/rush-plugins/rush-serve-plugin/package.json
+++ b/rush-plugins/rush-serve-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/rush-serve-plugin",
- "version": "0.4.2",
+ "version": "0.4.5",
"description": "A Rush plugin that hooks into a rush action and serves output folders from all projects in the repository.",
"license": "MIT",
"repository": {
diff --git a/rush.json b/rush.json
index 56a875ca1fd..40f16d732d1 100644
--- a/rush.json
+++ b/rush.json
@@ -1040,6 +1040,12 @@
},
// "webpack" folder (alphabetical order)
+ {
+ "packageName": "@rushstack/webpack-embedded-dependencies-plugin",
+ "projectFolder": "webpack/webpack-embedded-dependencies-plugin",
+ "reviewCategory": "libraries",
+ "shouldPublish": true
+ },
{
"packageName": "@rushstack/webpack-plugin-utilities",
"projectFolder": "webpack/webpack-plugin-utilities",
diff --git a/webpack/hashed-folder-copy-plugin/CHANGELOG.json b/webpack/hashed-folder-copy-plugin/CHANGELOG.json
index 099519fe5a9..0b6d79f3372 100644
--- a/webpack/hashed-folder-copy-plugin/CHANGELOG.json
+++ b/webpack/hashed-folder-copy-plugin/CHANGELOG.json
@@ -1,6 +1,63 @@
{
"name": "@rushstack/hashed-folder-copy-plugin",
"entries": [
+ {
+ "version": "0.2.6",
+ "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.6",
+ "date": "Thu, 23 Mar 2023 15:24:08 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.1`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.2.5",
+ "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.5",
+ "date": "Wed, 22 Mar 2023 20:48:30 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.0`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.2.4",
+ "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.4",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.57`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.1`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.2.3",
+ "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.3",
+ "date": "Sat, 11 Mar 2023 01:24:51 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.0`"
+ }
+ ]
+ }
+ },
{
"version": "0.2.2",
"tag": "@rushstack/hashed-folder-copy-plugin_v0.2.2",
diff --git a/webpack/hashed-folder-copy-plugin/CHANGELOG.md b/webpack/hashed-folder-copy-plugin/CHANGELOG.md
index b3d00f556b6..2956a4df5d2 100644
--- a/webpack/hashed-folder-copy-plugin/CHANGELOG.md
+++ b/webpack/hashed-folder-copy-plugin/CHANGELOG.md
@@ -1,6 +1,26 @@
# Change Log - @rushstack/hashed-folder-copy-plugin
-This log was last generated on Fri, 10 Feb 2023 01:18:50 GMT and should not be manually modified.
+This log was last generated on Thu, 23 Mar 2023 15:24:08 GMT and should not be manually modified.
+
+## 0.2.6
+Thu, 23 Mar 2023 15:24:08 GMT
+
+_Version update only_
+
+## 0.2.5
+Wed, 22 Mar 2023 20:48:30 GMT
+
+_Version update only_
+
+## 0.2.4
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
+
+## 0.2.3
+Sat, 11 Mar 2023 01:24:51 GMT
+
+_Version update only_
## 0.2.2
Fri, 10 Feb 2023 01:18:50 GMT
diff --git a/webpack/hashed-folder-copy-plugin/package.json b/webpack/hashed-folder-copy-plugin/package.json
index 48f495513f0..c6c9f9ea4d3 100644
--- a/webpack/hashed-folder-copy-plugin/package.json
+++ b/webpack/hashed-folder-copy-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/hashed-folder-copy-plugin",
- "version": "0.2.2",
+ "version": "0.2.6",
"description": "Webpack plugin for copying a folder to the output directory with a hash in the folder name.",
"typings": "dist/hashed-folder-copy-plugin.d.ts",
"main": "lib/index.js",
diff --git a/webpack/loader-load-themed-styles/CHANGELOG.json b/webpack/loader-load-themed-styles/CHANGELOG.json
index f79ba0d5fa2..07ef214658b 100644
--- a/webpack/loader-load-themed-styles/CHANGELOG.json
+++ b/webpack/loader-load-themed-styles/CHANGELOG.json
@@ -1,6 +1,42 @@
{
"name": "@microsoft/loader-load-themed-styles",
"entries": [
+ {
+ "version": "2.0.29",
+ "tag": "@microsoft/loader-load-themed-styles_v2.0.29",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.31`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.30` to `^2.0.31`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "2.0.28",
+ "tag": "@microsoft/loader-load-themed-styles_v2.0.28",
+ "date": "Sat, 11 Mar 2023 01:24:51 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.30`"
+ },
+ {
+ "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.29` to `^2.0.30`"
+ }
+ ]
+ }
+ },
{
"version": "2.0.27",
"tag": "@microsoft/loader-load-themed-styles_v2.0.27",
diff --git a/webpack/loader-load-themed-styles/CHANGELOG.md b/webpack/loader-load-themed-styles/CHANGELOG.md
index a584f37099f..1c06ef25de1 100644
--- a/webpack/loader-load-themed-styles/CHANGELOG.md
+++ b/webpack/loader-load-themed-styles/CHANGELOG.md
@@ -1,6 +1,16 @@
# Change Log - @microsoft/loader-load-themed-styles
-This log was last generated on Fri, 10 Feb 2023 01:18:50 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 2.0.29
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
+
+## 2.0.28
+Sat, 11 Mar 2023 01:24:51 GMT
+
+_Version update only_
## 2.0.27
Fri, 10 Feb 2023 01:18:50 GMT
diff --git a/webpack/loader-load-themed-styles/package.json b/webpack/loader-load-themed-styles/package.json
index 583103541aa..7d68bd6967f 100644
--- a/webpack/loader-load-themed-styles/package.json
+++ b/webpack/loader-load-themed-styles/package.json
@@ -1,6 +1,6 @@
{
"name": "@microsoft/loader-load-themed-styles",
- "version": "2.0.27",
+ "version": "2.0.29",
"description": "This simple loader wraps the loading of CSS in script equivalent to `require('load-themed-styles').loadStyles( /* css text */ )`. It is designed to be a replacement for style-loader.",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
@@ -22,7 +22,7 @@
},
"peerDependencies": {
"@types/webpack": "^4",
- "@microsoft/load-themed-styles": "^2.0.29"
+ "@microsoft/load-themed-styles": "^2.0.31"
},
"dependencies": {
"loader-utils": "1.4.2"
diff --git a/webpack/loader-raw-script/CHANGELOG.json b/webpack/loader-raw-script/CHANGELOG.json
index fa50df989c7..653263b11b1 100644
--- a/webpack/loader-raw-script/CHANGELOG.json
+++ b/webpack/loader-raw-script/CHANGELOG.json
@@ -1,6 +1,21 @@
{
"name": "@rushstack/loader-raw-script",
"entries": [
+ {
+ "version": "1.3.282",
+ "tag": "@rushstack/loader-raw-script_v1.3.282",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
{
"version": "1.3.281",
"tag": "@rushstack/loader-raw-script_v1.3.281",
diff --git a/webpack/loader-raw-script/CHANGELOG.md b/webpack/loader-raw-script/CHANGELOG.md
index 0f05e112fe5..e3128d0bc00 100644
--- a/webpack/loader-raw-script/CHANGELOG.md
+++ b/webpack/loader-raw-script/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/loader-raw-script
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 1.3.282
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 1.3.281
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/webpack/loader-raw-script/package.json b/webpack/loader-raw-script/package.json
index 21ee33e3b32..0e9a4e02ef6 100644
--- a/webpack/loader-raw-script/package.json
+++ b/webpack/loader-raw-script/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/loader-raw-script",
- "version": "1.3.281",
+ "version": "1.3.282",
"description": "",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
diff --git a/webpack/preserve-dynamic-require-plugin/CHANGELOG.json b/webpack/preserve-dynamic-require-plugin/CHANGELOG.json
index 06a4e73b551..afaa9e04594 100644
--- a/webpack/preserve-dynamic-require-plugin/CHANGELOG.json
+++ b/webpack/preserve-dynamic-require-plugin/CHANGELOG.json
@@ -1,6 +1,21 @@
{
"name": "@rushstack/webpack-preserve-dynamic-require-plugin",
"entries": [
+ {
+ "version": "0.10.4",
+ "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.4",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
{
"version": "0.10.3",
"tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.3",
diff --git a/webpack/preserve-dynamic-require-plugin/CHANGELOG.md b/webpack/preserve-dynamic-require-plugin/CHANGELOG.md
index c20366f25c6..55c82080f06 100644
--- a/webpack/preserve-dynamic-require-plugin/CHANGELOG.md
+++ b/webpack/preserve-dynamic-require-plugin/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/webpack-preserve-dynamic-require-plugin
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.10.4
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 0.10.3
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/webpack/preserve-dynamic-require-plugin/package.json b/webpack/preserve-dynamic-require-plugin/package.json
index 5c71f7164bd..3bf260bd835 100644
--- a/webpack/preserve-dynamic-require-plugin/package.json
+++ b/webpack/preserve-dynamic-require-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/webpack-preserve-dynamic-require-plugin",
- "version": "0.10.3",
+ "version": "0.10.4",
"description": "This plugin tells webpack to leave dynamic calls to \"require\" as-is instead of trying to bundle them.",
"main": "lib/index.js",
"typings": "dist/webpack-preserve-dynamic-require-plugin.d.ts",
diff --git a/webpack/set-webpack-public-path-plugin/CHANGELOG.json b/webpack/set-webpack-public-path-plugin/CHANGELOG.json
index 72663958f0c..15f66834c00 100644
--- a/webpack/set-webpack-public-path-plugin/CHANGELOG.json
+++ b/webpack/set-webpack-public-path-plugin/CHANGELOG.json
@@ -1,6 +1,63 @@
{
"name": "@rushstack/set-webpack-public-path-plugin",
"entries": [
+ {
+ "version": "3.3.95",
+ "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.95",
+ "date": "Thu, 23 Mar 2023 15:24:08 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.1`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "3.3.94",
+ "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.94",
+ "date": "Wed, 22 Mar 2023 20:48:30 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.0`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "3.3.93",
+ "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.93",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.57`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.1`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "3.3.92",
+ "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.92",
+ "date": "Sat, 11 Mar 2023 01:24:51 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.0`"
+ }
+ ]
+ }
+ },
{
"version": "3.3.91",
"tag": "@rushstack/set-webpack-public-path-plugin_v3.3.91",
diff --git a/webpack/set-webpack-public-path-plugin/CHANGELOG.md b/webpack/set-webpack-public-path-plugin/CHANGELOG.md
index d2d867a21c5..ff6fe30915c 100644
--- a/webpack/set-webpack-public-path-plugin/CHANGELOG.md
+++ b/webpack/set-webpack-public-path-plugin/CHANGELOG.md
@@ -1,6 +1,26 @@
# Change Log - @rushstack/set-webpack-public-path-plugin
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Thu, 23 Mar 2023 15:24:08 GMT and should not be manually modified.
+
+## 3.3.95
+Thu, 23 Mar 2023 15:24:08 GMT
+
+_Version update only_
+
+## 3.3.94
+Wed, 22 Mar 2023 20:48:30 GMT
+
+_Version update only_
+
+## 3.3.93
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
+
+## 3.3.92
+Sat, 11 Mar 2023 01:24:51 GMT
+
+_Version update only_
## 3.3.91
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/webpack/set-webpack-public-path-plugin/package.json b/webpack/set-webpack-public-path-plugin/package.json
index 8bf3a01ebcf..8666be9e318 100644
--- a/webpack/set-webpack-public-path-plugin/package.json
+++ b/webpack/set-webpack-public-path-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/set-webpack-public-path-plugin",
- "version": "3.3.91",
+ "version": "3.3.95",
"description": "This plugin sets the webpack public path at runtime.",
"main": "lib/index.js",
"typings": "dist/set-webpack-public-path-plugin.d.ts",
diff --git a/webpack/webpack-embedded-dependencies-plugin/.eslintrc.js b/webpack/webpack-embedded-dependencies-plugin/.eslintrc.js
new file mode 100644
index 00000000000..4c934799d67
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/.eslintrc.js
@@ -0,0 +1,10 @@
+// This is a workaround for https://github.com/eslint/eslint/issues/3458
+require('@rushstack/eslint-config/patch/modern-module-resolution');
+
+module.exports = {
+ extends: [
+ '@rushstack/eslint-config/profile/node-trusted-tool',
+ '@rushstack/eslint-config/mixins/friendly-locals'
+ ],
+ parserOptions: { tsconfigRootDir: __dirname }
+};
diff --git a/webpack/webpack-embedded-dependencies-plugin/.npmignore b/webpack/webpack-embedded-dependencies-plugin/.npmignore
new file mode 100644
index 00000000000..302dbc5b019
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/.npmignore
@@ -0,0 +1,30 @@
+# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO.
+
+# Ignore all files by default, to avoid accidentally publishing unintended files.
+*
+
+# Use negative patterns to bring back the specific things we want to publish.
+!/bin/**
+!/lib/**
+!/lib-*/**
+!/dist/**
+!ThirdPartyNotice.txt
+
+# Ignore certain patterns that should not get published.
+/dist/*.stats.*
+/lib/**/test/
+/lib-*/**/test/
+*.test.js
+
+# NOTE: These don't need to be specified, because NPM includes them automatically.
+#
+# package.json
+# README (and its variants)
+# CHANGELOG (and its variants)
+# LICENSE / LICENCE
+
+#--------------------------------------------
+# DO NOT MODIFY THE TEMPLATE ABOVE THIS LINE
+#--------------------------------------------
+
+# (Add your project-specific overrides here)
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/CHANGELOG.json b/webpack/webpack-embedded-dependencies-plugin/CHANGELOG.json
new file mode 100644
index 00000000000..65ca65c8070
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/CHANGELOG.json
@@ -0,0 +1,34 @@
+{
+ "name": "@rushstack/webpack-embedded-dependencies-plugin",
+ "entries": [
+ {
+ "version": "0.1.1",
+ "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.1",
+ "date": "Thu, 23 Mar 2023 15:24:08 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.1`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.1.0",
+ "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.0",
+ "date": "Wed, 22 Mar 2023 20:48:30 GMT",
+ "comments": {
+ "minor": [
+ {
+ "comment": "Introduce webpack-embedded-dependencies-plugin"
+ }
+ ],
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.0`"
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/webpack/webpack-embedded-dependencies-plugin/CHANGELOG.md b/webpack/webpack-embedded-dependencies-plugin/CHANGELOG.md
new file mode 100644
index 00000000000..3608b30a615
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/CHANGELOG.md
@@ -0,0 +1,16 @@
+# Change Log - @rushstack/webpack-embedded-dependencies-plugin
+
+This log was last generated on Thu, 23 Mar 2023 15:24:08 GMT and should not be manually modified.
+
+## 0.1.1
+Thu, 23 Mar 2023 15:24:08 GMT
+
+_Version update only_
+
+## 0.1.0
+Wed, 22 Mar 2023 20:48:30 GMT
+
+### Minor changes
+
+- Introduce webpack-embedded-dependencies-plugin
+
diff --git a/webpack/webpack-embedded-dependencies-plugin/README.md b/webpack/webpack-embedded-dependencies-plugin/README.md
new file mode 100644
index 00000000000..f8d063611d6
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/README.md
@@ -0,0 +1,127 @@
+# webpack-embedded-dependencies-plugin
+
+## Installation
+
+`npm install @rushstack/webpack-embedded-dependencies-plugin --save`
+
+## Overview
+
+A webpack plugin for generating a list of embedded dependencies. Embedded dependencies are third-party packages which are being
+bundled into your released code and are oftentimes subject to license, security, and other legal requirements. This plugin
+aims to make it easier to generate a list of embedded dependencies and their associated metadata, so they can be analyzed by additional tools.
+
+The plugin also includes the ability to generate a secondary asset which contains the license text for each embedded dependency into a single file called
+THIRD-PARTY-NOTICES.html. This is a common legal requirement when deploying services or products containing open-source code.
+
+## Plugin
+
+```typescript
+// webpack.config.js
+import EmbeddedDependenciesWebpackPlugin from '@rushstack/webpack-embedded-dependencies-plugin';
+
+export default () => {
+ /*...*/
+ plugins: [
+ new EmbeddedDependenciesWebpackPlugin( /* options */ )
+ ]
+}
+```
+
+## Options
+
+### `outputFileName`: `string`
+
+Name of the file to be generated. Defaults to embedded-dependencies.json
+
+```typescript
+new EmbeddedDependenciesWebpackPlugin({
+ outputFileName: 'my-custom-file-name.json'
+})
+```
+
+### `generateLicenseFile`: `boolean`
+
+Whether to generate a license file. Defaults to false and will only generate the embedded-dependencies.json file
+
+```typescript
+new EmbeddedDependenciesWebpackPlugin({
+ generateLicenseFile: true
+})
+```
+
+### `generateLicenseFileFunction`: `LicenseFileGeneratorFunction`
+
+Function that generates the license file. Defaults to the plugin's internal default generator function but allows you to override it.
+
+```typescript
+new EmbeddedDependenciesWebpackPlugin({
+ generateLicenseFile: true,
+ generateLicenseFileFunction: (packages: IPackageData[]): string => {
+ return packages
+ .map((pkg) => {
+ return `${pkg.name}
${pkg.license}
`;
+ }).join('');
+ }
+})
+```
+
+### `generatedLicenseFilename`: `LicenseFileName`
+
+```typescript
+new EmbeddedDependenciesWebpackPlugin({
+ generateLicenseFile: true,
+ generatedLicenseFilename: 'custom-license-file-name.html'
+})
+```
+
+Name of the generated license file. Defaults to THIRD-PARTY-NOTICES.html but can be customized to any name you want.
+
+### `packageFilterPredicate`: `(packageJson: IPackageData, filePath: string) => boolean`
+
+Function that allows you to filter out packages that you don't want to include in any generated files.
+
+```typescript
+new EmbeddedDependenciesWebpackPlugin({
+ packageFilterPredicate: (packageJson: IPackageData, filePath: string): boolean => {
+ return packageJson.name !== 'my-package-to-exclude';
+ }
+})
+```
+
+## Types
+
+### `LicenseFileGeneratorFunction`
+
+`export declare type LicenseFileGeneratorFunction = (packages: IPackageData[]) => string;`
+
+Function type that generates the license file.
+
+```ts
+const licenseFileGenerator: LicenseFileGeneratorFunction = (packages: IPackageData[]): string => {
+ return packages
+ .map((pkg) => {
+ return `${pkg.name}
${pkg.license}
`;
+ }).join('');
+}
+```
+
+### `LicenseFileName`
+
+``export declare type LicenseFileName = `${string}.${'html' | 'md' | 'txt'}`;``
+
+Loose string type that represents the name of the generated license file. The string must have at least one character and must end with one of the following file extensions: html, md, or txt or else you'll receive a TypeScript error.
+
+```ts
+const licenseFileName: LicenseFileName = 'custom-license-file-name.html';
+const licenseMarkdownFileName: LicenseFileName = 'custom-license-file-name.md';
+const licenseTextFileName: LicenseFileName = 'custom-license-file-name.txt';
+```
+
+
+## Links
+
+- [CHANGELOG.md](
+ https://github.com/microsoft/rushstack/blob/main/webpack/webpack-embedded-dependencies-plugin/CHANGELOG.md) - Find
+ out what's new in the latest version
+
+`@rushstack/webpack-embedded-dependencies-plugin` is part of the [Rush Stack](https://rushstack.io/) family of projects.
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/config/api-extractor.json b/webpack/webpack-embedded-dependencies-plugin/config/api-extractor.json
new file mode 100644
index 00000000000..31010bc6261
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/config/api-extractor.json
@@ -0,0 +1,19 @@
+{
+ "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
+
+ "mainEntryPointFilePath": "/lib/index.d.ts",
+
+ "apiReport": {
+ "enabled": true,
+ "reportFolder": "../../../common/reviews/api"
+ },
+
+ "docModel": {
+ "enabled": true
+ },
+
+ "dtsRollup": {
+ "enabled": true,
+ "betaTrimmedFilePath": "/dist/.d.ts"
+ }
+}
diff --git a/webpack/webpack-embedded-dependencies-plugin/config/rig.json b/webpack/webpack-embedded-dependencies-plugin/config/rig.json
new file mode 100644
index 00000000000..6ac88a96368
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/config/rig.json
@@ -0,0 +1,7 @@
+{
+ // The "rig.json" file directs tools to look for their config files in an external package.
+ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package
+ "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
+
+ "rigPackageName": "@rushstack/heft-node-rig"
+}
diff --git a/webpack/webpack-embedded-dependencies-plugin/package.json b/webpack/webpack-embedded-dependencies-plugin/package.json
new file mode 100644
index 00000000000..255a5f25f26
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/package.json
@@ -0,0 +1,40 @@
+{
+ "name": "@rushstack/webpack-embedded-dependencies-plugin",
+ "version": "0.1.1",
+ "description": "This plugin analyzes bundled dependencies from Node Modules for use with Component Governance and License Scanning.",
+ "main": "lib/index.js",
+ "typings": "dist/webpack-embedded-dependencies-plugin.d.ts",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/microsoft/rushstack.git",
+ "directory": "webpack/webpack-embedded-dependencies-plugin"
+ },
+ "scripts": {
+ "build": "heft build --clean",
+ "test": "heft test --no-build",
+ "_phase:build": "heft build --clean",
+ "_phase:test": "heft test --no-build"
+ },
+ "dependencies": {
+ "@rushstack/node-core-library": "workspace:*"
+ },
+ "peerDependencies": {
+ "webpack": "^5.35.1"
+ },
+ "peerDependenciesMeta": {
+ "webpack": {
+ "optional": true
+ }
+ },
+ "devDependencies": {
+ "@rushstack/webpack-plugin-utilities": "workspace:*",
+ "@rushstack/eslint-config": "workspace:*",
+ "@rushstack/heft": "workspace:*",
+ "@rushstack/heft-node-rig": "workspace:*",
+ "@types/heft-jest": "1.0.1",
+ "@types/node": "14.18.36",
+ "webpack": "~5.75.0",
+ "memfs": "3.4.3"
+ }
+}
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/EmbeddedDependenciesWebpackPlugin.ts b/webpack/webpack-embedded-dependencies-plugin/src/EmbeddedDependenciesWebpackPlugin.ts
new file mode 100644
index 00000000000..3cf9db901b8
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/EmbeddedDependenciesWebpackPlugin.ts
@@ -0,0 +1,386 @@
+import path from 'path';
+import { Async, Sort, LegacyAdapters, FileSystem } from '@rushstack/node-core-library';
+
+import type { Compiler, Compilation, WebpackPluginInstance, WebpackError } from 'webpack';
+import type { IPackageJson } from '@rushstack/node-core-library';
+
+import { LICENSE_FILES_REGEXP, COPYRIGHT_REGEX } from './regexpUtils';
+
+const PLUGIN_NAME: 'EmbeddedDependenciesWebpackPlugin' = 'EmbeddedDependenciesWebpackPlugin';
+const PLUGIN_ERROR_PREFIX: string = '[embedded-dependencies-webpack-plugin]';
+const DEFAULT_GENERATED_LICENSE_FILE_NAME: 'THIRD-PARTY-NOTICES.html' = 'THIRD-PARTY-NOTICES.html';
+const DEFAULT_EMBEDDED_DEPENDENCIES_FILE_NAME: 'embedded-dependencies.json' = 'embedded-dependencies.json';
+const DEFAULT_PACKAGE_FILTER_FUNCTION: (packageJson: IPackageData, filePath: string) => boolean = () => true;
+
+interface IEmbeddedDependenciesFile {
+ name?: string;
+ version?: string;
+ embeddedDependencies: IPackageData[];
+}
+
+interface IResourceResolveData {
+ descriptionFileData?: IPackageData;
+ descriptionFileRoot?: string;
+ relativePath?: string;
+}
+
+interface IWebpackModuleCreateData {
+ resourceResolveData?: IResourceResolveData;
+}
+
+/**
+ * @beta
+ * Data type for a package.json file. This is a superset of the full package.json file and includes additional fields
+ * that are generated by the plugin, including licenseSource, licenses, copyright, and author.
+ */
+export interface IPackageData extends IPackageJson {
+ /**
+ * A small string subset which is used for copyright extraction from a licenseSource file.
+ */
+ copyright: string | undefined;
+ /**
+ * The author of the package. This is a superset of the full package.json author field.
+ * Grabs either the author field or author.name field from package.json.
+ */
+ author?: string | { name?: string };
+ /**
+ * Additional license metadata if present. May contain information about a project which has multiple licenses.
+ */
+ licenses?: { type: string; url: string }[];
+
+ /**
+ * The source of the license file itself used for generating THIRD-PARTY-NOTICES.html or custom license files.
+ */
+ licenseSource?: string;
+}
+
+/**
+ * @beta
+ * Plugin options for EmbeddedDependenciesWebpackPlugin
+ *
+ * @param outputFileName - Name of the file to be generated. Defaults to embedded-dependencies.json
+ * @param generateLicenseFile - Whether to generate a license file. Defaults to false and will only generate the embedded-dependencies.json file
+ * @param generateLicenseFileFunction - Function that generates the license file. Defaults to the plugin's internal default generator function but allows you to override it
+ * @param generatedLicenseFilename - Name of the generated license file. Defaults to THIRD-PARTY-NOTICES.html
+ *
+ * @example
+ * ```ts
+ * // webpack.config.js
+ * plugins: [
+ * new EmbeddedDependenciesWebpackPlugin({
+ * outputFileName: 'custom-file-name.json',
+ * generateLicenseFile: true,
+ * generateLicenseFileFunction: (packages: IPackageData[]) => {
+ * return packages
+ * .map((pkg) => {
+ * return `${pkg.name}
${pkg.license}
`;
+ * }).join('');
+ * },
+ * generatedLicenseFilename: 'custom-license-file-name.html'
+ * })
+ * ]
+ * ```
+ */
+export interface IEmbeddedDependenciesWebpackPluginOptions {
+ /**
+ * Name of the file to be generated. Defaults to embedded-dependencies.json
+ */
+ outputFileName?: string;
+ /**
+ * Whether to generate a license file. Defaults to false and will only generate the embedded-dependencies.json file
+ */
+ generateLicenseFile?: boolean;
+ /**
+ * Function that generates the license file. Defaults to the plugin's internal default generator function but allows you to override it
+ */
+ generateLicenseFileFunction?: LicenseFileGeneratorFunction;
+ /**
+ * Name of the generated license file. Defaults to THIRD-PARTY-NOTICES.html
+ */
+ generatedLicenseFilename?: LicenseFileName;
+
+ /**
+ * Predicate function that determines whether a package should be included in the embedded
+ * dependencies file or the generated license file.
+ */
+ packageFilterPredicate?: (packageJson: IPackageData, filePath: string) => boolean;
+}
+
+/**
+ * @beta
+ * Function type that generates the license file.
+ *
+ * @example
+ * ```ts
+ * const licenseFileGenerator: LicenseFileGeneratorFunction = (packages: IPackageData[]): string => {
+ * return packages
+ * .map((pkg) => {
+ * return `${pkg.name}
${pkg.license}
`;
+ * }).join('');
+ * }
+ * ```
+ */
+export type LicenseFileGeneratorFunction = (packages: IPackageData[]) => string;
+
+/**
+ * @beta
+ * Loose string type that represents the name of the generated license file.
+ *
+ * @example
+ * ```ts
+ * const licenseFileName: LicenseFileName = 'custom-license-file-name.html';
+ * const licenseMarkdownFileName: LicenseFileName = 'custom-license-file-name.md';
+ * const licenseTextFileName: LicenseFileName = 'custom-license-file-name.txt';
+ * ```
+ */
+export type LicenseFileName = `${string}.${'html' | 'md' | 'txt'}`;
+
+type PackageNameAndVersion = `${string}@${string}`;
+type ThirdPartyPackageMap = Map<
+ PackageNameAndVersion,
+ { packageFolderPath: string; packageJsonData: IPackageData }
+>;
+type DefaultLicenseTemplate = `
${string}
${string}`;
+
+/**
+ * @beta
+ * Webpack plugin that generates a file with the list of embedded dependencies
+ * 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;
+
+ 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;
+ }
+
+ /**
+ * @beta
+ * Webpack plugin apply method. This method is called by the webpack compiler to apply the plugin, however it not usually
+ * needed to be invoked manually by the developer in a webpack configuration. However, if you are calling this plugin (applying it from another plugin)
+ * you can call `plugin.apply(compiler)` to apply the plugin and invoke it.
+ * @param compiler - The webpack compiler instance.
+ */
+ public apply(compiler: Compiler): void {
+ const { sources, Compilation } = compiler.webpack;
+ // Tap into compilation so we can tap into compilation.hooks.processAssets
+ compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation, { normalModuleFactory }) => {
+ const thirdPartyPackages: ThirdPartyPackageMap = new Map();
+
+ normalModuleFactory.hooks.module.tap(
+ PLUGIN_NAME,
+ (module, moduleCreateData: IWebpackModuleCreateData, resolveData) => {
+ const { resourceResolveData } = moduleCreateData;
+ const pkg: IPackageData | undefined = resourceResolveData?.descriptionFileData;
+ const filePath: string | undefined = resourceResolveData?.descriptionFileRoot;
+
+ if (
+ pkg &&
+ filePath &&
+ this._packageFilterFunction(pkg, filePath) &&
+ filePath?.includes('node_modules')
+ ) {
+ const key: PackageNameAndVersion = makePackageMapKeyForPackage(pkg);
+ thirdPartyPackages.set(key, { packageFolderPath: filePath, packageJsonData: pkg });
+ }
+
+ return module;
+ }
+ );
+
+ compilation.hooks.processAssets.tapPromise(
+ { name: PLUGIN_NAME, stage: Compilation.PROCESS_ASSETS_STAGE_REPORT },
+ async (assets) => {
+ const packages: IPackageData[] = [];
+
+ try {
+ await Async.forEachAsync(
+ thirdPartyPackages,
+ async ([, { packageFolderPath: dir, packageJsonData: data }]) => {
+ const { name, version } = data;
+ let licenseSource: string | undefined;
+ const license: string | undefined = parseLicense(data);
+ 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);
+
+ packages.push({
+ name,
+ version,
+ license,
+ licenseSource,
+ copyright
+ });
+ } else {
+ // If there is no license file path, we still should populate the other required fields
+ const copyright: string | undefined = parsePackageAuthor(data);
+
+ packages.push({
+ name,
+ version,
+ license,
+ copyright
+ });
+ }
+ }
+ );
+ } catch (error) {
+ this._emitWebpackError(compilation, 'Failed to process embedded dependencies', error);
+ } finally {
+ Sort.sortBy(packages, (pkg) => pkg.name);
+ }
+
+ const dataToStringify: IEmbeddedDependenciesFile = {
+ embeddedDependencies: packages
+ };
+
+ compilation.emitAsset(this._outputFileName, new sources.RawSource(JSON.stringify(dataToStringify)));
+
+ 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))
+ );
+ } catch (error: unknown) {
+ this._emitWebpackError(compilation, 'Failed to generate license file', error);
+ }
+ }
+
+ return;
+ }
+ );
+ });
+ }
+
+ /**
+ * Default error handler for try/catch blocks in the plugin
+ * try/catches emit errors of type `unknown` and we need to handle them based on what
+ * type the error is. This function provides a convenient way to handle errors and then
+ * propagate them to webpack as WebpackError objects on `compilation.errors` array.
+ *
+ * @remarks
+ * _If we need to push errors to `compilation.warnings` array, we should just create a companion function
+ * that does the same thing but pushes to `compilation.warnings` array instead._
+ *
+ * @example
+ * ```typescript
+ * try {
+ * // do some operation
+ * FileSystem.readFile('some-file');
+ * } catch (error: unknown) {
+ * this._emitWebpackError(compilation, 'Failed to do some operation', error);
+ * }
+ * ```
+ */
+ private _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
+ if (typeof error === 'string') {
+ emittedError = new WebpackError(`${PLUGIN_ERROR_PREFIX}: ${errorMessage}: ${error}`);
+ // If error is an instance of Error, we can emit it with message prefix, error message and stack trace
+ } else if (error instanceof Error) {
+ emittedError = new WebpackError(
+ `${PLUGIN_ERROR_PREFIX}: ${errorMessage}: ${error.message}\n${error.stack || ''}`
+ );
+ // If error is not a string or an instance of Error, we can emit it with message prefix and error message and JSON.stringify it
+ } else {
+ emittedError = new WebpackError(
+ `${PLUGIN_ERROR_PREFIX}: ${errorMessage}: ${JSON.stringify(error || '')}`
+ );
+ }
+
+ compilation.errors.push(emittedError);
+ }
+
+ /**
+ * Searches a third party package directory for a license file.
+ */
+ private async _getLicenseFilePathAsync(
+ modulePath: string,
+ compiler: Compiler
+ ): Promise {
+ type InputFileSystemReadDirResults = Parameters<
+ Parameters[1]
+ >[1];
+
+ // TODO: Real fs.readdir can take an arguement ({ withFileTypes: true }) which will filter out directories for better performance
+ // and return a list of Dirent objects. Currently the webpack types are hand generated for fs.readdir so
+ // we can't use this feature yet, or we would have to cast the types of inputFileSystem.readdir.
+ // https://github.com/webpack/webpack/issues/16780 tracks this issue.
+ const files: InputFileSystemReadDirResults = await LegacyAdapters.convertCallbackToPromise(
+ compiler.inputFileSystem.readdir,
+ modulePath
+ );
+
+ return files
+ ?.map((file) => file.toString())
+ .filter((file) => LICENSE_FILES_REGEXP.test(file))
+ .map((file) => path.join(modulePath, file))[0]; // Grabbing the first license file if multiple are found
+ }
+
+ /**
+ * Given a module path, try to parse the module's copyright attribution.
+ */
+ private _parseCopyright(licenseSource: string): string | undefined {
+ const match: RegExpMatchArray | null = licenseSource.match(COPYRIGHT_REGEX);
+
+ if (match) {
+ return match[0];
+ }
+
+ return undefined;
+ }
+
+ private _defaultLicenseFileGenerator(packages: IPackageData[]): string {
+ const licenseContent = (pkg: IPackageData): string =>
+ pkg.licenseSource || pkg.copyright || 'License or Copyright not found';
+
+ const licenseTemplateForPackage = (pkg: IPackageData): DefaultLicenseTemplate => {
+ return `
${pkg.name} - ${pkg.version}
${licenseContent(pkg)}`;
+ };
+
+ return packages.map(licenseTemplateForPackage).join('\n');
+ }
+}
+
+function makePackageMapKeyForPackage(pkg: IPackageData): PackageNameAndVersion {
+ return `${pkg.name}@${pkg.version}`;
+}
+
+/**
+ * Returns the license type
+ */
+function parseLicense(packageData: IPackageData): string | undefined {
+ if (packageData.license) {
+ return packageData.license;
+ } else if (typeof packageData.licenses === 'string') {
+ return packageData.licenses;
+ } else if (packageData.licenses?.length) {
+ return packageData.licenses.length === 1
+ ? packageData.licenses[0].type
+ : `(${packageData.licenses
+ .map((license: { type: string; url: string }) => license.type)
+ .join(' OR ')})`;
+ }
+
+ return undefined;
+}
+
+function parsePackageAuthor(p: IPackageData): string | undefined {
+ return typeof p.author === 'string' ? p.author : p.author?.name;
+}
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/index.ts b/webpack/webpack-embedded-dependencies-plugin/src/index.ts
new file mode 100644
index 00000000000..db7fe20598d
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/index.ts
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
+// See LICENSE in the project root for license information.
+
+/**
+ * A webpack plugin for generating a list of embedded dependencies. Embedded dependencies are third-party packages which are being
+ * bundled into your released code and are often times subject to license, security, and other legal requirements. This plugin
+ * aims to make it easier to generate a list of embedded dependencies and their associated metadata, so they can be analyzed by additional tools.
+ *
+ * @remarks
+ * The plugin also includes the ability to generate a secondary asset which contains the license text for each embedded dependency into a single file called
+ * THIRD-PARTY-NOTICES.html. This is a common legal requirement for large companies deploying commercial services/products containing open source code.
+ *
+ * @packageDocumentation
+ */
+
+import EmbeddedDependenciesWebpackPlugin from './EmbeddedDependenciesWebpackPlugin';
+export * from './EmbeddedDependenciesWebpackPlugin';
+
+export default EmbeddedDependenciesWebpackPlugin;
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/regexpUtils.ts b/webpack/webpack-embedded-dependencies-plugin/src/regexpUtils.ts
new file mode 100644
index 00000000000..bf9eda8e0c0
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/regexpUtils.ts
@@ -0,0 +1,26 @@
+/**
+ * Regular expression used to match common license file names.
+ *
+ * @remarks The following file names are covered via unit tests to be matched:
+ *
+ * - `'LICENSE'`
+ * - `'LICENSE.txt'`
+ * - `'LICENSE.md'`
+ * - `'LICENSE-MIT.txt'`
+ * - `'license'`
+ * - `'license.txt'`
+ */
+export const LICENSE_FILES_REGEXP: RegExp = /^LICENSE(-[A-Z-]+)?(\.(txt|md))?$/i;
+
+/**
+ * Regular expression used to match common copyright statements. It is by no means exhaustive however it
+ * should cover the majority of cases that we come across in the wild.
+ *
+ * @remarks The following copyright statements are covered via unit tests to be matched:
+ *
+ * - `'Copyright © 2023 FAKE-PACKAGE-MIT-LICENSE'`
+ * - `'Copyright (C) 2007 Free Software Foundation, Inc. '`
+ * - `'Copyright 2023 Some Licenser Name'`
+ *
+ */
+export const COPYRIGHT_REGEX: RegExp = /Copyright\s*(\(c\)|©)?\s*\d{4}\s*.*$/im;
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/.gitignore b/webpack/webpack-embedded-dependencies-plugin/src/test/.gitignore
new file mode 100644
index 00000000000..1b9396ec719
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/.gitignore
@@ -0,0 +1,3 @@
+!node_modules
+!dist
+!lib
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/WebpackEmbeddedDependenciesPlugin.test.ts b/webpack/webpack-embedded-dependencies-plugin/src/test/WebpackEmbeddedDependenciesPlugin.test.ts
new file mode 100644
index 00000000000..17cd9341eed
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/WebpackEmbeddedDependenciesPlugin.test.ts
@@ -0,0 +1,263 @@
+import path from 'path';
+import { createFsFromVolume, IFs, Volume } from 'memfs';
+import EmbeddedDependenciesWebpackPlugin from '../EmbeddedDependenciesWebpackPlugin';
+
+import { LICENSE_FILES_REGEXP, COPYRIGHT_REGEX } from '../regexpUtils';
+
+import { Testing } from '@rushstack/webpack-plugin-utilities';
+import { FileSystem } from '@rushstack/node-core-library';
+
+const TESTS_FOLDER_PATH: string = `${process.cwd()}/src/test`;
+const FIXTURES_FOLDER_PATH: string = `${TESTS_FOLDER_PATH}/fixtures`;
+const FAKE_NODE_MODULES_FOLDER_PATH: string = `${TESTS_FOLDER_PATH}/node_modules`;
+const VIRTUAL_FILE_SYSTEM_OUTPUT_PATH: string = path.resolve(
+ process.cwd(),
+ '../webpack-embedded-dependencies-plugin/dist'
+);
+
+const fixtures: string[] = FileSystem.readFolderItemNames(FIXTURES_FOLDER_PATH);
+
+const defaultConfigurationWithPlugin = {
+ context: TESTS_FOLDER_PATH,
+ plugins: [new EmbeddedDependenciesWebpackPlugin()]
+};
+
+const defaultConfigurationCustomOutputFileName = {
+ context: TESTS_FOLDER_PATH,
+ plugins: [new EmbeddedDependenciesWebpackPlugin({ outputFileName: 'custom-file-name.json' })]
+};
+
+const configurationWithLicenseFileGenerated = {
+ context: TESTS_FOLDER_PATH,
+ plugins: [new EmbeddedDependenciesWebpackPlugin({ generateLicenseFile: true })]
+};
+
+const configurationWithLicenseFileGeneratedAndCustomPackageFilter = {
+ context: TESTS_FOLDER_PATH,
+ plugins: [
+ new EmbeddedDependenciesWebpackPlugin({
+ generateLicenseFile: true,
+ packageFilterPredicate: (packageJson, filePath) => {
+ return !filePath.includes('some-fake-custom-package');
+ }
+ })
+ ]
+};
+
+describe('COPYRIGHT_REGEX', () => {
+ it('should extract the right copyright from apache 2.0 license', () => {
+ const license = FileSystem.readFile(
+ path.join(FAKE_NODE_MODULES_FOLDER_PATH, 'fake-package-apache-with-copyleft-dep', 'LICENSE.txt')
+ );
+ const match = license.match(COPYRIGHT_REGEX);
+
+ expect(match).toBeDefined();
+ expect(match?.[0]).toBe('Copyright 2023 Fake Package Apache License w/ AGPL Transitive');
+ });
+
+ it('should extract the right copyright from mit license', () => {
+ const license = FileSystem.readFile(
+ path.join(FAKE_NODE_MODULES_FOLDER_PATH, 'fake-package-mit-license', 'LICENSE-MIT.txt')
+ );
+ const match = license.match(COPYRIGHT_REGEX);
+
+ expect(match).toBeDefined();
+ expect(match?.[0]).toBe('Copyright © 2023 FAKE-PACKAGE-MIT-LICENSE');
+ });
+
+ it('should extract the right copyright from agpl license', () => {
+ const license = FileSystem.readFile(
+ path.join(FAKE_NODE_MODULES_FOLDER_PATH, 'fake-package-agpl-license', 'LICENSE')
+ );
+ const match = license.match(COPYRIGHT_REGEX);
+
+ expect(match).toBeDefined();
+ expect(match?.[0]).toBe('Copyright (C) 2007 Free Software Foundation, Inc. ');
+ });
+
+ it('should extract the right copyright from agpl license', () => {
+ const license = FileSystem.readFile(
+ path.join(FAKE_NODE_MODULES_FOLDER_PATH, 'fake-package-copyleft-license', 'license')
+ );
+ const match = license.match(COPYRIGHT_REGEX);
+
+ expect(match).toBeDefined();
+ expect(match?.[0]).toBe('Copyright (C) 2007 Free Software Foundation, Inc. ');
+ });
+});
+
+describe('LICENSE_FILES_REGEXP', () => {
+ for (const filename of ['LICENSE', 'LICENSE-MIT.txt', 'LICENSE.md', 'LICENSE.txt', 'license']) {
+ it(`should match ${filename}`, () => {
+ expect(LICENSE_FILES_REGEXP.test(filename)).toBe(true);
+ });
+ }
+});
+
+for (const fixture of fixtures) {
+ describe('WebpackEmbeddedDependenciesPlugin', () => {
+ it('should run', async () => {
+ const stats = await Testing.getTestingWebpackCompilerAsync(
+ `./fixtures/${fixture}/src`,
+ defaultConfigurationWithPlugin
+ );
+
+ expect(stats).toBeDefined();
+ });
+
+ it('should generate a secondary asset with the correct default name', async () => {
+ const stats = await Testing.getTestingWebpackCompilerAsync(
+ `./fixtures/${fixture}/src`,
+ defaultConfigurationWithPlugin
+ );
+ const embeddedDepAsset = stats
+ ?.toJson({ all: false, assets: true })
+ .assets?.some((asset) => asset.name === 'embedded-dependencies.json');
+
+ expect(embeddedDepAsset).toBe(true);
+ });
+
+ it('should generate a secondary asset with a custom outputFileName', async () => {
+ const stats = await Testing.getTestingWebpackCompilerAsync(
+ `./fixtures/${fixture}/src`,
+ defaultConfigurationCustomOutputFileName
+ );
+ const embeddedDepAsset = stats
+ ?.toJson({ all: false, assets: true })
+ .assets?.some((asset) => asset.name === 'custom-file-name.json');
+
+ expect(embeddedDepAsset).toBe(true);
+ });
+
+ it('should generate a tertiary asset if generating a license file', async () => {
+ const stats = await Testing.getTestingWebpackCompilerAsync(
+ `./fixtures/${fixture}/src`,
+ configurationWithLicenseFileGenerated
+ );
+ const embeddedDepAsset = stats
+ ?.toJson({ all: false, assets: true })
+ .assets?.some((asset) => asset.name === 'THIRD-PARTY-NOTICES.html');
+
+ // No dependencies fixture should not generate a license file
+ // and emit a warning so we'll exclude it here, but also should test separately
+ if (fixture !== 'no-dependencies') {
+ expect(embeddedDepAsset).toBe(true);
+ }
+ });
+ });
+
+ const virtualFileSystem: IFs = createFsFromVolume(new Volume());
+
+ switch (fixture) {
+ case 'dependencies-with-copyleft-licenses':
+ break;
+ case 'dependencies-with-licenses':
+ break;
+ case 'dependencies-with-transient-copyleft-license':
+ it('should have three files created when using the generator from the entire build with correct default names and the licenses have been correctly detected', async () => {
+ // For this test we'll create the virtual file system and pass it to the Testing.getTestingWebpackCompilerAsync
+ // beacuse we want to reuse it to verify the files generated by the plugin
+
+ await Testing.getTestingWebpackCompilerAsync(
+ `./fixtures/${fixture}/src`,
+ configurationWithLicenseFileGenerated,
+ virtualFileSystem
+ );
+
+ // get files generated from the plugin in the virtual file system
+ const files = virtualFileSystem.readdirSync(VIRTUAL_FILE_SYSTEM_OUTPUT_PATH);
+
+ expect(files).toBeDefined();
+ expect(files.length).toBe(3);
+ // verify the name of each file is correct
+ expect(files).toContain('embedded-dependencies.json');
+ expect(files).toContain('THIRD-PARTY-NOTICES.html');
+ expect(files).toContain('test-bundle.js');
+
+ for (const file of files) {
+ const fileContent = virtualFileSystem.readFileSync(
+ path.join(VIRTUAL_FILE_SYSTEM_OUTPUT_PATH, file.toString()),
+ {
+ encoding: 'utf8'
+ }
+ );
+
+ switch (file) {
+ case 'THIRD-PARTY-NOTICES.html':
+ expect(fileContent).toContain('Apache License');
+ break;
+ case 'embedded-dependencies.json':
+ const json = JSON.parse(fileContent.toString());
+ expect(json).toBeDefined();
+ expect(json.embeddedDependencies).toBeDefined();
+ expect(json.embeddedDependencies.length).toBe(2);
+ expect(json.embeddedDependencies[0].name).toBe('fake-package-apache-with-copyleft-dep');
+ expect(json.embeddedDependencies[0].version).toBe('1.3.4');
+ break;
+ default:
+ break;
+ }
+
+ expect(fileContent).toBeDefined();
+ }
+ });
+ break;
+ case 'no-dependencies':
+ it('should not emit a warning if there are no third party deps but license generation is set to true', async () => {
+ const stats = await Testing.getTestingWebpackCompilerAsync(
+ `./fixtures/${fixture}/src`,
+ configurationWithLicenseFileGenerated
+ );
+
+ const warnings = stats?.toJson({ all: false, warnings: true }).warnings;
+
+ expect(warnings).toBeDefined();
+ expect(warnings?.length).toBe(0);
+ });
+
+ break;
+
+ case 'dependencies-with-dependency-to-filter-out':
+ it('should filter out specific packages using a package filter function option', async () => {
+ // For this test we'll create the virtual file system and pass it to the Testing.getTestingWebpackCompilerAsync
+ // beacuse we want to reuse it to verify the files generated by the plugin
+
+ await Testing.getTestingWebpackCompilerAsync(
+ `./fixtures/${fixture}/src`,
+ configurationWithLicenseFileGeneratedAndCustomPackageFilter,
+ virtualFileSystem
+ );
+
+ // get files generated from the plugin in the virtual file system
+ const files = virtualFileSystem.readdirSync(VIRTUAL_FILE_SYSTEM_OUTPUT_PATH);
+
+ expect(files).toBeDefined();
+ expect(files.length).toBe(3);
+ // verify the name of each file is correct
+ expect(files).toContain('embedded-dependencies.json');
+ expect(files).toContain('THIRD-PARTY-NOTICES.html');
+ expect(files).toContain('test-bundle.js');
+
+ for (const file of files) {
+ const fileContent = virtualFileSystem.readFileSync(
+ path.join(VIRTUAL_FILE_SYSTEM_OUTPUT_PATH, file.toString()),
+ {
+ encoding: 'utf8'
+ }
+ );
+
+ if (file.toString() === 'embedded-dependencies.json') {
+ const { embeddedDependencies } = JSON.parse(fileContent.toString());
+ expect(embeddedDependencies[0].name).not.toBe('some-fake-custom-package');
+ expect(embeddedDependencies).toBeDefined();
+ }
+
+ expect(fileContent).toBeDefined();
+ }
+ });
+
+ break;
+ default:
+ break;
+ }
+}
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-copyleft-licenses/src/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-copyleft-licenses/src/index.js
new file mode 100644
index 00000000000..bf18de462b9
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-copyleft-licenses/src/index.js
@@ -0,0 +1,3 @@
+import mod from 'fake-package-copyleft-license';
+
+console.log(mod);
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-dependency-to-filter-out/src/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-dependency-to-filter-out/src/index.js
new file mode 100644
index 00000000000..aa334daaad9
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-dependency-to-filter-out/src/index.js
@@ -0,0 +1,4 @@
+import mod from 'fake-package-mit-license';
+import * as fakeNamespace from 'some-fake-custom-package';
+
+console.log(pattern1, fakeNamespace);
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-licenses/src/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-licenses/src/index.js
new file mode 100644
index 00000000000..488fe2fdb42
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-licenses/src/index.js
@@ -0,0 +1 @@
+import mod from 'fake-package-mit-license';
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-transient-copyleft-license/src/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-transient-copyleft-license/src/index.js
new file mode 100644
index 00000000000..a02abbea8dd
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-transient-copyleft-license/src/index.js
@@ -0,0 +1,3 @@
+import mod from 'fake-package-apache-with-copyleft-dep';
+
+console.log(mod);
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/file-a.js b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/file-a.js
new file mode 100644
index 00000000000..668268e602d
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/file-a.js
@@ -0,0 +1 @@
+export default 'file-a';
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/file-b.js b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/file-b.js
new file mode 100644
index 00000000000..15118154ccb
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/file-b.js
@@ -0,0 +1 @@
+export default 'file-b';
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/index.js
new file mode 100644
index 00000000000..f7e2705754b
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/index.js
@@ -0,0 +1,4 @@
+import fileA from './file-a';
+import fileB from './file-b';
+
+document.write(`${fileA} + ${fileB}`);
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/LICENSE b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/LICENSE
new file mode 100644
index 00000000000..be3f7b28e56
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/LICENSE
@@ -0,0 +1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+.
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/lib/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/lib/index.js
new file mode 100644
index 00000000000..1342bcda23b
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/lib/index.js
@@ -0,0 +1 @@
+export default "THIS HAS A COPYLEFT LICENSE";
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/package.json b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/package.json
new file mode 100644
index 00000000000..a276468db41
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "fake-package-apgl-license",
+ "version": "1.0.0",
+ "license": "AGPL",
+ "main": "./lib"
+}
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/LICENSE.txt b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/LICENSE.txt
new file mode 100644
index 00000000000..1a638f265e2
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2023 Fake Package Apache License w/ AGPL Transitive
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/lib/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/lib/index.js
new file mode 100644
index 00000000000..1e55461856b
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/lib/index.js
@@ -0,0 +1,3 @@
+import copyLeftCode from "fake-package-agpl-license"
+
+export default `THIS PACKAGE HAS APACHE LICENSE BUT ${copyLeftCode}`
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/package.json b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/package.json
new file mode 100644
index 00000000000..65d3380e0a8
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "fake-package-apache-with-copyleft-dep",
+ "module": "./lib/index.js",
+ "version": "1.3.4",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "fake-package-agpl-license": "1.0.0"
+ }
+}
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/lib/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/lib/index.js
new file mode 100644
index 00000000000..1342bcda23b
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/lib/index.js
@@ -0,0 +1 @@
+export default "THIS HAS A COPYLEFT LICENSE";
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/license b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/license
new file mode 100644
index 00000000000..a824e194d8e
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/license
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C) 2014 Fake Package Maker
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Fake Package Copyleft License Copyright (C) 2014 Fake Package Maker
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and`show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/package.json b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/package.json
new file mode 100644
index 00000000000..513dcb29e81
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "fake-package-copyleft-license",
+ "version": "1.0.0",
+ "license": "GPL",
+ "main": "./lib"
+}
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/LICENSE-MIT.txt b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/LICENSE-MIT.txt
new file mode 100644
index 00000000000..ab23bff8de5
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/LICENSE-MIT.txt
@@ -0,0 +1,8 @@
+The MIT License (MIT)
+Copyright © 2023 FAKE-PACKAGE-MIT-LICENSE
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/lib/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/lib/index.js
new file mode 100644
index 00000000000..fc0fff7f6b5
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/lib/index.js
@@ -0,0 +1 @@
+export default "THIS IS A MODULE WITH MIT LICENSE"
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/package.json b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/package.json
new file mode 100644
index 00000000000..c5e6bc25799
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "fake-package-good-license",
+ "module": "./lib/index.js",
+ "version": "1.1.1",
+ "license": "MIT"
+}
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mpl-license/lib/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mpl-license/lib/index.js
new file mode 100644
index 00000000000..1342bcda23b
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mpl-license/lib/index.js
@@ -0,0 +1 @@
+export default "THIS HAS A COPYLEFT LICENSE";
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mpl-license/package.json b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mpl-license/package.json
new file mode 100644
index 00000000000..05dc8db0933
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mpl-license/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "fake-package-mpl-license",
+ "version": "1.0.0",
+ "license": "MPL",
+ "main": "./lib"
+}
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/1.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/1.js
new file mode 100644
index 00000000000..8f99fabc3a2
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/1.js
@@ -0,0 +1 @@
+module.exports = module.id;
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/2.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/2.js
new file mode 100644
index 00000000000..8f99fabc3a2
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/2.js
@@ -0,0 +1 @@
+module.exports = module.id;
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/index.js
new file mode 100644
index 00000000000..d1ed864551f
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/index.js
@@ -0,0 +1,2 @@
+export * from "./1.js";
+export * from "./2.js";
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/package.json b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/package.json
new file mode 100644
index 00000000000..4f5cfb2e0a7
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "some-fake-custom-package",
+ "version": "1.0.0",
+ "description": "some fake custom package",
+ "main": "lib/index.js"
+}
\ No newline at end of file
diff --git a/webpack/webpack-embedded-dependencies-plugin/tsconfig.json b/webpack/webpack-embedded-dependencies-plugin/tsconfig.json
new file mode 100644
index 00000000000..fbc2f5c0a6c
--- /dev/null
+++ b/webpack/webpack-embedded-dependencies-plugin/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json",
+
+ "compilerOptions": {
+ "types": ["heft-jest", "node"]
+ }
+}
diff --git a/webpack/webpack-plugin-utilities/CHANGELOG.json b/webpack/webpack-plugin-utilities/CHANGELOG.json
index e9924e1225b..0ff05d335a3 100644
--- a/webpack/webpack-plugin-utilities/CHANGELOG.json
+++ b/webpack/webpack-plugin-utilities/CHANGELOG.json
@@ -1,6 +1,45 @@
{
"name": "@rushstack/webpack-plugin-utilities",
"entries": [
+ {
+ "version": "0.2.1",
+ "tag": "@rushstack/webpack-plugin-utilities_v0.2.1",
+ "date": "Thu, 23 Mar 2023 15:24:08 GMT",
+ "comments": {
+ "patch": [
+ {
+ "comment": "Fix an issue where the `Testing` library has a had a hard dependency on `webpack`, but the package declared it as an optional peerDependency."
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.2.0",
+ "tag": "@rushstack/webpack-plugin-utilities_v0.2.0",
+ "date": "Wed, 22 Mar 2023 20:48:30 GMT",
+ "comments": {
+ "minor": [
+ {
+ "comment": "Added Testing.getTestingWebpackCompiler utility function for webpack plugin testing."
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.1.57",
+ "tag": "@rushstack/webpack-plugin-utilities_v0.1.57",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
{
"version": "0.1.56",
"tag": "@rushstack/webpack-plugin-utilities_v0.1.56",
diff --git a/webpack/webpack-plugin-utilities/CHANGELOG.md b/webpack/webpack-plugin-utilities/CHANGELOG.md
index 447d0e24fa6..2868a309917 100644
--- a/webpack/webpack-plugin-utilities/CHANGELOG.md
+++ b/webpack/webpack-plugin-utilities/CHANGELOG.md
@@ -1,6 +1,25 @@
# Change Log - @rushstack/webpack-plugin-utilities
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Thu, 23 Mar 2023 15:24:08 GMT and should not be manually modified.
+
+## 0.2.1
+Thu, 23 Mar 2023 15:24:08 GMT
+
+### Patches
+
+- Fix an issue where the `Testing` library has a had a hard dependency on `webpack`, but the package declared it as an optional peerDependency.
+
+## 0.2.0
+Wed, 22 Mar 2023 20:48:30 GMT
+
+### Minor changes
+
+- Added Testing.getTestingWebpackCompiler utility function for webpack plugin testing.
+
+## 0.1.57
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 0.1.56
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/webpack/webpack-plugin-utilities/README.md b/webpack/webpack-plugin-utilities/README.md
index ffa1d8af3dc..b377c223fbd 100644
--- a/webpack/webpack-plugin-utilities/README.md
+++ b/webpack/webpack-plugin-utilities/README.md
@@ -10,6 +10,8 @@ This is a collection of utilities for writing webpack plugins
# Usage
+## VersionDetection
+
```JavaScript
import { VersionDetection } from "@rushstack/webpack-plugin-utilities"
@@ -38,6 +40,66 @@ class MyExampleWebpackPlugin {
}
```
+## Testing
+
+### `getTestingWebpackCompiler`
+
+```typescript
+
+import { getTestingWebpackCompiler } from "@rushstack/webpack-plugin-utilities"
+
+describe("MyPlugin", () => {
+ it("should run", async () => {
+ const stats = await getTestingWebpackCompiler("./src/index.ts");
+
+ expect(stats).toBeDefined();
+ });
+});
+```
+
+### `getTestingWebpackCompiler` with additional configuration
+
+If you want to pass in additional configuration to the webpack compiler, you can pass it in as the second parameter to `getTestingWebpackCompiler`.
+
+```typescript
+import { getTestingWebpackCompiler } from "@rushstack/webpack-plugin-utilities"
+
+describe("MyPlugin", () => {
+ it("should run", async () => {
+ const stats = await getTestingWebpackCompiler("./src/index.ts", {
+ mode: "production",
+ });
+
+ expect(stats).toBeDefined();
+ });
+});
+```
+
+### `getTestingWebpackCompiler` with virtual filesystem
+
+If you want to be able to read, analyze, access the files written to the memory filesystem,
+you can pass in a memory filesystem instance to the `memFs` parameter.
+
+```typescript
+import { getTestingWebpackCompiler } from "@rushstack/webpack-plugin-utilities"
+import { createFsFromVolume, Volume, IFs } from "memfs"
+import path from "path"
+
+describe("MyPlugin", () => {
+ it("should run", async () => {
+ const virtualFileSystem: IFs = createFsFromVolume(new Volume());
+ const stats = await getTestingWebpackCompiler(
+ `./src/index.ts`,
+ {},
+ virtualFileSystem
+ );
+
+ expect(stats).toBeDefined();
+ expect(virtualFileSystem.existsSync(path.join(__dirname, "dist", "index.js"))).toBe(true);
+ });
+});
+```
+
## Links
- [CHANGELOG.md](
diff --git a/webpack/webpack-plugin-utilities/package.json b/webpack/webpack-plugin-utilities/package.json
index 2661032207b..790bf3bc027 100644
--- a/webpack/webpack-plugin-utilities/package.json
+++ b/webpack/webpack-plugin-utilities/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/webpack-plugin-utilities",
- "version": "0.1.56",
+ "version": "0.2.1",
"description": "This plugin sets the webpack public path at runtime.",
"main": "lib/index.js",
"typings": "dist/webpack-plugin-utilities.d.ts",
@@ -14,6 +14,10 @@
"build": "heft build --clean",
"_phase:build": "heft build --clean"
},
+ "dependencies": {
+ "webpack-merge": "~5.8.0",
+ "memfs": "3.4.3"
+ },
"peerDependencies": {
"@types/webpack": "^4.39.8",
"webpack": "^5.35.1"
diff --git a/webpack/webpack-plugin-utilities/src/Testing.ts b/webpack/webpack-plugin-utilities/src/Testing.ts
new file mode 100644
index 00000000000..bb123e63879
--- /dev/null
+++ b/webpack/webpack-plugin-utilities/src/Testing.ts
@@ -0,0 +1,144 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
+// See LICENSE in the project root for license information.
+
+import { createFsFromVolume, Volume, IFs } from 'memfs';
+import path from 'path';
+import type { StatsCompilation as WebpackStatsCompilation } from 'webpack';
+import webpackMerge from 'webpack-merge';
+
+import type { MultiStats, Stats, Configuration, Compiler, StatsError } from 'webpack';
+
+/**
+ * @public
+ * This function generates a webpack compiler with default configuration and the output filesystem mapped to
+ * a memory filesystem. This is useful for testing webpack plugins/loaders where we do not need to write to disk (which can be costly).
+ * @param entry - The entry point for the webpack compiler
+ * @param additionalConfig - Any additional configuration that should be merged with the default configuration
+ * @param memFs - The memory filesystem to use for the output filesystem. Use this option if you want to _inspect_, analyze, or read the output
+ * files generated by the webpack compiler. If you do not need to do this, you can omit this parameter and the output files.
+ *
+ * @returns - A webpack compiler with the output filesystem mapped to a memory filesystem
+ *
+ * @example
+ * ```typescript
+ * import Testing from '@rushstack/webpack-plugin-utilities';
+ *
+ * describe('MyPlugin', () => {
+ it('should run', async () => {
+ const stats = await Testing.getTestingWebpackCompiler(
+ `./src/index.ts`,
+ );
+
+ expect(stats).toBeDefined();
+ });
+ * });
+ * ```
+ *
+ * @remarks
+ * If you want to be able to read, analyze, access the files written to the memory filesystem,
+ * you can pass in a memory filesystem instance to the `memFs` parameter.
+ *
+ * @example
+ * ```typescript
+ * import Testing from '@rushstack/webpack-plugin-utilities';
+ * import { createFsFromVolume, Volume, IFs } from 'memfs';
+ * import path from 'path';
+ *
+ * describe('MyPlugin', () => {
+ * it('should run', async () => {
+ * const virtualFileSystem: IFs = createFsFromVolume(new Volume());
+ * const stats = await Testing.getTestingWebpackCompiler(
+ * `./src/index.ts`,
+ * {},
+ * virtualFileSystem
+ * );
+ *
+ * expect(stats).toBeDefined();
+ * expect(virtualFileSystem.existsSync(path.join(__dirname, 'dist', 'index.js'))).toBe(true);
+ * });
+ * });
+ * ```
+ */
+export async function getTestingWebpackCompilerAsync(
+ entry: string,
+ additionalConfig: Configuration = {},
+ memFs: IFs = createFsFromVolume(new Volume())
+): Promise<(Stats | MultiStats) | undefined> {
+ let webpackModule: typeof import('webpack');
+ try {
+ webpackModule = (await import('webpack')).default;
+ } catch (e) {
+ throw new Error(
+ 'Unable to load module "webpack". The @rushstack/webpack-plugin-utilities package declares "webpack" as ' +
+ 'an optional peer dependency, but a function was invoked on it that requires webpack. Make sure ' +
+ `the peer dependency on "webpack" is fulfilled. Inner error: ${e}`
+ );
+ }
+
+ const compilerOptions: Configuration = webpackMerge(_defaultWebpackConfig(entry), additionalConfig);
+ const compiler: Compiler = webpackModule(compilerOptions);
+
+ compiler.outputFileSystem = memFs;
+ compiler.outputFileSystem.join = path.join.bind(path);
+
+ return new Promise((resolve, reject) => {
+ compiler.run((err, stats) => {
+ compiler.close(() => {
+ if (err) {
+ return reject(err);
+ }
+
+ _processAndHandleStatsErrorsAndWarnings(stats, reject);
+
+ resolve(stats);
+ });
+ });
+ });
+}
+
+function _processAndHandleStatsErrorsAndWarnings(
+ stats: Stats | MultiStats | undefined,
+ reject: (reason: unknown) => void
+): void {
+ if (stats?.hasErrors() || stats?.hasWarnings()) {
+ const serializedStats: WebpackStatsCompilation[] = [stats?.toJson('errors-warnings')];
+
+ const errors: StatsError[] = [];
+ const warnings: StatsError[] = [];
+
+ for (const compilationStats of serializedStats) {
+ if (compilationStats.warnings) {
+ for (const warning of compilationStats.warnings) {
+ warnings.push(warning);
+ }
+ }
+
+ if (compilationStats.errors) {
+ for (const error of compilationStats.errors) {
+ errors.push(error);
+ }
+ }
+
+ if (compilationStats.children) {
+ for (const child of compilationStats.children) {
+ serializedStats.push(child);
+ }
+ }
+ }
+
+ reject([...errors, ...warnings]);
+ }
+}
+
+function _defaultWebpackConfig(entry: string = './src'): Configuration {
+ return {
+ // We don't want to have eval source maps, nor minification
+ // so we set mode to 'none' to disable both. Default is 'production'
+ mode: 'none',
+ context: __dirname,
+ entry,
+ output: {
+ filename: 'test-bundle.js'
+ }
+ };
+}
diff --git a/webpack/webpack-plugin-utilities/src/index.ts b/webpack/webpack-plugin-utilities/src/index.ts
index 38b15ffd63b..75a14e2aa39 100644
--- a/webpack/webpack-plugin-utilities/src/index.ts
+++ b/webpack/webpack-plugin-utilities/src/index.ts
@@ -8,4 +8,5 @@
*/
import * as VersionDetection from './DetectWebpackVersion';
-export { VersionDetection };
+import * as Testing from './Testing';
+export { VersionDetection, Testing };
diff --git a/webpack/webpack4-localization-plugin/CHANGELOG.json b/webpack/webpack4-localization-plugin/CHANGELOG.json
index 3c2d5120834..6a1b008e739 100644
--- a/webpack/webpack4-localization-plugin/CHANGELOG.json
+++ b/webpack/webpack4-localization-plugin/CHANGELOG.json
@@ -1,6 +1,75 @@
{
"name": "@rushstack/webpack4-localization-plugin",
"entries": [
+ {
+ "version": "0.17.6",
+ "tag": "@rushstack/webpack4-localization-plugin_v0.17.6",
+ "date": "Thu, 23 Mar 2023 15:24:08 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.95`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.94` to `^3.3.95`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.17.5",
+ "tag": "@rushstack/webpack4-localization-plugin_v0.17.5",
+ "date": "Wed, 22 Mar 2023 20:48:30 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.94`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.93` to `^3.3.94`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.17.4",
+ "tag": "@rushstack/webpack4-localization-plugin_v0.17.4",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.47`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.93`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.92` to `^3.3.93`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.17.3",
+ "tag": "@rushstack/webpack4-localization-plugin_v0.17.3",
+ "date": "Sat, 11 Mar 2023 01:24:51 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.92`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.91` to `^3.3.92`"
+ }
+ ]
+ }
+ },
{
"version": "0.17.2",
"tag": "@rushstack/webpack4-localization-plugin_v0.17.2",
diff --git a/webpack/webpack4-localization-plugin/CHANGELOG.md b/webpack/webpack4-localization-plugin/CHANGELOG.md
index 4ba8a824cc5..a0f07176814 100644
--- a/webpack/webpack4-localization-plugin/CHANGELOG.md
+++ b/webpack/webpack4-localization-plugin/CHANGELOG.md
@@ -1,6 +1,26 @@
# Change Log - @rushstack/webpack4-localization-plugin
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Thu, 23 Mar 2023 15:24:08 GMT and should not be manually modified.
+
+## 0.17.6
+Thu, 23 Mar 2023 15:24:08 GMT
+
+_Version update only_
+
+## 0.17.5
+Wed, 22 Mar 2023 20:48:30 GMT
+
+_Version update only_
+
+## 0.17.4
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
+
+## 0.17.3
+Sat, 11 Mar 2023 01:24:51 GMT
+
+_Version update only_
## 0.17.2
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/webpack/webpack4-localization-plugin/package.json b/webpack/webpack4-localization-plugin/package.json
index be6f6a15b28..5268e490901 100644
--- a/webpack/webpack4-localization-plugin/package.json
+++ b/webpack/webpack4-localization-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/webpack4-localization-plugin",
- "version": "0.17.2",
+ "version": "0.17.6",
"description": "This plugin facilitates localization with Webpack.",
"main": "lib/index.js",
"typings": "dist/webpack4-localization-plugin.d.ts",
@@ -15,7 +15,7 @@
"_phase:build": "heft build --clean"
},
"peerDependencies": {
- "@rushstack/set-webpack-public-path-plugin": "^3.3.91",
+ "@rushstack/set-webpack-public-path-plugin": "^3.3.95",
"@types/webpack": "^4.39.0",
"webpack": "^4.31.0",
"@types/node": "*"
diff --git a/webpack/webpack4-module-minifier-plugin/CHANGELOG.json b/webpack/webpack4-module-minifier-plugin/CHANGELOG.json
index 4aebcdc39bb..350b09102e7 100644
--- a/webpack/webpack4-module-minifier-plugin/CHANGELOG.json
+++ b/webpack/webpack4-module-minifier-plugin/CHANGELOG.json
@@ -1,6 +1,27 @@
{
"name": "@rushstack/webpack4-module-minifier-plugin",
"entries": [
+ {
+ "version": "0.11.3",
+ "tag": "@rushstack/webpack4-module-minifier-plugin_v0.11.3",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.3`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.3`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
{
"version": "0.11.2",
"tag": "@rushstack/webpack4-module-minifier-plugin_v0.11.2",
diff --git a/webpack/webpack4-module-minifier-plugin/CHANGELOG.md b/webpack/webpack4-module-minifier-plugin/CHANGELOG.md
index 4bcfdb837ed..76561115988 100644
--- a/webpack/webpack4-module-minifier-plugin/CHANGELOG.md
+++ b/webpack/webpack4-module-minifier-plugin/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/webpack4-module-minifier-plugin
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.11.3
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 0.11.2
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/webpack/webpack4-module-minifier-plugin/package.json b/webpack/webpack4-module-minifier-plugin/package.json
index 38fdcaff666..252f8d8595f 100644
--- a/webpack/webpack4-module-minifier-plugin/package.json
+++ b/webpack/webpack4-module-minifier-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/webpack4-module-minifier-plugin",
- "version": "0.11.2",
+ "version": "0.11.3",
"description": "This plugin splits minification of webpack compilations into smaller units.",
"main": "lib/index.js",
"typings": "dist/webpack4-module-minifier-plugin.d.ts",
diff --git a/webpack/webpack5-load-themed-styles-loader/CHANGELOG.json b/webpack/webpack5-load-themed-styles-loader/CHANGELOG.json
index 7938bce5d88..c5c3b7fdf9f 100644
--- a/webpack/webpack5-load-themed-styles-loader/CHANGELOG.json
+++ b/webpack/webpack5-load-themed-styles-loader/CHANGELOG.json
@@ -1,6 +1,42 @@
{
"name": "@microsoft/webpack5-load-themed-styles-loader",
"entries": [
+ {
+ "version": "0.1.13",
+ "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.13",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.31`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.30` to `^2.0.31`"
+ }
+ ]
+ }
+ },
+ {
+ "version": "0.1.12",
+ "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.12",
+ "date": "Sat, 11 Mar 2023 01:24:51 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.30`"
+ },
+ {
+ "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.29` to `^2.0.30`"
+ }
+ ]
+ }
+ },
{
"version": "0.1.11",
"tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.11",
diff --git a/webpack/webpack5-load-themed-styles-loader/CHANGELOG.md b/webpack/webpack5-load-themed-styles-loader/CHANGELOG.md
index 18244c1170e..6446f1b912e 100644
--- a/webpack/webpack5-load-themed-styles-loader/CHANGELOG.md
+++ b/webpack/webpack5-load-themed-styles-loader/CHANGELOG.md
@@ -1,6 +1,16 @@
# Change Log - @microsoft/webpack5-load-themed-styles-loader
-This log was last generated on Fri, 10 Feb 2023 01:18:50 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.1.13
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
+
+## 0.1.12
+Sat, 11 Mar 2023 01:24:51 GMT
+
+_Version update only_
## 0.1.11
Fri, 10 Feb 2023 01:18:50 GMT
diff --git a/webpack/webpack5-load-themed-styles-loader/package.json b/webpack/webpack5-load-themed-styles-loader/package.json
index 9f1fad77395..7a21da8e1d0 100644
--- a/webpack/webpack5-load-themed-styles-loader/package.json
+++ b/webpack/webpack5-load-themed-styles-loader/package.json
@@ -1,6 +1,6 @@
{
"name": "@microsoft/webpack5-load-themed-styles-loader",
- "version": "0.1.11",
+ "version": "0.1.13",
"description": "This simple loader wraps the loading of CSS in script equivalent to `require('load-themed-styles').loadStyles( /* css text */ )`. It is designed to be a replacement for style-loader.",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
@@ -16,7 +16,7 @@
"_phase:test": "heft test --no-build"
},
"peerDependencies": {
- "@microsoft/load-themed-styles": "^2.0.29",
+ "@microsoft/load-themed-styles": "^2.0.31",
"webpack": "^5"
},
"peerDependenciesMeta": {
diff --git a/webpack/webpack5-localization-plugin/CHANGELOG.json b/webpack/webpack5-localization-plugin/CHANGELOG.json
index 4dbca32cc65..ffd38b5bf4f 100644
--- a/webpack/webpack5-localization-plugin/CHANGELOG.json
+++ b/webpack/webpack5-localization-plugin/CHANGELOG.json
@@ -1,6 +1,24 @@
{
"name": "@rushstack/webpack5-localization-plugin",
"entries": [
+ {
+ "version": "0.4.3",
+ "tag": "@rushstack/webpack5-localization-plugin_v0.4.3",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.47`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ }
+ ]
+ }
+ },
{
"version": "0.4.2",
"tag": "@rushstack/webpack5-localization-plugin_v0.4.2",
diff --git a/webpack/webpack5-localization-plugin/CHANGELOG.md b/webpack/webpack5-localization-plugin/CHANGELOG.md
index 57588e34fa5..0fb2bbda55e 100644
--- a/webpack/webpack5-localization-plugin/CHANGELOG.md
+++ b/webpack/webpack5-localization-plugin/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/webpack5-localization-plugin
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 0.4.3
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 0.4.2
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/webpack/webpack5-localization-plugin/package.json b/webpack/webpack5-localization-plugin/package.json
index 90a8e20fe8b..44dff60ff11 100644
--- a/webpack/webpack5-localization-plugin/package.json
+++ b/webpack/webpack5-localization-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/webpack5-localization-plugin",
- "version": "0.4.2",
+ "version": "0.4.3",
"description": "This plugin facilitates localization with Webpack.",
"main": "lib/index.js",
"typings": "dist/webpack5-localization-plugin.d.ts",
diff --git a/webpack/webpack5-module-minifier-plugin/CHANGELOG.json b/webpack/webpack5-module-minifier-plugin/CHANGELOG.json
index 8eaf1dbcece..6dbf225e9d1 100644
--- a/webpack/webpack5-module-minifier-plugin/CHANGELOG.json
+++ b/webpack/webpack5-module-minifier-plugin/CHANGELOG.json
@@ -1,6 +1,30 @@
{
"name": "@rushstack/webpack5-module-minifier-plugin",
"entries": [
+ {
+ "version": "5.3.3",
+ "tag": "@rushstack/webpack5-module-minifier-plugin_v5.3.3",
+ "date": "Sat, 18 Mar 2023 00:20:56 GMT",
+ "comments": {
+ "dependency": [
+ {
+ "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.3`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.3`"
+ },
+ {
+ "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`"
+ }
+ ]
+ }
+ },
{
"version": "5.3.2",
"tag": "@rushstack/webpack5-module-minifier-plugin_v5.3.2",
diff --git a/webpack/webpack5-module-minifier-plugin/CHANGELOG.md b/webpack/webpack5-module-minifier-plugin/CHANGELOG.md
index d9c94fb170c..db1721d1e6a 100644
--- a/webpack/webpack5-module-minifier-plugin/CHANGELOG.md
+++ b/webpack/webpack5-module-minifier-plugin/CHANGELOG.md
@@ -1,6 +1,11 @@
# Change Log - @rushstack/webpack5-module-minifier-plugin
-This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified.
+This log was last generated on Sat, 18 Mar 2023 00:20:56 GMT and should not be manually modified.
+
+## 5.3.3
+Sat, 18 Mar 2023 00:20:56 GMT
+
+_Version update only_
## 5.3.2
Fri, 10 Feb 2023 01:18:51 GMT
diff --git a/webpack/webpack5-module-minifier-plugin/package.json b/webpack/webpack5-module-minifier-plugin/package.json
index 7193f1bd2aa..819c697681c 100644
--- a/webpack/webpack5-module-minifier-plugin/package.json
+++ b/webpack/webpack5-module-minifier-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@rushstack/webpack5-module-minifier-plugin",
- "version": "5.3.2",
+ "version": "5.3.3",
"description": "This plugin splits minification of webpack compilations into smaller units.",
"main": "lib/index.js",
"typings": "dist/webpack5-module-minifier-plugin.d.ts",