From d44931fbdac18ca66601b9f82717217e26ba7a83 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Mon, 15 Jun 2020 14:34:03 -0700 Subject: [PATCH 01/33] Move to installManager --- apps/rush-lib/src/logic/{ => installManager}/InstallHelpers.ts | 0 .../{InstallManager.ts => installManager/RushInstallManager.ts} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename apps/rush-lib/src/logic/{ => installManager}/InstallHelpers.ts (100%) rename apps/rush-lib/src/logic/{InstallManager.ts => installManager/RushInstallManager.ts} (100%) diff --git a/apps/rush-lib/src/logic/InstallHelpers.ts b/apps/rush-lib/src/logic/installManager/InstallHelpers.ts similarity index 100% rename from apps/rush-lib/src/logic/InstallHelpers.ts rename to apps/rush-lib/src/logic/installManager/InstallHelpers.ts diff --git a/apps/rush-lib/src/logic/InstallManager.ts b/apps/rush-lib/src/logic/installManager/RushInstallManager.ts similarity index 100% rename from apps/rush-lib/src/logic/InstallManager.ts rename to apps/rush-lib/src/logic/installManager/RushInstallManager.ts From 65c1c44dfd4cbe5e9451519198007f0c4442a4c9 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Wed, 17 Jun 2020 12:35:03 -0700 Subject: [PATCH 02/33] Add initial implementation of workspaces --- apps/rush-lib/package.json | 4 +- apps/rush-lib/src/api/PackageJsonEditor.ts | 6 +- apps/rush-lib/src/api/RushConfiguration.ts | 32 + .../src/cli/actions/BaseInstallAction.ts | 5 +- .../rush-lib/src/cli/actions/InstallAction.ts | 2 +- apps/rush-lib/src/cli/actions/UpdateAction.ts | 2 +- .../rush-lib/src/cli/actions/VersionAction.ts | 10 +- .../cli/scriptActions/GlobalScriptAction.ts | 2 +- .../rush-lib/src/logic/DependencySpecifier.ts | 10 + .../src/logic/InstallManagerFactory.ts | 42 + apps/rush-lib/src/logic/PackageJsonUpdater.ts | 11 +- apps/rush-lib/src/logic/PublishUtilities.ts | 14 +- .../src/logic/base/BaseInstallManager.ts | 766 ++++++++++ .../src/logic/base/BaseShrinkwrapFile.ts | 51 + .../src/logic/base/BaseWorkspaceFile.ts | 67 + .../logic/installManager/InstallHelpers.ts | 284 +++- .../installManager/RushInstallManager.ts | 1325 +++-------------- .../installManager/WorkspaceInstallManager.ts | 472 ++++++ .../src/logic/npm/NpmShrinkwrapFile.ts | 20 +- .../src/logic/pnpm/PnpmLinkManager.ts | 138 +- .../pnpm/PnpmProjectDependencyManifest.ts | 43 +- .../src/logic/pnpm/PnpmShrinkwrapFile.ts | 93 +- .../src/logic/pnpm/PnpmWorkspaceFile.ts | 90 ++ .../src/logic/yarn/YarnShrinkwrapFile.ts | 18 + apps/rush-lib/src/schemas/rush.schema.json | 8 + apps/rush-lib/src/utilities/Utilities.ts | 32 +- apps/rush/package.json | 4 +- .../api-extractor-test-02/package.json | 4 +- common/reviews/api/node-core-library.api.md | 3 + common/reviews/api/rush-lib.api.md | 4 + core-build/gulp-core-build/package.json | 4 +- libraries/node-core-library/package.json | 4 +- .../node-core-library/src/MapExtensions.ts | 15 + 33 files changed, 2431 insertions(+), 1154 deletions(-) create mode 100644 apps/rush-lib/src/logic/InstallManagerFactory.ts create mode 100644 apps/rush-lib/src/logic/base/BaseInstallManager.ts create mode 100644 apps/rush-lib/src/logic/base/BaseWorkspaceFile.ts create mode 100644 apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts create mode 100644 apps/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts diff --git a/apps/rush-lib/package.json b/apps/rush-lib/package.json index fb3d85b1636..c478c2bccea 100644 --- a/apps/rush-lib/package.json +++ b/apps/rush-lib/package.json @@ -41,7 +41,7 @@ "npm-packlist": "~2.1.2", "read-package-tree": "~5.1.5", "resolve": "~1.17.0", - "semver": "~5.3.0", + "semver": "~7.3.0", "strict-uri-encode": "~2.0.0", "tar": "~5.0.5", "true-case-path": "~2.2.1", @@ -64,7 +64,7 @@ "@types/npm-packlist": "~1.1.1", "@types/read-package-tree": "5.1.0", "@types/resolve": "1.17.1", - "@types/semver": "5.3.33", + "@types/semver": "~7.2.0", "@types/strict-uri-encode": "2.0.0", "@types/tar": "4.0.3", "@types/wordwrap": "1.0.0", diff --git a/apps/rush-lib/src/api/PackageJsonEditor.ts b/apps/rush-lib/src/api/PackageJsonEditor.ts index 739b544d67b..62e7d8eeafe 100644 --- a/apps/rush-lib/src/api/PackageJsonEditor.ts +++ b/apps/rush-lib/src/api/PackageJsonEditor.ts @@ -201,7 +201,11 @@ export class PackageJsonEditor { this._onChange.bind(this) ); - if (dependencyType === DependencyType.Regular || dependencyType === DependencyType.Optional) { + if ( + dependencyType === DependencyType.Regular || + dependencyType === DependencyType.Optional || + dependencyType === DependencyType.Peer + ) { this._dependencies.set(packageName, dependency); } else { this._devDependencies.set(packageName, dependency); diff --git a/apps/rush-lib/src/api/RushConfiguration.ts b/apps/rush-lib/src/api/RushConfiguration.ts index 2b4c85061e5..80ff3b041b4 100644 --- a/apps/rush-lib/src/api/RushConfiguration.ts +++ b/apps/rush-lib/src/api/RushConfiguration.ts @@ -168,6 +168,14 @@ export interface IPnpmOptionsJson extends IPackageManagerOptionsJsonBase { * {@inheritDoc PnpmOptionsConfiguration.preventManualShrinkwrapChanges} */ preventManualShrinkwrapChanges?: boolean; + /** + * {@inheritDoc PnpmOptionsConfiguration.useWorkspaces} + */ + useWorkspaces?: boolean; + /** + * {@inheritDoc PnpmOptionsConfiguration.useShimPnpmfile} + */ + useShimPnpmfile?: boolean; } /** @@ -346,6 +354,28 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration */ public readonly preventManualShrinkwrapChanges: boolean; + /** + * If true, then Rush will use the workspaces feature to install and link packages when invoking PNPM. + * + * @remarks + * The default value is false. (For now.) + */ + public readonly useWorkspaces: boolean; + + /** + * If true, then Rush will create a pnpmfile that runs before the provided pnpmfile. This shim + * pnpmfile is used to inject preferred versions support into the PNPM package resolver. + * + * @remarks + * Preferred versions are supported using pnpmfile by substituting any dependency version specifier + * for the preferred version during package resolution. This is only done if the preferred version range + * is a subset of the dependency version range. Allowed alternate versions are not modified. The pnpmfile + * shim will subsequently call into the provided pnpmfile, if one exists. + * + * The default value is false. (For now.) + */ + public readonly useShimPnpmfile: boolean; + /** @internal */ public constructor(json: IPnpmOptionsJson, commonTempFolder: string) { super(json); @@ -360,6 +390,8 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration this.strictPeerDependencies = !!json.strictPeerDependencies; this.resolutionStrategy = json.resolutionStrategy || 'fewer-dependencies'; this.preventManualShrinkwrapChanges = !!json.preventManualShrinkwrapChanges; + this.useWorkspaces = !!json.useWorkspaces; + this.useShimPnpmfile = !!json.useShimPnpmfile; } } diff --git a/apps/rush-lib/src/cli/actions/BaseInstallAction.ts b/apps/rush-lib/src/cli/actions/BaseInstallAction.ts index ec29a2db4df..3e0973bd274 100644 --- a/apps/rush-lib/src/cli/actions/BaseInstallAction.ts +++ b/apps/rush-lib/src/cli/actions/BaseInstallAction.ts @@ -12,7 +12,8 @@ import { import { BaseRushAction } from './BaseRushAction'; import { Event } from '../../api/EventHooks'; -import { InstallManager, IInstallManagerOptions } from '../../logic/InstallManager'; +import { BaseInstallManager, IInstallManagerOptions } from '../../logic/base/BaseInstallManager'; +import { InstallManagerFactory } from '../../logic/InstallManagerFactory'; import { PurgeManager } from '../../logic/PurgeManager'; import { SetupChecks } from '../../logic/SetupChecks'; import { StandardScriptUpdater } from '../../logic/StandardScriptUpdater'; @@ -117,7 +118,7 @@ export abstract class BaseInstallAction extends BaseRushAction { const installManagerOptions: IInstallManagerOptions = this.buildInstallOptions(); - const installManager: InstallManager = new InstallManager( + const installManager: BaseInstallManager = InstallManagerFactory.getInstallManager( this.rushConfiguration, this.rushGlobalFolder, purgeManager, diff --git a/apps/rush-lib/src/cli/actions/InstallAction.ts b/apps/rush-lib/src/cli/actions/InstallAction.ts index 9133fb9e2d6..2422d61a4e1 100644 --- a/apps/rush-lib/src/cli/actions/InstallAction.ts +++ b/apps/rush-lib/src/cli/actions/InstallAction.ts @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. import { BaseInstallAction } from './BaseInstallAction'; -import { IInstallManagerOptions } from '../../logic/InstallManager'; +import { IInstallManagerOptions } from '../../logic/base/BaseInstallManager'; import { RushCommandLineParser } from '../RushCommandLineParser'; export class InstallAction extends BaseInstallAction { diff --git a/apps/rush-lib/src/cli/actions/UpdateAction.ts b/apps/rush-lib/src/cli/actions/UpdateAction.ts index 48e05ad7e48..27d800c7262 100644 --- a/apps/rush-lib/src/cli/actions/UpdateAction.ts +++ b/apps/rush-lib/src/cli/actions/UpdateAction.ts @@ -4,7 +4,7 @@ import { CommandLineFlagParameter } from '@rushstack/ts-command-line'; import { BaseInstallAction } from './BaseInstallAction'; -import { IInstallManagerOptions } from '../../logic/InstallManager'; +import { IInstallManagerOptions } from '../../logic/base/BaseInstallManager'; import { RushCommandLineParser } from '../RushCommandLineParser'; export class UpdateAction extends BaseInstallAction { diff --git a/apps/rush-lib/src/cli/actions/VersionAction.ts b/apps/rush-lib/src/cli/actions/VersionAction.ts index 778afff94fa..4761e514c5d 100644 --- a/apps/rush-lib/src/cli/actions/VersionAction.ts +++ b/apps/rush-lib/src/cli/actions/VersionAction.ts @@ -154,10 +154,16 @@ export class VersionAction extends BaseRushAction { const newPolicyVersion: semver.SemVer = new semver.SemVer(policy.version); if (newPolicyVersion.prerelease.length) { // Update 1.5.0-alpha.10 to 1.5.0-beta.10 - newPolicyVersion.prerelease[0] = this._prereleaseIdentifier.value; + // For example, if we are parsing "1.5.0-alpha.10" then the newPolicyVersion.prerelease array + // would contain [ "alpha", 10 ], so we would replace "alpha" with "beta" + newPolicyVersion.prerelease = [ + this._prereleaseIdentifier.value, + ...newPolicyVersion.prerelease.slice(1) + ]; } else { // Update 1.5.0 to 1.5.0-beta - newPolicyVersion.prerelease.push(this._prereleaseIdentifier.value); + // Since there is no length, we can just set to a new array + newPolicyVersion.prerelease = [this._prereleaseIdentifier.value]; } newVersion = newPolicyVersion.format(); } diff --git a/apps/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts b/apps/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts index 7e9524d076f..61b88d4afa6 100644 --- a/apps/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts +++ b/apps/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts @@ -9,7 +9,7 @@ import { BaseScriptAction, IBaseScriptActionOptions } from './BaseScriptAction'; import { Utilities } from '../../utilities/Utilities'; import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; import { FileSystem, LockFile, IPackageJson, JsonFile, PackageName } from '@rushstack/node-core-library'; -import { InstallHelpers } from '../../logic/InstallHelpers'; +import { InstallHelpers } from '../../logic/installManager/InstallHelpers'; import { RushConstants } from '../../logic/RushConstants'; import { LastInstallFlag } from '../../api/LastInstallFlag'; diff --git a/apps/rush-lib/src/logic/DependencySpecifier.ts b/apps/rush-lib/src/logic/DependencySpecifier.ts index 51f653aad58..6249004dac5 100644 --- a/apps/rush-lib/src/logic/DependencySpecifier.ts +++ b/apps/rush-lib/src/logic/DependencySpecifier.ts @@ -32,6 +32,7 @@ export class DependencySpecifier { * directory - A local directory * remote - An HTTP url to a .tar.gz, .tar or .tgz file * alias - A package alias such as "npm:other-package@^1.2.3" + * workspace - A package specified using workspace protocol such as "workspace:^1.2.3" */ public readonly specifierType: string; @@ -46,6 +47,15 @@ export class DependencySpecifier { this.packageName = packageName; this.versionSpecifier = versionSpecifier; + // Workspace ranges are a feature from PNPM and Yarn. Set the version specifier + // to the trimmed version range. + if (versionSpecifier.startsWith('workspace:')) { + this.specifierType = 'workspace'; + this.versionSpecifier = versionSpecifier.slice(this.specifierType.length + 1).trim(); + this.aliasTarget = undefined; + return; + } + const result: npmPackageArg.AliasResult = npmPackageArg.resolve( packageName, versionSpecifier diff --git a/apps/rush-lib/src/logic/InstallManagerFactory.ts b/apps/rush-lib/src/logic/InstallManagerFactory.ts new file mode 100644 index 00000000000..fb27a19b0da --- /dev/null +++ b/apps/rush-lib/src/logic/InstallManagerFactory.ts @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as colors from 'colors'; +import * as semver from 'semver'; + +import { BaseInstallManager, IInstallManagerOptions } from './base/BaseInstallManager'; +import { RushInstallManager } from './installManager/RushInstallManager'; +import { WorkspaceInstallManager } from './installManager/WorkspaceInstallManager'; +import { AlreadyReportedError } from '../utilities/AlreadyReportedError'; +import { PurgeManager } from './PurgeManager'; +import { RushConfiguration } from '../api/RushConfiguration'; +import { RushGlobalFolder } from '../api/RushGlobalFolder'; + +export class InstallManagerFactory { + public static getInstallManager( + rushConfiguration: RushConfiguration, + rushGlobalFolder: RushGlobalFolder, + purgeManager: PurgeManager, + options: IInstallManagerOptions + ): BaseInstallManager { + if ( + rushConfiguration.packageManager === 'pnpm' && + rushConfiguration.pnpmOptions && + rushConfiguration.pnpmOptions.useWorkspaces + ) { + if (!semver.satisfies(rushConfiguration.packageManagerToolVersion, '>=4.14.3')) { + console.log(); + console.log( + colors.red( + 'Workspaces are only supported in Rush for PNPM >=4.14.3. Upgrade PNPM to use the workspaces feature.' + ) + ); + throw new AlreadyReportedError(); + } + + return new WorkspaceInstallManager(rushConfiguration, rushGlobalFolder, purgeManager, options); + } + + return new RushInstallManager(rushConfiguration, rushGlobalFolder, purgeManager, options); + } +} diff --git a/apps/rush-lib/src/logic/PackageJsonUpdater.ts b/apps/rush-lib/src/logic/PackageJsonUpdater.ts index e6b3930182b..0f0a541ff93 100644 --- a/apps/rush-lib/src/logic/PackageJsonUpdater.ts +++ b/apps/rush-lib/src/logic/PackageJsonUpdater.ts @@ -5,7 +5,8 @@ import * as colors from 'colors'; import * as semver from 'semver'; import { RushConfiguration } from '../api/RushConfiguration'; -import { InstallManager, IInstallManagerOptions } from './InstallManager'; +import { BaseInstallManager, IInstallManagerOptions } from './base/BaseInstallManager'; +import { InstallManagerFactory } from './InstallManagerFactory'; import { VersionMismatchFinder } from './versionMismatch/VersionMismatchFinder'; import { PurgeManager } from './PurgeManager'; import { Utilities } from '../utilities/Utilities'; @@ -15,7 +16,7 @@ import { RushConfigurationProject } from '../api/RushConfigurationProject'; import { VersionMismatchFinderEntity } from './versionMismatch/VersionMismatchFinderEntity'; import { VersionMismatchFinderProject } from './versionMismatch/VersionMismatchFinderProject'; import { RushConstants } from './RushConstants'; -import { InstallHelpers } from './InstallHelpers'; +import { InstallHelpers } from './installManager/InstallHelpers'; /** * The type of SemVer range specifier that is prepended to the version @@ -123,7 +124,7 @@ export class PackageJsonUpdater { variant } = options; - const implicitlyPinned: Map = InstallManager.collectImplicitlyPreferredVersions( + const implicitlyPinned: Map = InstallHelpers.collectImplicitlyPreferredVersions( this._rushConfiguration, { variant @@ -143,7 +144,7 @@ export class PackageJsonUpdater { variant: variant, maxInstallAttempts: RushConstants.defaultMaxInstallAttempts }; - const installManager: InstallManager = new InstallManager( + const installManager: BaseInstallManager = InstallManagerFactory.getInstallManager( this._rushConfiguration, this._rushGlobalFolder, purgeManager, @@ -281,7 +282,7 @@ export class PackageJsonUpdater { */ private async _getNormalizedVersionSpec( projects: RushConfigurationProject[], - installManager: InstallManager, + installManager: BaseInstallManager, packageName: string, initialSpec: string | undefined, implicitlyPinnedVersion: string | undefined, diff --git a/apps/rush-lib/src/logic/PublishUtilities.ts b/apps/rush-lib/src/logic/PublishUtilities.ts index c2d88473030..427cc04f1b5 100644 --- a/apps/rush-lib/src/logic/PublishUtilities.ts +++ b/apps/rush-lib/src/logic/PublishUtilities.ts @@ -97,7 +97,7 @@ export class PublishUtilities { // For hotfix changes, do not re-write new version change.newVersion = change.changeType! >= ChangeType.patch - ? semver.inc(pkg.version, PublishUtilities._getReleaseType(change.changeType!)) + ? semver.inc(pkg.version, PublishUtilities._getReleaseType(change.changeType!))! : change.changeType === ChangeType.hotfix ? change.newVersion : pkg.version; @@ -253,9 +253,9 @@ export class PublishUtilities { let upperLimit: string = newVersion; if (semver.prerelease(newVersion)) { // Remove the prerelease first, then bump major. - upperLimit = semver.inc(newVersion, 'patch'); + upperLimit = semver.inc(newVersion, 'patch')!; } - upperLimit = semver.inc(upperLimit, 'major'); + upperLimit = semver.inc(upperLimit, 'major')!; return `>=${newVersion} <${upperLimit}`; } @@ -445,7 +445,7 @@ export class PublishUtilities { return newVersion; } if (prereleaseToken.isPrerelease && change.changeType === ChangeType.dependency) { - newVersion = semver.inc(newVersion, 'patch'); + newVersion = semver.inc(newVersion, 'patch')!; } return `${newVersion}-${prereleaseToken.name}`; } else { @@ -526,7 +526,7 @@ export class PublishUtilities { currentChange.changeType = ChangeType.none; } else { if (change.changeType === ChangeType.hotfix) { - const prereleaseComponents: string[] = semver.prerelease(pkg.version); + const prereleaseComponents: ReadonlyArray | null = semver.prerelease(pkg.version); if (!rushConfiguration.hotfixChangeEnabled) { throw new Error(`Cannot add hotfix change; hotfixChangeEnabled is false in configuration.`); } @@ -535,7 +535,7 @@ export class PublishUtilities { if (!prereleaseComponents) { currentChange.newVersion += '-hotfix'; } - currentChange.newVersion = semver.inc(currentChange.newVersion, 'prerelease'); + currentChange.newVersion = semver.inc(currentChange.newVersion, 'prerelease')!; } else { // When there are multiple changes of this package, the final value of new version // should not depend on the order of the changes. @@ -545,7 +545,7 @@ export class PublishUtilities { } currentChange.newVersion = change.changeType! >= ChangeType.patch - ? semver.inc(pkg.version, PublishUtilities._getReleaseType(currentChange.changeType!)) + ? semver.inc(pkg.version, PublishUtilities._getReleaseType(currentChange.changeType!))! : packageVersion; } diff --git a/apps/rush-lib/src/logic/base/BaseInstallManager.ts b/apps/rush-lib/src/logic/base/BaseInstallManager.ts new file mode 100644 index 00000000000..610ab2df85b --- /dev/null +++ b/apps/rush-lib/src/logic/base/BaseInstallManager.ts @@ -0,0 +1,766 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as colors from 'colors'; +import * as fetch from 'node-fetch'; +import * as fs from 'fs'; +import * as http from 'http'; +import HttpsProxyAgent = require('https-proxy-agent'); +import * as os from 'os'; +import * as path from 'path'; +import * as semver from 'semver'; +import { + FileSystem, + JsonFile, + JsonObject, + MapExtensions, + PosixModeBits, + NewlineKind +} from '@rushstack/node-core-library'; + +import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; +import { ApprovedPackagesChecker } from '../ApprovedPackagesChecker'; +import { AsyncRecycler } from '../../utilities/AsyncRecycler'; +import { BaseLinkManager } from './BaseLinkManager'; +import { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; +import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; +import { Git } from '../Git'; +import { LastInstallFlag } from '../../api/LastInstallFlag'; +import { PnpmPackageManager } from '../../api/packageManager/PnpmPackageManager'; +import { PurgeManager } from '../PurgeManager'; +import { RushConfiguration, ICurrentVariantJson } from '../../api/RushConfiguration'; +import { Rush } from '../../api/Rush'; +import { RushGlobalFolder } from '../../api/RushGlobalFolder'; +import { RushConstants } from '../RushConstants'; +import { ShrinkwrapFileFactory } from '../ShrinkwrapFileFactory'; +import { Utilities } from '../../utilities/Utilities'; +import { InstallHelpers } from '../installManager/InstallHelpers'; +import { PolicyValidator } from '../policy/PolicyValidator'; +import { LinkManagerFactory } from '../LinkManagerFactory'; + +export interface IInstallManagerOptions { + /** + * Whether the global "--debug" flag was specified. + */ + debug: boolean; + /** + * Whether or not Rush will automatically update the shrinkwrap file. + * True for "rush update", false for "rush install". + */ + allowShrinkwrapUpdates: boolean; + /** + * Whether to skip policy checks. + */ + bypassPolicy: boolean; + /** + * Whether to skip linking, i.e. require "rush link" to be done manually later. + */ + noLink: boolean; + /** + * Whether to delete the shrinkwrap file before installation, i.e. so that all dependencies + * will be upgraded to the latest SemVer-compatible version. + */ + fullUpgrade: boolean; + /** + * Whether to force an update to the shrinkwrap file even if it appears to be unnecessary. + * Normally Rush uses heuristics to determine when "pnpm install" can be skipped, + * but sometimes the heuristics can be inaccurate due to external influences + * (pnpmfile.js script logic, registry changes, etc). + */ + recheckShrinkwrap: boolean; + + /** + * The value of the "--network-concurrency" command-line parameter, which + * is a diagnostic option used to troubleshoot network failures. + * + * Currently only supported for PNPM. + */ + networkConcurrency: number | undefined; + + /** + * Whether or not to collect verbose logs from the package manager. + * If specified when using PNPM, the logs will be in /common/temp/pnpm.log + */ + collectLogFile: boolean; + + /** + * The variant to consider when performing installations and validating shrinkwrap updates. + */ + variant?: string | undefined; + + /** + * Retry the install the specified number of times + */ + maxInstallAttempts: number; +} + +/** + * This class implements common logic between "rush install" and "rush update". + */ +export abstract class BaseInstallManager { + private _rushConfiguration: RushConfiguration; + private _rushGlobalFolder: RushGlobalFolder; + private _commonTempInstallFlag: LastInstallFlag; + private _installRecycler: AsyncRecycler; + + private _options: IInstallManagerOptions; + + public constructor( + rushConfiguration: RushConfiguration, + rushGlobalFolder: RushGlobalFolder, + purgeManager: PurgeManager, + options: IInstallManagerOptions + ) { + this._rushConfiguration = rushConfiguration; + this._rushGlobalFolder = rushGlobalFolder; + this._installRecycler = purgeManager.commonTempFolderRecycler; + this._options = options; + + const lastInstallState: JsonObject = { + node: process.versions.node, + packageManager: rushConfiguration.packageManager, + packageManagerVersion: rushConfiguration.packageManagerToolVersion + }; + + if (lastInstallState.packageManager === 'pnpm') { + lastInstallState.storePath = rushConfiguration.pnpmOptions.pnpmStorePath; + } + + this._commonTempInstallFlag = new LastInstallFlag( + this._rushConfiguration.commonTempFolder, + lastInstallState + ); + } + + protected get rushConfiguration(): RushConfiguration { + return this._rushConfiguration; + } + + protected get rushGlobalFolder(): RushGlobalFolder { + return this._rushGlobalFolder; + } + + protected get installRecycler(): AsyncRecycler { + return this._installRecycler; + } + + protected get options(): IInstallManagerOptions { + return this._options; + } + + public async doInstall(): Promise { + const { shrinkwrapIsUpToDate, variantIsUpToDate } = await this.prepare(); + + // This marker file indicates that the last "rush install" completed successfully. + // If "--purge" was specified, or if the last install was interrupted, then we will need to + // perform a clean install. Otherwise, we can do an incremental install. + const cleanInstall: boolean = !this._commonTempInstallFlag.checkValidAndReportStoreIssues(); + + // Allow us to defer the file read until we need it + const canSkipInstall: () => boolean = () => { + // Based on timestamps, can we skip this install entirely? + const outputStats: fs.Stats = FileSystem.getStatistics(this._commonTempInstallFlag.path); + return this.canSkipInstall(outputStats.mtime); + }; + + if (cleanInstall || !shrinkwrapIsUpToDate || !variantIsUpToDate || !canSkipInstall()) { + let publishedRelease: boolean | undefined; + try { + publishedRelease = await this._checkIfReleaseIsPublished(); + } catch { + // If the user is working in an environment that can't reach the registry, + // don't bother them with errors. + } + + if (publishedRelease === false) { + console.log( + colors.yellow('Warning: This release of the Rush tool was unpublished; it may be unstable.') + ); + } + + // Since we're going to be tampering with common/node_modules, delete the "rush link" flag file if it exists; + // this ensures that a full "rush link" is required next time + Utilities.deleteFile(this.rushConfiguration.rushLinkJsonFilename); + + // Delete the successful install file to indicate the install transaction has started + this._commonTempInstallFlag.clear(); + + // Perform the actual install + await this.install(cleanInstall); + + const usePnpmFrozenLockfile: boolean = + this._rushConfiguration.packageManager === 'pnpm' && + this._rushConfiguration.experimentsConfiguration.configuration.usePnpmFrozenLockfileForRushInstall === + true; + + if (this.options.allowShrinkwrapUpdates && (usePnpmFrozenLockfile || !shrinkwrapIsUpToDate)) { + // Shrinkwrap files may need to be post processed after install, so load and save it + const tempShrinkwrapFile: BaseShrinkwrapFile | undefined = ShrinkwrapFileFactory.getShrinkwrapFile( + this._rushConfiguration.packageManager, + this._rushConfiguration.packageManagerOptions, + this._rushConfiguration.tempShrinkwrapFilename + ); + if (tempShrinkwrapFile) { + tempShrinkwrapFile.save(this._rushConfiguration.tempShrinkwrapFilename); + } + + // Copy (or delete) common\temp\pnpm-lock.yaml --> common\config\rush\pnpm-lock.yaml + Utilities.syncFile( + this._rushConfiguration.tempShrinkwrapFilename, + this._rushConfiguration.getCommittedShrinkwrapFilename(this.options.variant) + ); + } else { + // TODO: Validate whether the package manager updated it in a nontrivial way + } + + // Create the marker file to indicate a successful install + this._commonTempInstallFlag.create(); + + console.log(''); + } + + if (!this.options.noLink) { + const linkManager: BaseLinkManager = LinkManagerFactory.getLinkManager(this._rushConfiguration); + await linkManager.createSymlinksForProjects(false); + } else { + console.log( + os.EOL + colors.yellow('Since "--no-link" was specified, you will need to run "rush link" manually.') + ); + } + } + + protected abstract prepareAndCheckShrinkwrap( + shrinkwrapFile: BaseShrinkwrapFile | undefined + ): Promise<{ shrinkwrapIsUpToDate: boolean; shrinkwrapWarnings: string[] }>; + + protected abstract canSkipInstall(lastInstallDate: Date): boolean; + + protected abstract install(cleanInstall: boolean): Promise; + + protected async prepare(): Promise<{ variantIsUpToDate: boolean; shrinkwrapIsUpToDate: boolean }> { + // Check the policies + PolicyValidator.validatePolicy(this._rushConfiguration, this.options); + + // Git hooks are only installed if the repo opts in by including files in /common/git-hooks + const hookSource: string = path.join(this._rushConfiguration.commonFolder, 'git-hooks'); + const hookDestination: string | undefined = Git.getHooksFolder(); + + if (FileSystem.exists(hookSource) && hookDestination) { + const allHookFilenames: string[] = FileSystem.readFolder(hookSource); + // Ignore the ".sample" file(s) in this folder. + const hookFilenames: string[] = allHookFilenames.filter((x) => !/\.sample$/.test(x)); + if (hookFilenames.length > 0) { + console.log(os.EOL + colors.bold('Found files in the "common/git-hooks" folder.')); + + // Clear the currently installed git hooks and install fresh copies + FileSystem.ensureEmptyFolder(hookDestination); + + // Only copy files that look like Git hook names + const filteredHookFilenames: string[] = hookFilenames.filter((x) => /^[a-z\-]+/.test(x)); + for (const filename of filteredHookFilenames) { + // Copy the file. Important: For Bash scripts, the EOL must not be CRLF. + const hookFileContent: string = FileSystem.readFile(path.join(hookSource, filename)); + FileSystem.writeFile(path.join(hookDestination, filename), hookFileContent, { + convertLineEndings: NewlineKind.Lf + }); + + FileSystem.changePosixModeBits( + path.join(hookDestination, filename), + // eslint-disable-next-line no-bitwise + PosixModeBits.UserRead | PosixModeBits.UserExecute + ); + } + + console.log( + 'Successfully installed these Git hook scripts: ' + filteredHookFilenames.join(', ') + os.EOL + ); + } + } + + const approvedPackagesChecker: ApprovedPackagesChecker = new ApprovedPackagesChecker( + this._rushConfiguration + ); + if (approvedPackagesChecker.approvedPackagesFilesAreOutOfDate) { + if (this._options.allowShrinkwrapUpdates) { + approvedPackagesChecker.rewriteConfigFiles(); + console.log( + colors.yellow( + 'Approved package files have been updated. These updates should be committed to source control' + ) + ); + } else { + throw new Error(`Approved packages files are out-of date. Run "rush update" to update them.`); + } + } + + // Ensure that the package manager is installed + await InstallHelpers.ensureLocalPackageManager( + this._rushConfiguration, + this._rushGlobalFolder, + this._options.maxInstallAttempts + ); + + let shrinkwrapFile: BaseShrinkwrapFile | undefined = undefined; + + // (If it's a full update, then we ignore the shrinkwrap from Git since it will be overwritten) + if (!this.options.fullUpgrade) { + try { + shrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile( + this._rushConfiguration.packageManager, + this._rushConfiguration.packageManagerOptions, + this._rushConfiguration.getCommittedShrinkwrapFilename(this.options.variant) + ); + } catch (ex) { + console.log(); + console.log(`Unable to load the ${this._rushConfiguration.shrinkwrapFilePhrase}: ${ex.message}`); + + if (!this.options.allowShrinkwrapUpdates) { + console.log(); + console.log(colors.red('You need to run "rush update" to fix this problem')); + throw new AlreadyReportedError(); + } + + shrinkwrapFile = undefined; + } + } + + // Write a file indicating which variant is being installed. + // This will be used by bulk scripts to determine the correct Shrinkwrap file to track. + const currentVariantJsonFilename: string = this._rushConfiguration.currentVariantJsonFilename; + const currentVariantJson: ICurrentVariantJson = { + variant: this.options.variant || null // eslint-disable-line @rushstack/no-null + }; + + // Determine if the variant is already current by updating current-variant.json. + // If nothing is written, the variant has not changed. + const variantIsUpToDate: boolean = !JsonFile.save(currentVariantJson, currentVariantJsonFilename, { + onlyIfChanged: true + }); + + if (this.options.variant) { + console.log(); + console.log(colors.bold(`Using variant '${this.options.variant}' for installation.`)); + } else if (!variantIsUpToDate && !this.options.variant) { + console.log(); + console.log(colors.bold('Using the default variant for installation.')); + } + + // Also copy down the committed .npmrc file, if there is one + // "common\config\rush\.npmrc" --> "common\temp\.npmrc" + // Also ensure that we remove any old one that may be hanging around + Utilities.syncNpmrc( + this._rushConfiguration.commonRushConfigFolder, + this._rushConfiguration.commonTempFolder + ); + + // also, copy the pnpmfile.js if it exists + if (this._rushConfiguration.packageManager === 'pnpm') { + const committedPnpmFilePath: string = this._rushConfiguration.getPnpmfilePath(this._options.variant); + const tempPnpmFilePath: string = path.join( + this._rushConfiguration.commonTempFolder, + RushConstants.pnpmfileFilename + ); + + // ensure that we remove any old one that may be hanging around + Utilities.syncFile(committedPnpmFilePath, tempPnpmFilePath); + + // shim support for common versions resolution into the pnpmfile. We want to ensure that it is enabled + // when requested or when using workspaces, since workspaces support preferred versions differently + if ( + this.rushConfiguration.pnpmOptions && + (this.rushConfiguration.pnpmOptions.useShimPnpmfile || + this.rushConfiguration.pnpmOptions.useWorkspaces) + ) { + await this.createShimPnpmfile(tempPnpmFilePath); + } + } + + // Allow for package managers to do their own preparation and check that the shrinkwrap is up to date + // eslint-disable-next-line prefer-const + let { shrinkwrapIsUpToDate, shrinkwrapWarnings } = await this.prepareAndCheckShrinkwrap(shrinkwrapFile); + shrinkwrapIsUpToDate = + shrinkwrapIsUpToDate && + !(this.options.recheckShrinkwrap || (shrinkwrapFile && shrinkwrapFile.shouldForceRecheck())); + + // Write out the reported warnings + if (shrinkwrapWarnings.length > 0) { + console.log(); + console.log( + colors.yellow( + Utilities.wrapWords( + `The ${this.rushConfiguration.shrinkwrapFilePhrase} contains the following issues:` + ) + ) + ); + + for (const shrinkwrapWarning of shrinkwrapWarnings) { + console.log(colors.yellow(' ' + shrinkwrapWarning)); + } + console.log(); + } + + this._syncTempShrinkwrap(shrinkwrapFile); + + // Force update if the shrinkwrap is out of date + if (!shrinkwrapIsUpToDate) { + if (!this.options.allowShrinkwrapUpdates) { + console.log(); + console.log( + colors.red( + `The ${this.rushConfiguration.shrinkwrapFilePhrase} is out of date. You need to run "rush update".` + ) + ); + throw new AlreadyReportedError(); + } + } + + return { shrinkwrapIsUpToDate, variantIsUpToDate }; + } + + /** + * Used when invoking the NPM tool. Appends the common configuration options + * to the command-line. + */ + protected pushConfigurationArgs(args: string[], options: IInstallManagerOptions): void { + if (this._rushConfiguration.packageManager === 'npm') { + if (semver.lt(this._rushConfiguration.packageManagerToolVersion, '5.0.0')) { + // NOTE: + // + // When using an npm version older than v5.0.0, we do NOT install optional dependencies for + // Rush, because npm does not generate the shrinkwrap file consistently across platforms. + // + // Consider the "fsevents" package. This is a Mac specific package + // which is an optional second-order dependency. Optional dependencies work by attempting to install + // the package, but removes the package if the install failed. + // This means that someone running generate on a Mac WILL have fsevents included in their shrinkwrap. + // When someone using Windows attempts to install from the shrinkwrap, the install will fail. + // + // If someone generates the shrinkwrap using Windows, then fsevents will NOT be listed in the shrinkwrap. + // When someone using Mac attempts to install from the shrinkwrap, they will NOT have the + // optional dependency installed. + // + // This issue has been fixed as of npm v5.0.0: https://github.com/npm/npm/releases/tag/v5.0.0 + // + // For more context, see https://github.com/microsoft/rushstack/issues/761#issuecomment-428689600 + args.push('--no-optional'); + } + args.push('--cache', this._rushConfiguration.npmCacheFolder); + args.push('--tmp', this._rushConfiguration.npmTmpFolder); + + if (options.collectLogFile) { + args.push('--verbose'); + } + } else if (this._rushConfiguration.packageManager === 'pnpm') { + // Only explicitly define the store path if `pnpmStore` is using the default, or has been set to + // 'local'. If `pnpmStore` = 'global', then allow PNPM to use the system's default + // path. In all cases, this will be overridden by RUSH_PNPM_STORE_PATH + if ( + this._rushConfiguration.pnpmOptions.pnpmStore === 'local' || + EnvironmentConfiguration.pnpmStorePathOverride + ) { + args.push('--store', this._rushConfiguration.pnpmOptions.pnpmStorePath); + } + + // we are using the --no-lock flag for now, which unfortunately prints a warning, but should be OK + // since rush already has its own install lock file which will invalidate the cache for us. + // we theoretically could use the lock file, but we would need to clean the store if the + // lockfile existed, otherwise PNPM would hang indefinitely. it is simpler to rely on Rush's + // last install flag, which encapsulates the entire installation + args.push('--no-lock'); + + if ( + this._rushConfiguration.experimentsConfiguration.configuration.usePnpmFrozenLockfileForRushInstall && + !this._options.allowShrinkwrapUpdates + ) { + if (semver.gte(this._rushConfiguration.packageManagerToolVersion, '3.0.0')) { + args.push('--frozen-lockfile'); + } else { + args.push('--frozen-shrinkwrap'); + } + } else { + // Ensure that Rush's tarball dependencies get synchronized properly with the pnpm-lock.yaml file. + // See this GitHub issue: https://github.com/pnpm/pnpm/issues/1342 + if (semver.gte(this._rushConfiguration.packageManagerToolVersion, '3.0.0')) { + args.push('--no-prefer-frozen-lockfile'); + } else { + args.push('--no-prefer-frozen-shrinkwrap'); + } + } + + if (options.collectLogFile) { + args.push('--reporter', 'ndjson'); + } + + if (options.networkConcurrency) { + args.push('--network-concurrency', options.networkConcurrency.toString()); + } + + if (this._rushConfiguration.pnpmOptions.strictPeerDependencies) { + args.push('--strict-peer-dependencies'); + } + + if ((this._rushConfiguration.packageManagerWrapper as PnpmPackageManager).supportsResolutionStrategy) { + args.push(`--resolution-strategy=${this._rushConfiguration.pnpmOptions.resolutionStrategy}`); + } + } else if (this._rushConfiguration.packageManager === 'yarn') { + args.push('--link-folder', 'yarn-link'); + args.push('--cache-folder', this._rushConfiguration.yarnCacheFolder); + + // Without this option, Yarn will sometimes stop and ask for user input on STDIN + // (e.g. "Which command would you like to run?"). + args.push('--non-interactive'); + + if (options.networkConcurrency) { + args.push('--network-concurrency', options.networkConcurrency.toString()); + } + + if (this._rushConfiguration.yarnOptions.ignoreEngines) { + args.push('--ignore-engines'); + } + } + } + + protected async createShimPnpmfile(filename: string): Promise { + // Get the versions we want to add to the shim pnpmfile + const allPreferredVersions: Map = InstallHelpers.collectPreferredVersions( + this.rushConfiguration, + this.options + ); + const allowedAlternativeVersions: Map< + string, + ReadonlyArray + > = this.rushConfiguration.getCommonVersions(this.options.variant).allowedAlternativeVersions; + + const clientPnpmfileName: string = 'clientPnpmfile.js'; + const pnpmfileContent: string[] = [ + '// THIS IS A GENERATED FILE. DO NOT MODIFY.', + '"use strict";', + 'module.exports = { hooks: { readPackage, afterAllResolved } };', + + // Obtain the original pnpmfile provided by the repo, if it exists. + 'const { existsSync } = require("fs");', + 'const clientPnpmfile = ', + ` existsSync("${clientPnpmfileName}") ? require("./${path.basename( + clientPnpmfileName, + '.js' + )}") : undefined;`, + // We will require semver from this path on disk, since this is the version of semver shipping with Rush + `const semver = require(${JSON.stringify(require.resolve('semver'))});`, + + // Include all the preferredVersions and allowedAlternativeVersions directly since there is no need to + // generate them on the fly + `const allPreferredVersions = ${JSON.stringify(MapExtensions.toObject(allPreferredVersions))};`, + `const allowedAlternativeVersions = ${JSON.stringify( + MapExtensions.toObject(allowedAlternativeVersions) + )};`, + + // Call the original pnpmfile (if it exists) + 'function afterAllResolved(lockfile, context) {', + ' return (clientPnpmfile && clientPnpmfile.hooks && clientPnpmfile.hooks.afterAllResolved)', + ' ? clientPnpmfile.hooks.afterAllResolved(lockfile, context)', + ' : lockfile;', + '}', + + // Set the preferred versions in the package, then call the original pnpmfile (if it exists) + 'function readPackage(pkg, context) {', + ' setPreferredVersions(pkg.dependencies);', + ' setPreferredVersions(pkg.devDependencies);', + ' setPreferredVersions(pkg.optionalDependencies);', + ' return (clientPnpmfile && clientPnpmfile.hooks && clientPnpmfile.hooks.readPackage)', + ' ? clientPnpmfile.hooks.readPackage(pkg, context)', + ' : pkg;', + '}', + + // Set the preferred versions on the dependency map. If the version on the map is an allowedAlternativeVersion + // then skip it. Otherwise, check to ensure that the common version is a subset of the specified version. If + // it is, then replace the specified version with the preferredVersion + 'function setPreferredVersions(dependencies) {', + ' for (const name of Object.keys(dependencies || {})) {', + ' if (allPreferredVersions.hasOwnProperty(name)) {', + ' const preferredVersion = allPreferredVersions[name];', + ' const version = dependencies[name];', + ' if (allowedAlternativeVersions.hasOwnProperty(name)) {', + ' const allowedAlternatives = allowedAlternativeVersions[name];', + ' if (allowedAlternatives && allowedAlternatives.indexOf(version) > -1) {', + ' continue;', + ' }', + ' }', + ' let isValidRange = false;', + ' try {', + ' isValidRange = !!semver.validRange(preferredVersion) && !!semver.validRange(version);', + ' } catch {', + ' }', + ' if (isValidRange && semver.subset(preferredVersion, version)) {', + ' dependencies[name] = preferredVersion;', + ' }', + ' }', + ' }', + '}' + ]; + + // Attempt to move the existing pnpmfile if there is one + try { + const pnpmfileDir: string = path.dirname(filename); + await FileSystem.moveAsync({ + sourcePath: filename, + destinationPath: path.join(pnpmfileDir, clientPnpmfileName) + }); + } catch (error) { + if (!FileSystem.isNotExistError(error)) { + throw error; + } + } + + // Write the shim pnpmfile to the original file path + await FileSystem.writeFileAsync(filename, pnpmfileContent.join(NewlineKind.Lf), { + ensureFolderExists: true + }); + } + + private _checkIfReleaseIsPublished(): Promise { + return Promise.resolve().then(() => { + const lastCheckFile: string = path.join( + this._rushGlobalFolder.nodeSpecificPath, + 'rush-' + Rush.version, + 'last-check.flag' + ); + + if (FileSystem.exists(lastCheckFile)) { + let cachedResult: boolean | 'error' | undefined = undefined; + try { + // NOTE: mtimeMs is not supported yet in Node.js 6.x + const nowMs: number = new Date().getTime(); + const ageMs: number = nowMs - FileSystem.getStatistics(lastCheckFile).mtime.getTime(); + const HOUR: number = 60 * 60 * 1000; + + // Is the cache too old? + if (ageMs < 24 * HOUR) { + // No, read the cached result + cachedResult = JsonFile.load(lastCheckFile); + } + } catch (e) { + // Unable to parse file + } + if (cachedResult === 'error') { + return Promise.reject(new Error('Unable to contact server')); + } + if (cachedResult === true || cachedResult === false) { + return cachedResult; + } + } + + // Before we start the network operation, record a failed state. If the process exits for some reason, + // this will record the error. It will also update the timestamp to prevent other Rush instances + // from attempting to update the file. + JsonFile.save('error', lastCheckFile, { ensureFolderExists: true }); + + // For this check we use the official registry, not the private registry + return this._queryIfReleaseIsPublished('https://registry.npmjs.org:443') + .then((publishedRelease: boolean) => { + // Cache the result + JsonFile.save(publishedRelease, lastCheckFile, { ensureFolderExists: true }); + return publishedRelease; + }) + .catch((error: Error) => { + JsonFile.save('error', lastCheckFile, { ensureFolderExists: true }); + return Promise.reject(error); + }); + }); + } + + // Helper for checkIfReleaseIsPublished() + private _queryIfReleaseIsPublished(registryUrl: string): Promise { + let queryUrl: string = registryUrl; + if (queryUrl[-1] !== '/') { + queryUrl += '/'; + } + // Note that the "@" symbol does not normally get URL-encoded + queryUrl += RushConstants.rushPackageName.replace('/', '%2F'); + + const userAgent: string = `pnpm/? npm/? node/${process.version} ${os.platform()} ${os.arch()}`; + + const headers: fetch.Headers = new fetch.Headers(); + headers.append('user-agent', userAgent); + headers.append('accept', 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*'); + + let agent: http.Agent | undefined = undefined; + if (process.env.HTTP_PROXY) { + agent = new HttpsProxyAgent(process.env.HTTP_PROXY); + } + + return fetch + .default(queryUrl, { + headers: headers, + agent: agent + }) + .then((response: fetch.Response) => { + if (!response.ok) { + return Promise.reject(new Error('Failed to query')); + } + return response.json().then((data) => { + let url: string; + try { + if (!data.versions[Rush.version]) { + // Version was not published + return false; + } + url = data.versions[Rush.version].dist.tarball; + if (!url) { + return Promise.reject(new Error(`URL not found`)); + } + } catch (e) { + return Promise.reject(new Error('Error parsing response')); + } + + // Make sure the tarball wasn't deleted from the CDN + headers.set('accept', '*/*'); + return fetch + .default(url, { + headers: headers, + agent: agent + }) + .then((response2: fetch.Response) => { + if (!response2.ok) { + if (response2.status === 404) { + return false; + } else { + return Promise.reject(new Error('Failed to fetch')); + } + } + return true; + }); + }); + }); + } + + private _syncTempShrinkwrap(shrinkwrapFile: BaseShrinkwrapFile | undefined): void { + if (shrinkwrapFile) { + // If we have a (possibly incomplete) shrinkwrap file, save it as the temporary file. + shrinkwrapFile.save(this.rushConfiguration.tempShrinkwrapFilename); + shrinkwrapFile.save(this.rushConfiguration.tempShrinkwrapPreinstallFilename); + } else { + // Otherwise delete the temporary file + FileSystem.deleteFile(this.rushConfiguration.tempShrinkwrapFilename); + + if (this.rushConfiguration.packageManager === 'pnpm') { + // Workaround for https://github.com/pnpm/pnpm/issues/1890 + // + // When "rush update --full" is run, rush deletes common/temp/pnpm-lock.yaml so that + // a new lockfile can be generated. But because of the above bug "pnpm install" would + // respect "common/temp/node_modules/.pnpm-lock.yaml" and thus would not generate a + // new lockfile. Deleting this file in addition to deleting common/temp/pnpm-lock.yaml + // ensures that a new lockfile will be generated with "rush update --full". + + const pnpmPackageManager: PnpmPackageManager = this.rushConfiguration + .packageManagerWrapper as PnpmPackageManager; + + FileSystem.deleteFile( + path.join( + this.rushConfiguration.commonTempFolder, + pnpmPackageManager.internalShrinkwrapRelativePath + ) + ); + } + } + } +} diff --git a/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts b/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts index 3be7726de09..7cf979c56f2 100644 --- a/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts +++ b/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts @@ -121,6 +121,57 @@ export abstract class BaseShrinkwrapFile { /** @virtual */ protected abstract getTopLevelDependencyVersion(dependencyName: string): DependencySpecifier | undefined; + /** + * Returns true if the specified workspace in the shrinkwrap file includes a package that would + * satisfy the specified SemVer version range. + * + * Consider this example: + * + * - project-a\ + * - lib-a@1.2.3 + * - lib-b@1.0.0 + * - lib-b@2.0.0 + * + * In this example, hasCompatibleWorkspaceDependency("lib-b", ">= 1.1.0", "workspace-key-for-project-a") + * would fail because it finds lib-b@1.0.0 which does not satisfy the pattern ">= 1.1.0". + * + * @virtual + */ + public hasCompatibleWorkspaceDependency( + dependencySpecifier: DependencySpecifier, + workspaceKey: string + ): boolean { + const shrinkwrapDependency: DependencySpecifier | undefined = this.getWorkspaceDependencyVersion( + dependencySpecifier, + workspaceKey + ); + return shrinkwrapDependency + ? this._checkDependencyVersion(dependencySpecifier, shrinkwrapDependency) + : false; + } + + /** + * Returns the list of keys to workspace projects specified in the shrinkwrap. + * Example: [ '../../apps/project1', '../../apps/project2' ] + * + * @virtual + */ + public abstract getWorkspaceKeys(): ReadonlyArray; + + /** + * Returns the key to the project in the workspace specified by the shrinkwrap. + * Example: '../../apps/project1' + * + * @virtual + */ + public abstract getWorkspaceKeyByPath(workspaceRoot: string, projectFolder: string): string; + + /** @virtual */ + protected abstract getWorkspaceDependencyVersion( + dependencySpecifier: DependencySpecifier, + workspaceKey: string + ): DependencySpecifier | undefined; + /** @virtual */ protected abstract serialize(): string; diff --git a/apps/rush-lib/src/logic/base/BaseWorkspaceFile.ts b/apps/rush-lib/src/logic/base/BaseWorkspaceFile.ts new file mode 100644 index 00000000000..e3546d58ed5 --- /dev/null +++ b/apps/rush-lib/src/logic/base/BaseWorkspaceFile.ts @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { FileSystem } from '@rushstack/node-core-library'; + +export interface IWorkspaceFileSaveOptions { + /** + * If there is an existing file, and the contents have not changed, then + * don't write anything; this preserves the old timestamp. + */ + onlyIfChanged?: boolean; + + /** + * Creates the folder recursively using FileSystem.ensureFolder() + * Defaults to false. + */ + ensureFolderExists?: boolean; +} + +/** + * This class is a parser for pnpm's pnpm-workspace.yaml file format. + */ +export abstract class BaseWorkspaceFile { + protected _alreadyWarnedSpecs: Set = new Set(); + + /** + * Serializes and saves the workspace file to specified location + */ + public save(filePath: string, options: IWorkspaceFileSaveOptions): void { + // Do we need to read the previous file contents? + let oldBuffer: Buffer | undefined = undefined; + if (options.onlyIfChanged && FileSystem.exists(filePath)) { + try { + oldBuffer = FileSystem.readFileToBuffer(filePath); + } catch (error) { + // Ignore this error, and try writing a new file. If that fails, then we should report that + // error instead. + } + } + + const newYaml: string = this.serialize(); + + const newBuffer: Buffer = Buffer.from(newYaml); // utf8 encoding happens here + + if (options.onlyIfChanged) { + // Has the file changed? + if (oldBuffer && Buffer.compare(newBuffer, oldBuffer) === 0) { + // Nothing has changed, so don't touch the file + return; + } + } + + FileSystem.writeFile(filePath, newBuffer.toString(), { + ensureFolderExists: options.ensureFolderExists + }); + } + + /** + * Adds a package path to the workspace file. + * + * @virtual + */ + public abstract addPackage(packagePath: string): void; + + /** @virtual */ + protected abstract serialize(): string; +} diff --git a/apps/rush-lib/src/logic/installManager/InstallHelpers.ts b/apps/rush-lib/src/logic/installManager/InstallHelpers.ts index f4382ac512a..102c5dcf19f 100644 --- a/apps/rush-lib/src/logic/installManager/InstallHelpers.ts +++ b/apps/rush-lib/src/logic/installManager/InstallHelpers.ts @@ -4,15 +4,169 @@ import * as colors from 'colors'; import * as os from 'os'; import * as path from 'path'; -import { LockFile, FileSystem } from '@rushstack/node-core-library'; +import * as semver from 'semver'; +import { + FileConstants, + FileSystem, + IPackageJson, + JsonFile, + LockFile, + MapExtensions +} from '@rushstack/node-core-library'; -import { LastInstallFlag } from '../api/LastInstallFlag'; -import { Utilities } from '../utilities/Utilities'; -import { PackageManagerName } from '../api/packageManager/PackageManager'; -import { RushConfiguration } from '../api/RushConfiguration'; -import { RushGlobalFolder } from '../api/RushGlobalFolder'; +import { CommonVersionsConfiguration } from '../../api/CommonVersionsConfiguration'; +import { LastInstallFlag } from '../../api/LastInstallFlag'; +import { PackageJsonDependency } from '../../api/PackageJsonEditor'; +import { PackageManagerName } from '../../api/packageManager/PackageManager'; +import { RushConfiguration, IConfigurationEnvironment } from '../../api/RushConfiguration'; +import { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { RushGlobalFolder } from '../../api/RushGlobalFolder'; +import { Utilities } from '../../utilities/Utilities'; export class InstallHelpers { + /** + * Returns a map containing all preferred versions for a Rush project. + * Returns a map: dependency name --> version specifier + */ + public static collectPreferredVersions( + rushConfiguration: RushConfiguration, + options: { + explicitPreferredVersions?: Map; + variant?: string | undefined; + } = {} + ): Map { + // dependency name --> version specifier + const allExplicitPreferredVersions: Map = options.explicitPreferredVersions + ? options.explicitPreferredVersions + : rushConfiguration.getCommonVersions(options.variant).getAllPreferredVersions(); + + // dependency name --> version specifier + const allPreferredVersions: Map = new Map(); + + // Should we add implicitly preferred versions? + let useImplicitlyPinnedVersions: boolean; + if (rushConfiguration.commonVersions.implicitlyPreferredVersions !== undefined) { + // Use the manually configured setting + useImplicitlyPinnedVersions = rushConfiguration.commonVersions.implicitlyPreferredVersions; + } else { + // Default to true. + useImplicitlyPinnedVersions = true; + } + + if (useImplicitlyPinnedVersions) { + // Add in the implicitly preferred versions. + // These are any first-level dependencies for which we only consume a single version range + // (e.g. every package that depends on react uses an identical specifier) + const implicitlyPreferredVersions: Map< + string, + string + > = InstallHelpers.collectImplicitlyPreferredVersions(rushConfiguration, options); + MapExtensions.mergeFromMap(allPreferredVersions, implicitlyPreferredVersions); + } + + // Add in the explicitly preferred versions. + // Note that these take precedence over implicitly preferred versions. + MapExtensions.mergeFromMap(allPreferredVersions, allExplicitPreferredVersions); + return allPreferredVersions; + } + + /** + * Returns a map of all direct dependencies that only have a single semantic version specifier. + * Returns a map: dependency name --> version specifier + */ + public static collectImplicitlyPreferredVersions( + rushConfiguration: RushConfiguration, + options: { + variant?: string | undefined; + } = {} + ): Map { + // First, collect all the direct dependencies of all local projects, and their versions: + // direct dependency name --> set of version specifiers + const versionsForDependencies: Map> = new Map>(); + + rushConfiguration.projects.forEach((project: RushConfigurationProject) => { + InstallHelpers._collectVersionsForDependencies(rushConfiguration, { + versionsForDependencies, + dependencies: project.packageJsonEditor.dependencyList, + cyclicDependencies: project.cyclicDependencyProjects, + variant: options.variant + }); + + InstallHelpers._collectVersionsForDependencies(rushConfiguration, { + versionsForDependencies, + dependencies: project.packageJsonEditor.devDependencyList, + cyclicDependencies: project.cyclicDependencyProjects, + variant: options.variant + }); + }); + + // If any dependency has more than one version, then filter it out (since we don't know which version + // should be preferred). What remains will be the list of preferred dependencies. + // dependency --> version specifier + const implicitlyPreferred: Map = new Map(); + versionsForDependencies.forEach((versions: Set, dep: string) => { + if (versions.size === 1) { + const version: string = versions.values().next().value; + implicitlyPreferred.set(dep, version); + } + }); + return implicitlyPreferred; + } + + public static generateCommonPackageJson( + rushConfiguration: RushConfiguration, + dependencies: Map + ): void { + const commonPackageJson: IPackageJson = { + dependencies: {}, + description: 'Temporary file generated by the Rush tool', + name: 'rush-common', + private: true, + version: '0.0.0' + }; + + // Add any preferred versions to the top of the commonPackageJson + // do this in alphabetical order for simpler debugging + for (const dependency of Array.from(dependencies.keys()).sort()) { + commonPackageJson.dependencies![dependency] = dependencies.get(dependency)!; + } + + // Example: "C:\MyRepo\common\temp\package.json" + const commonPackageJsonFilename: string = path.join( + rushConfiguration.commonTempFolder, + FileConstants.PackageJson + ); + + // Don't update the file timestamp unless the content has changed, since "rush install" + // will consider this timestamp + JsonFile.save(commonPackageJson, commonPackageJsonFilename, { onlyIfChanged: true }); + } + + public static getPackageManagerEnvironment( + rushConfiguration: RushConfiguration, + options: { + debug?: boolean; + } = {} + ): NodeJS.ProcessEnv { + let configurationEnvironment: IConfigurationEnvironment | undefined = undefined; + + if (rushConfiguration.packageManager === 'npm') { + if (rushConfiguration.npmOptions && rushConfiguration.npmOptions.environmentVariables) { + configurationEnvironment = rushConfiguration.npmOptions.environmentVariables; + } + } else if (rushConfiguration.packageManager === 'pnpm') { + if (rushConfiguration.pnpmOptions && rushConfiguration.pnpmOptions.environmentVariables) { + configurationEnvironment = rushConfiguration.pnpmOptions.environmentVariables; + } + } else if (rushConfiguration.packageManager === 'yarn') { + if (rushConfiguration.yarnOptions && rushConfiguration.yarnOptions.environmentVariables) { + configurationEnvironment = rushConfiguration.yarnOptions.environmentVariables; + } + } + + return InstallHelpers._mergeEnvironmentVariables(process.env, configurationEnvironment, options); + } + /** * If the "(p)npm-local" symlink hasn't been set up yet, this creates it, installing the * specified (P)npm version in the user's home directory if needed. @@ -102,4 +256,122 @@ export class InstallHelpers { lock.release(); } + + // Helper for collectImplicitlyPreferredVersions() + private static _collectVersionsForDependencies( + rushConfiguration: RushConfiguration, + options: { + versionsForDependencies: Map>; + dependencies: ReadonlyArray; + cyclicDependencies: Set; + variant: string | undefined; + } + ): void { + const { variant, dependencies, versionsForDependencies, cyclicDependencies } = options; + + const commonVersions: CommonVersionsConfiguration = rushConfiguration.getCommonVersions(variant); + + const allowedAlternativeVersions: Map> = + commonVersions.allowedAlternativeVersions; + + for (const dependency of dependencies) { + const alternativesForThisDependency: ReadonlyArray = + allowedAlternativeVersions.get(dependency.name) || []; + + // For each dependency, collectImplicitlyPreferredVersions() is collecting the set of all version specifiers + // that appear across the repo. If there is only one version specifier, then that's the "preferred" one. + // However, there are a few cases where additional version specifiers can be safely ignored. + let ignoreVersion: boolean = false; + + // 1. If the version specifier was listed in "allowedAlternativeVersions", then it's never a candidate. + // (Even if it's the only version specifier anywhere in the repo, we still ignore it, because + // otherwise the rule would be difficult to explain.) + if (alternativesForThisDependency.indexOf(dependency.version) > 0) { + ignoreVersion = true; + } else { + // Is it a local project? + const localProject: RushConfigurationProject | undefined = rushConfiguration.getProjectByName( + dependency.name + ); + if (localProject) { + // 2. If it's a symlinked local project, then it's not a candidate, because the package manager will + // never even see it. + // However there are two ways that a local project can NOT be symlinked: + // - if the local project doesn't satisfy the referenced semver specifier; OR + // - if the local project was specified in "cyclicDependencyProjects" in rush.json + if ( + semver.satisfies(localProject.packageJsonEditor.version, dependency.version) && + !cyclicDependencies.has(dependency.name) + ) { + ignoreVersion = true; + } + } + + if (!ignoreVersion) { + InstallHelpers._updateVersionsForDependencies( + versionsForDependencies, + dependency.name, + dependency.version + ); + } + } + } + } + + // Helper for collectImplicitlyPreferredVersions() + private static _updateVersionsForDependencies( + versionsForDependencies: Map>, + dependency: string, + version: string + ): void { + if (!versionsForDependencies.has(dependency)) { + versionsForDependencies.set(dependency, new Set()); + } + versionsForDependencies.get(dependency)!.add(version); + } + + // Helper for getPackageManagerEnvironment + private static _mergeEnvironmentVariables( + baseEnv: NodeJS.ProcessEnv, + environmentVariables?: IConfigurationEnvironment, + options: { + debug?: boolean; + } = {} + ): NodeJS.ProcessEnv { + const packageManagerEnv: NodeJS.ProcessEnv = baseEnv; + + if (environmentVariables) { + // eslint-disable-next-line guard-for-in + for (const envVar in environmentVariables) { + let setEnvironmentVariable: boolean = true; + console.log(`\nProcessing definition for environment variable: ${envVar}`); + + if (baseEnv.hasOwnProperty(envVar)) { + setEnvironmentVariable = false; + console.log(`Environment variable already defined:`); + console.log(` Name: ${envVar}`); + console.log(` Existing value: ${baseEnv[envVar]}`); + console.log(` Value set in rush.json: ${environmentVariables[envVar].value}`); + + if (environmentVariables[envVar].override) { + setEnvironmentVariable = true; + console.log(`Overriding the environment variable with the value set in rush.json.`); + } else { + console.log(colors.yellow(`WARNING: Not overriding the value of the environment variable.`)); + } + } + + if (setEnvironmentVariable) { + if (options.debug) { + console.log(`Setting environment variable for package manager.`); + console.log(` Name: ${envVar}`); + console.log(` Value: ${environmentVariables[envVar].value}`); + } + packageManagerEnv[envVar] = environmentVariables[envVar].value; + } + } + } + + return packageManagerEnv; + } } diff --git a/apps/rush-lib/src/logic/installManager/RushInstallManager.ts b/apps/rush-lib/src/logic/installManager/RushInstallManager.ts index 6dcf0f3f2b2..5e604881b91 100644 --- a/apps/rush-lib/src/logic/installManager/RushInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/RushInstallManager.ts @@ -3,56 +3,24 @@ import * as glob from 'glob'; import * as colors from 'colors'; -import * as fetch from 'node-fetch'; -import * as http from 'http'; -import HttpsProxyAgent = require('https-proxy-agent'); import * as os from 'os'; import * as path from 'path'; import * as semver from 'semver'; import * as tar from 'tar'; import * as globEscape from 'glob-escape'; -import { - JsonFile, - Text, - IPackageJson, - MapExtensions, - FileSystem, - FileConstants, - Sort, - PosixModeBits, - JsonObject, - NewlineKind -} from '@rushstack/node-core-library'; - -import { ApprovedPackagesChecker } from '../logic/ApprovedPackagesChecker'; -import { AsyncRecycler } from '../utilities/AsyncRecycler'; -import { BaseLinkManager } from '../logic/base/BaseLinkManager'; -import { BaseShrinkwrapFile } from '../logic/base/BaseShrinkwrapFile'; -import { PolicyValidator } from '../logic/policy/PolicyValidator'; -import { IRushTempPackageJson } from '../logic/base/BasePackage'; -import { Git } from '../logic/Git'; -import { LastInstallFlag } from '../api/LastInstallFlag'; -import { LinkManagerFactory } from '../logic/LinkManagerFactory'; -import { PurgeManager } from './PurgeManager'; -import { RushConfiguration, ICurrentVariantJson, IConfigurationEnvironment } from '../api/RushConfiguration'; -import { RushConfigurationProject } from '../api/RushConfigurationProject'; -import { RushConstants } from '../logic/RushConstants'; -import { ShrinkwrapFileFactory } from '../logic/ShrinkwrapFileFactory'; -import { Stopwatch } from '../utilities/Stopwatch'; -import { Utilities } from '../utilities/Utilities'; -import { Rush } from '../api/Rush'; -import { PackageJsonEditor, DependencyType, PackageJsonDependency } from '../api/PackageJsonEditor'; -import { AlreadyReportedError } from '../utilities/AlreadyReportedError'; -import { CommonVersionsConfiguration } from '../api/CommonVersionsConfiguration'; -import { RushGlobalFolder } from '../api/RushGlobalFolder'; -import { PnpmPackageManager } from '../api/packageManager/PnpmPackageManager'; -import { DependencySpecifier } from './DependencySpecifier'; -import { EnvironmentConfiguration } from '../api/EnvironmentConfiguration'; +import { JsonFile, Text, FileSystem, FileConstants, Sort, PosixModeBits } from '@rushstack/node-core-library'; + +import { BaseInstallManager } from '../base/BaseInstallManager'; +import { BaseShrinkwrapFile } from '../../logic/base/BaseShrinkwrapFile'; +import { IRushTempPackageJson } from '../../logic/base/BasePackage'; +import { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { RushConstants } from '../../logic/RushConstants'; +import { Stopwatch } from '../../utilities/Stopwatch'; +import { Utilities } from '../../utilities/Utilities'; +import { PackageJsonEditor, DependencyType } from '../../api/PackageJsonEditor'; +import { DependencySpecifier } from '../DependencySpecifier'; import { InstallHelpers } from './InstallHelpers'; -// The PosixModeBits are intended to be used with bitwise operations. -/* eslint-disable no-bitwise */ - /** * The "noMtime" flag is new in tar@4.4.1 and not available yet for \@types/tar. * As a temporary workaround, augment the type. @@ -68,378 +36,26 @@ declare module 'tar' { } } -export interface IInstallManagerOptions { - /** - * Whether the global "--debug" flag was specified. - */ - debug: boolean; - /** - * Whether or not Rush will automatically update the shrinkwrap file. - * True for "rush update", false for "rush install". - */ - allowShrinkwrapUpdates: boolean; - /** - * Whether to skip policy checks. - */ - bypassPolicy: boolean; - /** - * Whether to skip linking, i.e. require "rush link" to be done manually later. - */ - noLink: boolean; - /** - * Whether to delete the shrinkwrap file before installation, i.e. so that all dependencies - * will be upgraded to the latest SemVer-compatible version. - */ - fullUpgrade: boolean; - /** - * Whether to force an update to the shrinkwrap file even if it appears to be unnecessary. - * Normally Rush uses heuristics to determine when "pnpm install" can be skipped, - * but sometimes the heuristics can be inaccurate due to external influences - * (pnpmfile.js script logic, registry changes, etc). - */ - recheckShrinkwrap: boolean; - - /** - * The value of the "--network-concurrency" command-line parameter, which - * is a diagnostic option used to troubleshoot network failures. - * - * Currently only supported for PNPM. - */ - networkConcurrency: number | undefined; - - /** - * Whether or not to collect verbose logs from the package manager. - * If specified when using PNPM, the logs will be in /common/temp/pnpm.log - */ - collectLogFile: boolean; - - /** - * The variant to consider when performing installations and validating shrinkwrap updates. - */ - variant?: string | undefined; - - /** - * Retry the install the specified number of times - */ - maxInstallAttempts: number; -} - /** * This class implements common logic between "rush install" and "rush update". */ -export class InstallManager { - private _rushConfiguration: RushConfiguration; - private _rushGlobalFolder: RushGlobalFolder; - private _commonNodeModulesMarker: LastInstallFlag; - private _commonTempFolderRecycler: AsyncRecycler; - - private _options: IInstallManagerOptions; - - public constructor( - rushConfiguration: RushConfiguration, - rushGlobalFolder: RushGlobalFolder, - purgeManager: PurgeManager, - options: IInstallManagerOptions - ) { - this._rushConfiguration = rushConfiguration; - this._rushGlobalFolder = rushGlobalFolder; - this._commonTempFolderRecycler = purgeManager.commonTempFolderRecycler; - this._options = options; - - const lastInstallState: JsonObject = { - node: process.versions.node, - packageManager: rushConfiguration.packageManager, - packageManagerVersion: rushConfiguration.packageManagerToolVersion - }; - - if (lastInstallState.packageManager === 'pnpm') { - lastInstallState.storePath = rushConfiguration.pnpmOptions.pnpmStorePath; - } - - this._commonNodeModulesMarker = new LastInstallFlag( - this._rushConfiguration.commonTempFolder, - lastInstallState - ); - } - - /** - * Returns a map of all direct dependencies that only have a single semantic version specifier. - * Returns a map: dependency name --> version specifier - */ - public static collectImplicitlyPreferredVersions( - rushConfiguration: RushConfiguration, - options: { - variant?: string | undefined; - } = {} - ): Map { - // First, collect all the direct dependencies of all local projects, and their versions: - // direct dependency name --> set of version specifiers - const versionsForDependencies: Map> = new Map>(); - - rushConfiguration.projects.forEach((project: RushConfigurationProject) => { - InstallManager._collectVersionsForDependencies(rushConfiguration, { - versionsForDependencies, - dependencies: project.packageJsonEditor.dependencyList, - cyclicDependencies: project.cyclicDependencyProjects, - variant: options.variant - }); - - InstallManager._collectVersionsForDependencies(rushConfiguration, { - versionsForDependencies, - dependencies: project.packageJsonEditor.devDependencyList, - cyclicDependencies: project.cyclicDependencyProjects, - variant: options.variant - }); - }); - - // If any dependency has more than one version, then filter it out (since we don't know which version - // should be preferred). What remains will be the list of preferred dependencies. - // dependency --> version specifier - const implicitlyPreferred: Map = new Map(); - versionsForDependencies.forEach((versions: Set, dep: string) => { - if (versions.size === 1) { - const version: string = versions.values().next().value; - implicitlyPreferred.set(dep, version); - } - }); - return implicitlyPreferred; - } - - // Helper for collectImplicitlyPreferredVersions() - private static _updateVersionsForDependencies( - versionsForDependencies: Map>, - dependency: string, - version: string - ): void { - if (!versionsForDependencies.has(dependency)) { - versionsForDependencies.set(dependency, new Set()); - } - versionsForDependencies.get(dependency)!.add(version); - } - - // Helper for collectImplicitlyPreferredVersions() - private static _collectVersionsForDependencies( - rushConfiguration: RushConfiguration, - options: { - versionsForDependencies: Map>; - dependencies: ReadonlyArray; - cyclicDependencies: Set; - variant: string | undefined; - } - ): void { - const { variant, dependencies, versionsForDependencies, cyclicDependencies } = options; - - const commonVersions: CommonVersionsConfiguration = rushConfiguration.getCommonVersions(variant); - - const allowedAlternativeVersions: Map> = - commonVersions.allowedAlternativeVersions; - - for (const dependency of dependencies) { - const alternativesForThisDependency: ReadonlyArray = - allowedAlternativeVersions.get(dependency.name) || []; - - // For each dependency, collectImplicitlyPreferredVersions() is collecting the set of all version specifiers - // that appear across the repo. If there is only one version specifier, then that's the "preferred" one. - // However, there are a few cases where additional version specifiers can be safely ignored. - let ignoreVersion: boolean = false; - - // 1. If the version specifier was listed in "allowedAlternativeVersions", then it's never a candidate. - // (Even if it's the only version specifier anywhere in the repo, we still ignore it, because - // otherwise the rule would be difficult to explain.) - if (alternativesForThisDependency.indexOf(dependency.version) > 0) { - ignoreVersion = true; - } else { - // Is it a local project? - const localProject: RushConfigurationProject | undefined = rushConfiguration.getProjectByName( - dependency.name - ); - if (localProject) { - // 2. If it's a symlinked local project, then it's not a candidate, because the package manager will - // never even see it. - // However there are two ways that a local project can NOT be symlinked: - // - if the local project doesn't satisfy the referenced semver specifier; OR - // - if the local project was specified in "cyclicDependencyProjects" in rush.json - if ( - semver.satisfies(localProject.packageJsonEditor.version, dependency.version) && - !cyclicDependencies.has(dependency.name) - ) { - ignoreVersion = true; - } - } - - if (!ignoreVersion) { - InstallManager._updateVersionsForDependencies( - versionsForDependencies, - dependency.name, - dependency.version - ); - } - } - } - } - - public get commonNodeModulesMarker(): LastInstallFlag { - return this._commonNodeModulesMarker; - } - - public async doInstall(): Promise { - const options: IInstallManagerOptions = this._options; - - // Check the policies - PolicyValidator.validatePolicy(this._rushConfiguration, options); - - // Git hooks are only installed if the repo opts in by including files in /common/git-hooks - const hookSource: string = path.join(this._rushConfiguration.commonFolder, 'git-hooks'); - const hookDestination: string | undefined = Git.getHooksFolder(); - - if (FileSystem.exists(hookSource) && hookDestination) { - const allHookFilenames: string[] = FileSystem.readFolder(hookSource); - // Ignore the ".sample" file(s) in this folder. - const hookFilenames: string[] = allHookFilenames.filter((x) => !/\.sample$/.test(x)); - if (hookFilenames.length > 0) { - console.log(os.EOL + colors.bold('Found files in the "common/git-hooks" folder.')); - - // Clear the currently installed git hooks and install fresh copies - FileSystem.ensureEmptyFolder(hookDestination); - - // Only copy files that look like Git hook names - const filteredHookFilenames: string[] = hookFilenames.filter((x) => /^[a-z\-]+/.test(x)); - for (const filename of filteredHookFilenames) { - // Copy the file. Important: For Bash scripts, the EOL must not be CRLF. - const hookFileContent: string = FileSystem.readFile(path.join(hookSource, filename)); - FileSystem.writeFile(path.join(hookDestination, filename), hookFileContent, { - convertLineEndings: NewlineKind.Lf - }); - - FileSystem.changePosixModeBits( - path.join(hookDestination, filename), - PosixModeBits.UserRead | PosixModeBits.UserExecute - ); - } - - console.log( - 'Successfully installed these Git hook scripts: ' + filteredHookFilenames.join(', ') + os.EOL - ); - } - } - - const approvedPackagesChecker: ApprovedPackagesChecker = new ApprovedPackagesChecker( - this._rushConfiguration - ); - if (approvedPackagesChecker.approvedPackagesFilesAreOutOfDate) { - if (this._options.allowShrinkwrapUpdates) { - approvedPackagesChecker.rewriteConfigFiles(); - console.log( - colors.yellow( - 'Approved package files have been updated. These updates should be committed to source control' - ) - ); - } else { - throw new Error(`Approved packages files are out-of date. Run "rush update" to update them.`); - } - } - - // Ensure that the package manager is installed - await InstallHelpers.ensureLocalPackageManager( - this._rushConfiguration, - this._rushGlobalFolder, - this._options.maxInstallAttempts - ); - - let shrinkwrapFile: BaseShrinkwrapFile | undefined = undefined; - - // (If it's a full update, then we ignore the shrinkwrap from Git since it will be overwritten) - if (!options.fullUpgrade) { - try { - shrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile( - this._rushConfiguration.packageManager, - this._rushConfiguration.packageManagerOptions, - this._rushConfiguration.getCommittedShrinkwrapFilename(options.variant) - ); - } catch (ex) { - console.log(); - console.log(`Unable to load the ${this._shrinkwrapFilePhrase}: ${ex.message}`); - - if (!options.allowShrinkwrapUpdates) { - console.log(); - console.log(colors.red('You need to run "rush update" to fix this problem')); - throw new AlreadyReportedError(); - } - - shrinkwrapFile = undefined; - } - } - - // Write a file indicating which variant is being installed. - // This will be used by bulk scripts to determine the correct Shrinkwrap file to track. - const currentVariantJsonFilename: string = this._rushConfiguration.currentVariantJsonFilename; - const currentVariantJson: ICurrentVariantJson = { - variant: options.variant || null // eslint-disable-line @rushstack/no-null - }; - - // Determine if the variant is already current by updating current-variant.json. - // If nothing is written, the variant has not changed. - const variantIsUpToDate: boolean = !JsonFile.save(currentVariantJson, currentVariantJsonFilename, { - onlyIfChanged: true - }); - - if (options.variant) { - console.log(); - console.log(colors.bold(`Using variant '${options.variant}' for installation.`)); - } else if (!variantIsUpToDate && !options.variant) { - console.log(); - console.log(colors.bold('Using the default variant for installation.')); - } - - const shrinkwrapIsUpToDate: boolean = - this._createTempModulesAndCheckShrinkwrap({ - shrinkwrapFile, - variant: options.variant - }) && !options.recheckShrinkwrap; - - if (!shrinkwrapIsUpToDate) { - if (!options.allowShrinkwrapUpdates) { - console.log(); - console.log( - colors.red(`The ${this._shrinkwrapFilePhrase} is out of date. You need to run "rush update".`) - ); - throw new AlreadyReportedError(); - } - } - - await this._installCommonModules({ - shrinkwrapIsUpToDate, - variantIsUpToDate, - ...options - }); - - if (!options.noLink) { - const linkManager: BaseLinkManager = LinkManagerFactory.getLinkManager(this._rushConfiguration); - await linkManager.createSymlinksForProjects(false); - } else { - console.log( - os.EOL + colors.yellow('Since "--no-link" was specified, you will need to run "rush link" manually.') - ); - } - } - +export class RushInstallManager extends BaseInstallManager { /** * Regenerates the common/package.json and all temp_modules projects. * If shrinkwrapFile is provided, this function also validates whether it contains * everything we need to install and returns true if so; in all other cases, * the return value is false. + * + * @override */ - private _createTempModulesAndCheckShrinkwrap(options: { - shrinkwrapFile: BaseShrinkwrapFile | undefined; - variant: string | undefined; - }): boolean { - const { shrinkwrapFile, variant } = options; - + protected async prepareAndCheckShrinkwrap( + shrinkwrapFile: BaseShrinkwrapFile | undefined + ): Promise<{ shrinkwrapIsUpToDate: boolean; shrinkwrapWarnings: string[] }> { const stopwatch: Stopwatch = Stopwatch.start(); // Example: "C:\MyRepo\common\temp\projects" const tempProjectsFolder: string = path.join( - this._rushConfiguration.commonTempFolder, + this.rushConfiguration.commonTempFolder, RushConstants.rushTempProjectsFolderName ); @@ -458,8 +74,8 @@ export class InstallManager { } // dependency name --> version specifier - const allExplicitPreferredVersions: Map = this._rushConfiguration - .getCommonVersions(variant) + const allExplicitPreferredVersions: Map = this.rushConfiguration + .getCommonVersions(this.options.variant) .getAllPreferredVersions(); if (shrinkwrapFile) { @@ -469,7 +85,7 @@ export class InstallManager { if (!shrinkwrapFile.hasCompatibleTopLevelDependency(dependencySpecifier)) { shrinkwrapWarnings.push( - `"${dependency}" (${version}) required by the preferred versions from ` + + `Missing dependency "${dependency}" (${version}) required by the preferred versions from ` + RushConstants.commonVersionsFilename ); shrinkwrapIsUpToDate = false; @@ -484,71 +100,18 @@ export class InstallManager { } } - // Also copy down the committed .npmrc file, if there is one - // "common\config\rush\.npmrc" --> "common\temp\.npmrc" - // Also ensure that we remove any old one that may be hanging around - Utilities.syncNpmrc( - this._rushConfiguration.commonRushConfigFolder, - this._rushConfiguration.commonTempFolder - ); - - // also, copy the pnpmfile.js if it exists - if (this._rushConfiguration.packageManager === 'pnpm') { - const committedPnpmFilePath: string = this._rushConfiguration.getPnpmfilePath(this._options.variant); - const tempPnpmFilePath: string = path.join( - this._rushConfiguration.commonTempFolder, - RushConstants.pnpmfileFilename - ); - - // ensure that we remove any old one that may be hanging around - this._syncFile(committedPnpmFilePath, tempPnpmFilePath); - } - - const commonPackageJson: IPackageJson = { - dependencies: {}, - description: 'Temporary file generated by the Rush tool', - name: 'rush-common', - private: true, - version: '0.0.0' - }; - // dependency name --> version specifier - const allPreferredVersions: Map = new Map(); - - // Should we add implicitly preferred versions? - let useImplicitlyPinnedVersions: boolean; - if (this._rushConfiguration.commonVersions.implicitlyPreferredVersions !== undefined) { - // Use the manually configured setting - useImplicitlyPinnedVersions = this._rushConfiguration.commonVersions.implicitlyPreferredVersions; - } else { - // Default to true. - useImplicitlyPinnedVersions = true; - } - - if (useImplicitlyPinnedVersions) { - // Add in the implicitly preferred versions. - // These are any first-level dependencies for which we only consume a single version range - // (e.g. every package that depends on react uses an identical specifier) - const implicitlyPreferredVersions: Map< - string, - string - > = InstallManager.collectImplicitlyPreferredVersions(this._rushConfiguration, { variant }); - MapExtensions.mergeFromMap(allPreferredVersions, implicitlyPreferredVersions); - } - - // Add in the explicitly preferred versions. - // Note that these take precedence over implicitly preferred versions. - MapExtensions.mergeFromMap(allPreferredVersions, allExplicitPreferredVersions); - - // Add any preferred versions to the top of the commonPackageJson - // do this in alphabetical order for simpler debugging - for (const dependency of Array.from(allPreferredVersions.keys()).sort()) { - commonPackageJson.dependencies![dependency] = allPreferredVersions.get(dependency)!; - } + const commonDependencies: Map = InstallHelpers.collectPreferredVersions( + this.rushConfiguration, + { + explicitPreferredVersions: allExplicitPreferredVersions, + variant: this.options.variant + } + ); // To make the common/package.json file more readable, sort alphabetically // according to rushProject.tempProjectName instead of packageName. - const sortedRushProjects: RushConfigurationProject[] = this._rushConfiguration.projects.slice(0); + const sortedRushProjects: RushConfigurationProject[] = this.rushConfiguration.projects.slice(0); Sort.sortBy(sortedRushProjects, (x) => x.tempProjectName); for (const rushProject of sortedRushProjects) { @@ -558,7 +121,7 @@ export class InstallManager { const tarballFile: string = this._getTarballFilePath(rushProject); // Example: dependencies["@rush-temp/my-project-2"] = "file:./projects/my-project-2.tgz" - commonPackageJson.dependencies![ + commonDependencies[ rushProject.tempProjectName ] = `file:./${RushConstants.rushTempProjectsFolderName}/${rushProject.unscopedTempProjectName}.tgz`; @@ -601,7 +164,7 @@ export class InstallManager { // If so, then we will symlink to the project folder rather than to common/temp/node_modules. // In this case, we don't want "npm install" to process this package, but we do need // to record this decision for "rush link" later, so we add it to a special 'rushDependencies' field. - const localProject: RushConfigurationProject | undefined = this._rushConfiguration.getProjectByName( + const localProject: RushConfigurationProject | undefined = this.rushConfiguration.getProjectByName( packageName ); @@ -627,9 +190,9 @@ export class InstallManager { let tryReusingPackageVersionsFromShrinkwrap: boolean = true; - if (this._rushConfiguration.packageManager === 'pnpm') { + if (this.rushConfiguration.packageManager === 'pnpm') { // Shrinkwrap churn optimization doesn't make sense when --frozen-lockfile is true - tryReusingPackageVersionsFromShrinkwrap = !this._rushConfiguration.experimentsConfiguration + tryReusingPackageVersionsFromShrinkwrap = !this.rushConfiguration.experimentsConfiguration .configuration.usePnpmFrozenLockfileForRushInstall; } @@ -642,7 +205,7 @@ export class InstallManager { ) ) { shrinkwrapWarnings.push( - `"${packageName}" (${packageVersion}) required by "${rushProject.packageName}"` + `Missing dependency "${packageName}" (${packageVersion}) required by "${rushProject.packageName}"` ); shrinkwrapIsUpToDate = false; } @@ -699,74 +262,19 @@ export class InstallManager { } } - // Example: "C:\MyRepo\common\temp\package.json" - const commonPackageJsonFilename: string = path.join( - this._rushConfiguration.commonTempFolder, - FileConstants.PackageJson - ); - - if (shrinkwrapFile) { - // If we have a (possibly incomplete) shrinkwrap file, check to see if any shrinkwrap-specific - // changes make the shrinkwrap out-of-date, and save it as the temporary file. - if (shrinkwrapFile.shouldForceRecheck()) { - shrinkwrapIsUpToDate = false; - } - - shrinkwrapFile.save(this._rushConfiguration.tempShrinkwrapFilename); - shrinkwrapFile.save(this._rushConfiguration.tempShrinkwrapPreinstallFilename); - } else { - // Otherwise delete the temporary file - FileSystem.deleteFile(this._rushConfiguration.tempShrinkwrapFilename); - - if (this._rushConfiguration.packageManager === 'pnpm') { - // Workaround for https://github.com/pnpm/pnpm/issues/1890 - // - // When "rush update --full" is run, rush deletes common/temp/pnpm-lock.yaml so that - // a new lockfile can be generated. But because of the above bug "pnpm install" would - // respect "common/temp/node_modules/.pnpm-lock.yaml" and thus would not generate a - // new lockfile. Deleting this file in addition to deleting common/temp/pnpm-lock.yaml - // ensures that a new lockfile will be generated with "rush update --full". - - const pnpmPackageManager: PnpmPackageManager = this._rushConfiguration - .packageManagerWrapper as PnpmPackageManager; - - FileSystem.deleteFile( - path.join( - this._rushConfiguration.commonTempFolder, - pnpmPackageManager.internalShrinkwrapRelativePath - ) - ); - } - } - - // Don't update the file timestamp unless the content has changed, since "rush install" - // will consider this timestamp - JsonFile.save(commonPackageJson, commonPackageJsonFilename, { onlyIfChanged: true }); + // Write the common package.json + InstallHelpers.generateCommonPackageJson(this.rushConfiguration, commonDependencies); stopwatch.stop(); console.log(`Finished creating temporary modules (${stopwatch.toString()})`); - if (shrinkwrapWarnings.length > 0) { - console.log(); - console.log( - colors.yellow( - Utilities.wrapWords(`The ${this._shrinkwrapFilePhrase} is missing the following dependencies:`) - ) - ); - - for (const shrinkwrapWarning of shrinkwrapWarnings) { - console.log(colors.yellow(' ' + shrinkwrapWarning)); - } - console.log(); - } - - return shrinkwrapIsUpToDate; + return { shrinkwrapIsUpToDate, shrinkwrapWarnings }; } private _getTempProjectFolder(rushProject: RushConfigurationProject): string { const unscopedTempProjectName: string = rushProject.unscopedTempProjectName; return path.join( - this._rushConfiguration.commonTempFolder, + this.rushConfiguration.commonTempFolder, RushConstants.rushTempProjectsFolderName, unscopedTempProjectName ); @@ -795,9 +303,10 @@ export class InstallManager { prefix: npmPackageFolder, filter: (path: string, stat: tar.FileStat): boolean => { if ( - !this._rushConfiguration.experimentsConfiguration.configuration.noChmodFieldInTarHeaderNormalization + !this.rushConfiguration.experimentsConfiguration.configuration.noChmodFieldInTarHeaderNormalization ) { stat.mode = + // eslint-disable-next-line no-bitwise (stat.mode & ~0x1ff) | PosixModeBits.AllRead | PosixModeBits.UserWrite | PosixModeBits.AllExecute; } return true; @@ -808,604 +317,242 @@ export class InstallManager { } /** - * Runs "npm/pnpm/yarn install" in the "common/temp" folder. + * Check whether or not the install is already valid, and therefore can be skipped. + * + * @override */ - private _installCommonModules( - options: { - shrinkwrapIsUpToDate: boolean; - variantIsUpToDate: boolean; - } & IInstallManagerOptions - ): Promise { - const { shrinkwrapIsUpToDate, variantIsUpToDate } = options; - - const usePnpmFrozenLockfile: boolean = - this._rushConfiguration.packageManager === 'pnpm' && - this._rushConfiguration.experimentsConfiguration.configuration.usePnpmFrozenLockfileForRushInstall === - true; - return Promise.resolve().then(() => { - console.log( - os.EOL + colors.bold('Checking node_modules in ' + this._rushConfiguration.commonTempFolder) + os.EOL - ); - - const commonNodeModulesFolder: string = path.join( - this._rushConfiguration.commonTempFolder, - 'node_modules' - ); - - // This marker file indicates that the last "rush install" completed successfully - const markerFileExistedAndWasValidAtStart: boolean = this._commonNodeModulesMarker.checkValidAndReportStoreIssues(); - - // If "--clean" or "--full-clean" was specified, or if the last install was interrupted, - // then we will need to delete the node_modules folder. Otherwise, we can do an incremental - // install. - const deleteNodeModules: boolean = !markerFileExistedAndWasValidAtStart; - - // Based on timestamps, can we skip this install entirely? - if (shrinkwrapIsUpToDate && !deleteNodeModules && variantIsUpToDate) { - const potentiallyChangedFiles: string[] = []; - - // Consider the timestamp on the node_modules folder; if someone tampered with it - // or deleted it entirely, then we can't skip this install - potentiallyChangedFiles.push(commonNodeModulesFolder); - - // Additionally, if they pulled an updated npm-shrinkwrap.json file from Git, - // then we can't skip this install - potentiallyChangedFiles.push(this._rushConfiguration.getCommittedShrinkwrapFilename(options.variant)); + protected canSkipInstall(lastModifiedDate: Date): boolean { + console.log( + os.EOL + + colors.bold( + `Checking ${RushConstants.nodeModulesFolderName} in ${this.rushConfiguration.commonTempFolder}` + ) + + os.EOL + ); - // Add common-versions.json file to the potentially changed files list. - potentiallyChangedFiles.push(this._rushConfiguration.getCommonVersionsFilePath(options.variant)); + // Based on timestamps, can we skip this install entirely? + const potentiallyChangedFiles: string[] = []; - if (this._rushConfiguration.packageManager === 'pnpm') { - // If the repo is using pnpmfile.js, consider that also - const pnpmFileFilename: string = this._rushConfiguration.getPnpmfilePath(options.variant); + // Consider the timestamp on the node_modules folder; if someone tampered with it + // or deleted it entirely, then we can't skip this install + potentiallyChangedFiles.push( + path.join(this.rushConfiguration.commonTempFolder, RushConstants.nodeModulesFolderName) + ); - if (FileSystem.exists(pnpmFileFilename)) { - potentiallyChangedFiles.push(pnpmFileFilename); - } - } + // Additionally, if they pulled an updated npm-shrinkwrap.json file from Git, + // then we can't skip this install + potentiallyChangedFiles.push(this.rushConfiguration.getCommittedShrinkwrapFilename(this.options.variant)); - // Also consider timestamps for all the temp tarballs. (createTempModulesAndCheckShrinkwrap() will - // carefully preserve these timestamps unless something has changed.) - // Example: "C:\MyRepo\common\temp\projects\my-project-2.tgz" - potentiallyChangedFiles.push( - ...this._rushConfiguration.projects.map((x) => { - return this._getTarballFilePath(x); - }) - ); + // Add common-versions.json file to the potentially changed files list. + potentiallyChangedFiles.push(this.rushConfiguration.getCommonVersionsFilePath(this.options.variant)); - // NOTE: If commonNodeModulesMarkerFilename (or any of the potentiallyChangedFiles) does not - // exist, then isFileTimestampCurrent() returns false. - if (Utilities.isFileTimestampCurrent(this._commonNodeModulesMarker.path, potentiallyChangedFiles)) { - // Nothing to do, because everything is up to date according to time stamps - return; - } - } + if (this.rushConfiguration.packageManager === 'pnpm') { + // If the repo is using pnpmfile.js, consider that also + const pnpmFileFilename: string = this.rushConfiguration.getPnpmfilePath(this.options.variant); - // Since we are actually running npm/pnpm/yarn install, recreate all the temp project tarballs. - // This ensures that any existing tarballs with older header bits will be regenerated. - // It is safe to assume that temp project pacakge.jsons already exist. - for (const rushProject of this._rushConfiguration.projects) { - this._createTempProjectTarball(rushProject); + if (FileSystem.exists(pnpmFileFilename)) { + potentiallyChangedFiles.push(pnpmFileFilename); } + } - return this._checkIfReleaseIsPublished() - .catch((error) => { - // If the user is working in an environment that can't reach the registry, - // don't bother them with errors. - return undefined; - }) - .then((publishedRelease: boolean | undefined) => { - if (publishedRelease === false) { - console.log( - colors.yellow('Warning: This release of the Rush tool was unpublished; it may be unstable.') - ); - } + // Also consider timestamps for all the temp tarballs. (createTempModulesAndCheckShrinkwrap() will + // carefully preserve these timestamps unless something has changed.) + // Example: "C:\MyRepo\common\temp\projects\my-project-2.tgz" + potentiallyChangedFiles.push( + ...this.rushConfiguration.projects.map((x) => { + return this._getTarballFilePath(x); + }) + ); - // Since we're going to be tampering with common/node_modules, delete the "rush link" flag file if it exists; - // this ensures that a full "rush link" is required next time - Utilities.deleteFile(this._rushConfiguration.rushLinkJsonFilename); + return Utilities.isFileTimestampCurrent(lastModifiedDate, potentiallyChangedFiles); + } - // Delete the successful install file to indicate the install transaction has started - this._commonNodeModulesMarker.clear(); + /** + * Runs "npm/pnpm/yarn install" in the "common/temp" folder. + * + * @override + */ + protected async install(cleanInstall: boolean): Promise { + // Since we are actually running npm/pnpm/yarn install, recreate all the temp project tarballs. + // This ensures that any existing tarballs with older header bits will be regenerated. + // It is safe to assume that temp project pacakge.jsons already exist. + for (const rushProject of this.rushConfiguration.projects) { + this._createTempProjectTarball(rushProject); + } - // NOTE: The PNPM store is supposed to be transactionally safe, so we don't delete it automatically. - // The user must request that via the command line. - if (deleteNodeModules) { - if (this._rushConfiguration.packageManager === 'npm') { - console.log(`Deleting the "npm-cache" folder`); - // This is faster and more thorough than "npm cache clean" - this._commonTempFolderRecycler.moveFolder(this._rushConfiguration.npmCacheFolder); + // NOTE: The PNPM store is supposed to be transactionally safe, so we don't delete it automatically. + // The user must request that via the command line. + if (cleanInstall) { + if (this.rushConfiguration.packageManager === 'npm') { + console.log(`Deleting the "npm-cache" folder`); + // This is faster and more thorough than "npm cache clean" + this.installRecycler.moveFolder(this.rushConfiguration.npmCacheFolder); - console.log(`Deleting the "npm-tmp" folder`); - this._commonTempFolderRecycler.moveFolder(this._rushConfiguration.npmTmpFolder); - } - } + console.log(`Deleting the "npm-tmp" folder`); + this.installRecycler.moveFolder(this.rushConfiguration.npmTmpFolder); + } + } - // Example: "C:\MyRepo\common\temp\npm-local\node_modules\.bin\npm" - const packageManagerFilename: string = this._rushConfiguration.packageManagerToolFilename; + // Example: "C:\MyRepo\common\temp\npm-local\node_modules\.bin\npm" + const packageManagerFilename: string = this.rushConfiguration.packageManagerToolFilename; - let packageManagerEnv: NodeJS.ProcessEnv = process.env; + const packageManagerEnv: NodeJS.ProcessEnv = InstallHelpers.getPackageManagerEnvironment( + this.rushConfiguration, + this.options + ); - let configurationEnvironment: IConfigurationEnvironment | undefined = undefined; + const commonNodeModulesFolder: string = path.join( + this.rushConfiguration.commonTempFolder, + RushConstants.nodeModulesFolderName + ); - if (this._rushConfiguration.packageManager === 'npm') { - if ( - this._rushConfiguration.npmOptions && - this._rushConfiguration.npmOptions.environmentVariables - ) { - configurationEnvironment = this._rushConfiguration.npmOptions.environmentVariables; - } - } else if (this._rushConfiguration.packageManager === 'pnpm') { - if ( - this._rushConfiguration.pnpmOptions && - this._rushConfiguration.pnpmOptions.environmentVariables - ) { - configurationEnvironment = this._rushConfiguration.pnpmOptions.environmentVariables; - } - } else if (this._rushConfiguration.packageManager === 'yarn') { - if ( - this._rushConfiguration.yarnOptions && - this._rushConfiguration.yarnOptions.environmentVariables - ) { - configurationEnvironment = this._rushConfiguration.yarnOptions.environmentVariables; - } - } + // Is there an existing "node_modules" folder to consider? + if (FileSystem.exists(commonNodeModulesFolder)) { + // Should we delete the entire "node_modules" folder? + if (cleanInstall) { + // YES: Delete "node_modules" - packageManagerEnv = this._mergeEnvironmentVariables(process.env, configurationEnvironment); - - // Is there an existing "node_modules" folder to consider? - if (FileSystem.exists(commonNodeModulesFolder)) { - // Should we delete the entire "node_modules" folder? - if (deleteNodeModules) { - // YES: Delete "node_modules" - - // Explain to the user why we are hosing their node_modules folder - console.log('Deleting files from ' + commonNodeModulesFolder); - - this._commonTempFolderRecycler.moveFolder(commonNodeModulesFolder); - - Utilities.createFolderWithRetry(commonNodeModulesFolder); - } else { - // NO: Prepare to do an incremental install in the "node_modules" folder - - // note: it is not necessary to run "prune" with pnpm - if (this._rushConfiguration.packageManager === 'npm') { - console.log( - `Running "${this._rushConfiguration.packageManager} prune"` + - ` in ${this._rushConfiguration.commonTempFolder}` - ); - const args: string[] = ['prune']; - this._pushConfigurationArgs(args, options); - - Utilities.executeCommandWithRetry( - this._options.maxInstallAttempts, - packageManagerFilename, - args, - this._rushConfiguration.commonTempFolder, - packageManagerEnv - ); - - // Delete the (installed image of) the temp projects, since "npm install" does not - // detect changes for "file:./" references. - // We recognize the temp projects by their names, which always start with "rush-". - - // Example: "C:\MyRepo\common\temp\node_modules\@rush-temp" - const pathToDeleteWithoutStar: string = path.join( - commonNodeModulesFolder, - RushConstants.rushTempNpmScope - ); - console.log(`Deleting ${pathToDeleteWithoutStar}\\*`); - // Glob can't handle Windows paths - const normalizedpathToDeleteWithoutStar: string = Text.replaceAll( - pathToDeleteWithoutStar, - '\\', - '/' - ); - - // Example: "C:/MyRepo/common/temp/node_modules/@rush-temp/*" - for (const tempModulePath of glob.sync( - globEscape(normalizedpathToDeleteWithoutStar) + '/*' - )) { - // We could potentially use AsyncRecycler here, but in practice these folders tend - // to be very small - Utilities.dangerouslyDeletePath(tempModulePath); - } - } - } - } + // Explain to the user why we are hosing their node_modules folder + console.log('Deleting files from ' + commonNodeModulesFolder); - if (this._rushConfiguration.packageManager === 'yarn') { - // Yarn does not correctly detect changes to a tarball, so we need to forcibly clear its cache - const yarnRushTempCacheFolder: string = path.join( - this._rushConfiguration.yarnCacheFolder, - 'v2', - 'npm-@rush-temp' - ); - if (FileSystem.exists(yarnRushTempCacheFolder)) { - console.log('Deleting ' + yarnRushTempCacheFolder); - Utilities.dangerouslyDeletePath(yarnRushTempCacheFolder); - } - } + this.installRecycler.moveFolder(commonNodeModulesFolder); - // Run "npm install" in the common folder - const installArgs: string[] = ['install']; - this._pushConfigurationArgs(installArgs, options); + Utilities.createFolderWithRetry(commonNodeModulesFolder); + } else { + // NO: Prepare to do an incremental install in the "node_modules" folder + // note: it is not necessary to run "prune" with pnpm + if (this.rushConfiguration.packageManager === 'npm') { console.log( - os.EOL + - colors.bold( - `Running "${this._rushConfiguration.packageManager} install" in` + - ` ${this._rushConfiguration.commonTempFolder}` - ) + - os.EOL + `Running "${this.rushConfiguration.packageManager} prune"` + + ` in ${this.rushConfiguration.commonTempFolder}` + ); + const args: string[] = ['prune']; + this.pushConfigurationArgs(args, this.options); + + Utilities.executeCommandWithRetry( + this.options.maxInstallAttempts, + packageManagerFilename, + args, + this.rushConfiguration.commonTempFolder, + packageManagerEnv ); - // If any diagnostic options were specified, then show the full command-line - if (options.debug || options.collectLogFile || options.networkConcurrency) { - console.log( - os.EOL + - colors.green('Invoking package manager: ') + - FileSystem.getRealPath(packageManagerFilename) + - ' ' + - installArgs.join(' ') + - os.EOL - ); - } - - try { - Utilities.executeCommandWithRetry( - this._options.maxInstallAttempts, - packageManagerFilename, - installArgs, - this._rushConfiguration.commonTempFolder, - packageManagerEnv, - false, - () => { - if (this._rushConfiguration.packageManager === 'pnpm') { - console.log(colors.yellow(`Deleting the "node_modules" folder`)); - this._commonTempFolderRecycler.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._commonTempFolderRecycler.moveFolder(this._rushConfiguration.pnpmOptions.pnpmStorePath); - } - - throw error; - } - - if (this._rushConfiguration.packageManager === 'npm') { - console.log(os.EOL + colors.bold('Running "npm shrinkwrap"...')); - const npmArgs: string[] = ['shrinkwrap']; - this._pushConfigurationArgs(npmArgs, options); - Utilities.executeCommand( - this._rushConfiguration.packageManagerToolFilename, - npmArgs, - this._rushConfiguration.commonTempFolder - ); - console.log('"npm shrinkwrap" completed' + os.EOL); - - this._fixupNpm5Regression(); - } - - if (options.allowShrinkwrapUpdates && (usePnpmFrozenLockfile || !shrinkwrapIsUpToDate)) { - // Shrinkwrap files may need to be post processed after install, so load and save it - const tempShrinkwrapFile: - | BaseShrinkwrapFile - | undefined = ShrinkwrapFileFactory.getShrinkwrapFile( - this._rushConfiguration.packageManager, - this._rushConfiguration.packageManagerOptions, - this._rushConfiguration.tempShrinkwrapFilename - ); - if (tempShrinkwrapFile) { - tempShrinkwrapFile.save(this._rushConfiguration.tempShrinkwrapFilename); - } - - // Copy (or delete) common\temp\pnpm-lock.yaml --> common\config\rush\pnpm-lock.yaml - this._syncFile( - this._rushConfiguration.tempShrinkwrapFilename, - this._rushConfiguration.getCommittedShrinkwrapFilename(options.variant) - ); - } else { - // TODO: Validate whether the package manager updated it in a nontrivial way - } - - // Finally, create the marker file to indicate a successful install - this._commonNodeModulesMarker.create(); - - console.log(''); - }); - }); - } + // Delete the (installed image of) the temp projects, since "npm install" does not + // detect changes for "file:./" references. + // We recognize the temp projects by their names, which always start with "rush-". - private _mergeEnvironmentVariables( - baseEnv: NodeJS.ProcessEnv, - environmentVariables?: IConfigurationEnvironment - ): NodeJS.ProcessEnv { - const packageManagerEnv: NodeJS.ProcessEnv = baseEnv; - - if (environmentVariables) { - // eslint-disable-next-line guard-for-in - for (const envVar in environmentVariables) { - let setEnvironmentVariable: boolean = true; - console.log(`\nProcessing definition for environment variable: ${envVar}`); - - if (baseEnv.hasOwnProperty(envVar)) { - setEnvironmentVariable = false; - console.log(`Environment variable already defined:`); - console.log(` Name: ${envVar}`); - console.log(` Existing value: ${baseEnv[envVar]}`); - console.log(` Value set in rush.json: ${environmentVariables[envVar].value}`); - - if (environmentVariables[envVar].override) { - setEnvironmentVariable = true; - console.log(`Overriding the environment variable with the value set in rush.json.`); - } else { - console.log(colors.yellow(`WARNING: Not overriding the value of the environment variable.`)); - } - } + // Example: "C:\MyRepo\common\temp\node_modules\@rush-temp" + const pathToDeleteWithoutStar: string = path.join( + commonNodeModulesFolder, + RushConstants.rushTempNpmScope + ); + console.log(`Deleting ${pathToDeleteWithoutStar}\\*`); + // Glob can't handle Windows paths + const normalizedpathToDeleteWithoutStar: string = Text.replaceAll( + pathToDeleteWithoutStar, + '\\', + '/' + ); - if (setEnvironmentVariable) { - if (this._options.debug) { - console.log(`Setting environment variable for package manager.`); - console.log(` Name: ${envVar}`); - console.log(` Value: ${environmentVariables[envVar].value}`); + // Example: "C:/MyRepo/common/temp/node_modules/@rush-temp/*" + for (const tempModulePath of glob.sync(globEscape(normalizedpathToDeleteWithoutStar) + '/*')) { + // We could potentially use AsyncRecycler here, but in practice these folders tend + // to be very small + Utilities.dangerouslyDeletePath(tempModulePath); } - packageManagerEnv[envVar] = environmentVariables[envVar].value; } } } - return packageManagerEnv; - } - - private _checkIfReleaseIsPublished(): Promise { - return Promise.resolve().then(() => { - const lastCheckFile: string = path.join( - this._rushGlobalFolder.nodeSpecificPath, - 'rush-' + Rush.version, - 'last-check.flag' + if (this.rushConfiguration.packageManager === 'yarn') { + // Yarn does not correctly detect changes to a tarball, so we need to forcibly clear its cache + const yarnRushTempCacheFolder: string = path.join( + this.rushConfiguration.yarnCacheFolder, + 'v2', + 'npm-@rush-temp' ); - - if (FileSystem.exists(lastCheckFile)) { - let cachedResult: boolean | 'error' | undefined = undefined; - try { - // NOTE: mtimeMs is not supported yet in Node.js 6.x - const nowMs: number = new Date().getTime(); - const ageMs: number = nowMs - FileSystem.getStatistics(lastCheckFile).mtime.getTime(); - const HOUR: number = 60 * 60 * 1000; - - // Is the cache too old? - if (ageMs < 24 * HOUR) { - // No, read the cached result - cachedResult = JsonFile.load(lastCheckFile); - } - } catch (e) { - // Unable to parse file - } - if (cachedResult === 'error') { - return Promise.reject(new Error('Unable to contact server')); - } - if (cachedResult === true || cachedResult === false) { - return cachedResult; - } + if (FileSystem.exists(yarnRushTempCacheFolder)) { + console.log('Deleting ' + yarnRushTempCacheFolder); + Utilities.dangerouslyDeletePath(yarnRushTempCacheFolder); } - - // Before we start the network operation, record a failed state. If the process exits for some reason, - // this will record the error. It will also update the timestamp to prevent other Rush instances - // from attempting to update the file. - JsonFile.save('error', lastCheckFile, { ensureFolderExists: true }); - - // For this check we use the official registry, not the private registry - return this._queryIfReleaseIsPublished('https://registry.npmjs.org:443') - .then((publishedRelease: boolean) => { - // Cache the result - JsonFile.save(publishedRelease, lastCheckFile, { ensureFolderExists: true }); - return publishedRelease; - }) - .catch((error: Error) => { - JsonFile.save('error', lastCheckFile, { ensureFolderExists: true }); - return Promise.reject(error); - }); - }); - } - - private _queryIfReleaseIsPublished(registryUrl: string): Promise { - let queryUrl: string = registryUrl; - if (queryUrl[-1] !== '/') { - queryUrl += '/'; } - // Note that the "@" symbol does not normally get URL-encoded - queryUrl += RushConstants.rushPackageName.replace('/', '%2F'); - - const userAgent: string = `pnpm/? npm/? node/${process.version} ${os.platform()} ${os.arch()}`; - const headers: fetch.Headers = new fetch.Headers(); - headers.append('user-agent', userAgent); - headers.append('accept', 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*'); + // Run "npm install" in the common folder + const installArgs: string[] = ['install']; + this.pushConfigurationArgs(installArgs, this.options); + + console.log( + os.EOL + + colors.bold( + `Running "${this.rushConfiguration.packageManager} install" in` + + ` ${this.rushConfiguration.commonTempFolder}` + ) + + os.EOL + ); - let agent: http.Agent | undefined = undefined; - if (process.env.HTTP_PROXY) { - agent = new HttpsProxyAgent(process.env.HTTP_PROXY); + // If any diagnostic options were specified, then show the full command-line + if (this.options.debug || this.options.collectLogFile || this.options.networkConcurrency) { + console.log( + os.EOL + + colors.green('Invoking package manager: ') + + FileSystem.getRealPath(packageManagerFilename) + + ' ' + + installArgs.join(' ') + + os.EOL + ); } - return fetch - .default(queryUrl, { - headers: headers, - agent: agent - }) - .then((response: fetch.Response) => { - if (!response.ok) { - return Promise.reject(new Error('Failed to query')); - } - return response.json().then((data) => { - let url: string; - try { - if (!data.versions[Rush.version]) { - // Version was not published - return false; - } - url = data.versions[Rush.version].dist.tarball; - if (!url) { - return Promise.reject(new Error(`URL not found`)); - } - } catch (e) { - return Promise.reject(new Error('Error parsing response')); + try { + Utilities.executeCommandWithRetry( + this.options.maxInstallAttempts, + packageManagerFilename, + installArgs, + this.rushConfiguration.commonTempFolder, + packageManagerEnv, + false, + () => { + 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); } - - // Make sure the tarball wasn't deleted from the CDN - headers.set('accept', '*/*'); - return fetch - .default(url, { - headers: headers, - agent: agent - }) - .then((response2: fetch.Response) => { - if (!response2.ok) { - if (response2.status === 404) { - return false; - } else { - return Promise.reject(new Error('Failed to fetch')); - } - } - return true; - }); - }); - }); - } - - /** - * Used when invoking the NPM tool. Appends the common configuration options - * to the command-line. - */ - private _pushConfigurationArgs(args: string[], options: IInstallManagerOptions): void { - if (this._rushConfiguration.packageManager === 'npm') { - if (semver.lt(this._rushConfiguration.packageManagerToolVersion, '5.0.0')) { - // NOTE: - // - // When using an npm version older than v5.0.0, we do NOT install optional dependencies for - // Rush, because npm does not generate the shrinkwrap file consistently across platforms. - // - // Consider the "fsevents" package. This is a Mac specific package - // which is an optional second-order dependency. Optional dependencies work by attempting to install - // the package, but removes the package if the install failed. - // This means that someone running generate on a Mac WILL have fsevents included in their shrinkwrap. - // When someone using Windows attempts to install from the shrinkwrap, the install will fail. - // - // If someone generates the shrinkwrap using Windows, then fsevents will NOT be listed in the shrinkwrap. - // When someone using Mac attempts to install from the shrinkwrap, they will NOT have the - // optional dependency installed. - // - // This issue has been fixed as of npm v5.0.0: https://github.com/npm/npm/releases/tag/v5.0.0 - // - // For more context, see https://github.com/microsoft/rushstack/issues/761#issuecomment-428689600 - args.push('--no-optional'); - } - args.push('--cache', this._rushConfiguration.npmCacheFolder); - args.push('--tmp', this._rushConfiguration.npmTmpFolder); - - if (options.collectLogFile) { - args.push('--verbose'); - } - } else if (this._rushConfiguration.packageManager === 'pnpm') { - // Only explicitly define the store path if `pnpmStore` is using the default, or has been set to - // 'local'. If `pnpmStore` = 'global', then allow PNPM to use the system's default - // path. In all cases, this will be overridden by RUSH_PNPM_STORE_PATH - if ( - this._rushConfiguration.pnpmOptions.pnpmStore === 'local' || - EnvironmentConfiguration.pnpmStorePathOverride - ) { - args.push('--store', this._rushConfiguration.pnpmOptions.pnpmStorePath); - } - - // we are using the --no-lock flag for now, which unfortunately prints a warning, but should be OK - // since rush already has its own install lock file which will invalidate the cache for us. - // we theoretically could use the lock file, but we would need to clean the store if the - // lockfile existed, otherwise PNPM would hang indefinitely. it is simpler to rely on Rush's - // last install flag, which encapsulates the entire installation - args.push('--no-lock'); + } + ); + } catch (error) { + // All the install attempts failed. if ( - this._rushConfiguration.experimentsConfiguration.configuration.usePnpmFrozenLockfileForRushInstall && - !this._options.allowShrinkwrapUpdates + this.rushConfiguration.packageManager === 'pnpm' && + this.rushConfiguration.pnpmOptions.pnpmStore === 'local' ) { - if (semver.gte(this._rushConfiguration.packageManagerToolVersion, '3.0.0')) { - args.push('--frozen-lockfile'); - } else { - args.push('--frozen-shrinkwrap'); - } - } else { - // Ensure that Rush's tarball dependencies get synchronized properly with the pnpm-lock.yaml file. - // See this GitHub issue: https://github.com/pnpm/pnpm/issues/1342 - if (semver.gte(this._rushConfiguration.packageManagerToolVersion, '3.0.0')) { - args.push('--no-prefer-frozen-lockfile'); - } else { - args.push('--no-prefer-frozen-shrinkwrap'); - } - } - - if (options.collectLogFile) { - args.push('--reporter', 'ndjson'); - } - - if (options.networkConcurrency) { - args.push('--network-concurrency', options.networkConcurrency.toString()); + // 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); } - if (this._rushConfiguration.pnpmOptions.strictPeerDependencies) { - args.push('--strict-peer-dependencies'); - } - - if ((this._rushConfiguration.packageManagerWrapper as PnpmPackageManager).supportsResolutionStrategy) { - args.push(`--resolution-strategy=${this._rushConfiguration.pnpmOptions.resolutionStrategy}`); - } - } else if (this._rushConfiguration.packageManager === 'yarn') { - args.push('--link-folder', 'yarn-link'); - args.push('--cache-folder', this._rushConfiguration.yarnCacheFolder); - - // Without this option, Yarn will sometimes stop and ask for user input on STDIN - // (e.g. "Which command would you like to run?"). - args.push('--non-interactive'); - - if (options.networkConcurrency) { - args.push('--network-concurrency', options.networkConcurrency.toString()); - } - - if (this._rushConfiguration.yarnOptions.ignoreEngines) { - args.push('--ignore-engines'); - } + throw error; } - } - /** - * Copies the file "sourcePath" to "destinationPath", overwriting the target file location. - * If the source file does not exist, then the target file is deleted. - */ - private _syncFile(sourcePath: string, destinationPath: string): void { - if (FileSystem.exists(sourcePath)) { - console.log('Updating ' + destinationPath); - FileSystem.copyFile({ sourcePath, destinationPath }); - } else { - if (FileSystem.exists(destinationPath)) { - console.log('Deleting ' + destinationPath); - FileSystem.deleteFile(destinationPath); - } + if (this.rushConfiguration.packageManager === 'npm') { + console.log(os.EOL + colors.bold('Running "npm shrinkwrap"...')); + const npmArgs: string[] = ['shrinkwrap']; + this.pushConfigurationArgs(npmArgs, this.options); + Utilities.executeCommand( + this.rushConfiguration.packageManagerToolFilename, + npmArgs, + this.rushConfiguration.commonTempFolder + ); + console.log('"npm shrinkwrap" completed' + os.EOL); + + this._fixupNpm5Regression(); } } @@ -1415,7 +562,7 @@ export class InstallManager { */ private _getTarballFilePath(project: RushConfigurationProject): string { return path.join( - this._rushConfiguration.commonTempFolder, + this.rushConfiguration.commonTempFolder, RushConstants.rushTempProjectsFolderName, `${project.unscopedTempProjectName}.tgz` ); @@ -1437,7 +584,7 @@ export class InstallManager { */ private _fixupNpm5Regression(): void { const pathToDeleteWithoutStar: string = path.join( - this._rushConfiguration.commonTempFolder, + this.rushConfiguration.commonTempFolder, 'node_modules', RushConstants.rushTempNpmScope ); @@ -1475,12 +622,12 @@ export class InstallManager { private _findOrphanedTempProjects(shrinkwrapFile: BaseShrinkwrapFile): boolean { // We can recognize temp projects because they are under the "@rush-temp" NPM scope. for (const tempProjectName of shrinkwrapFile.getTempProjectNames()) { - if (!this._rushConfiguration.findProjectByTempName(tempProjectName)) { + if (!this.rushConfiguration.findProjectByTempName(tempProjectName)) { console.log( os.EOL + colors.yellow( Utilities.wrapWords( - `Your ${this._shrinkwrapFilePhrase} references a project "${tempProjectName}" which no longer exists.` + `Your ${this.rushConfiguration.shrinkwrapFilePhrase} references a project "${tempProjectName}" which no longer exists.` ) ) + os.EOL @@ -1491,8 +638,4 @@ export class InstallManager { return false; // none found } - - private get _shrinkwrapFilePhrase(): string { - return this._rushConfiguration.shrinkwrapFilePhrase; - } } diff --git a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts new file mode 100644 index 00000000000..5a168e208b7 --- /dev/null +++ b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -0,0 +1,472 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as colors from 'colors'; +import * as os from 'os'; +import * as path from 'path'; +import * as semver from 'semver'; +import { FileSystem, InternalError } from '@rushstack/node-core-library'; + +import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; +import { BaseInstallManager, IInstallManagerOptions } from '../base/BaseInstallManager'; +import { BaseShrinkwrapFile } from '../../logic/base/BaseShrinkwrapFile'; +import { DependencySpecifier } from '../DependencySpecifier'; +import { PackageJsonEditor, DependencyType } from '../../api/PackageJsonEditor'; +import { PnpmWorkspaceFile } from '../pnpm/PnpmWorkspaceFile'; +import { RushConfiguration } from '../../api/RushConfiguration'; +import { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { RushConstants } from '../../logic/RushConstants'; +import { Stopwatch } from '../../utilities/Stopwatch'; +import { Utilities } from '../../utilities/Utilities'; +import { InstallHelpers } from './InstallHelpers'; + +/** + * This class implements common logic between "rush install" and "rush update". + */ +export class WorkspaceInstallManager extends BaseInstallManager { + public static getCommonWorkspaceKey(rushConfiguration: RushConfiguration): string { + switch (rushConfiguration.packageManager) { + case 'pnpm': + return '.'; + default: + throw new InternalError('Not implemented'); + } + } + + /** + * @override + */ + public async doInstall(): Promise { + // Workspaces do not support the no-link option, so throw if this is passed + if (this.options.noLink) { + console.log(); + console.log( + colors.red( + 'The "--no-link" option was provided but is not supported when using workspaces. Run the command again ' + + 'without specifying this argument.' + ) + ); + throw new AlreadyReportedError(); + } + + await super.doInstall(); + } + + /** + * Regenerates the common/package.json and related workspace files. + * If shrinkwrapFile is provided, this function also validates whether it contains + * everything we need to install and returns true if so; in all other cases, + * the return value is false. + * + * @override + */ + protected async prepareAndCheckShrinkwrap( + shrinkwrapFile: BaseShrinkwrapFile | undefined + ): Promise<{ shrinkwrapIsUpToDate: boolean; shrinkwrapWarnings: string[] }> { + const stopwatch: Stopwatch = Stopwatch.start(); + + console.log( + os.EOL + colors.bold('Updating workspace files in ' + this.rushConfiguration.commonTempFolder) + ); + + const shrinkwrapWarnings: string[] = []; + + // We will start with the assumption that it's valid, and then set it to false if + // any of the checks fail + let shrinkwrapIsUpToDate: boolean = true; + + if (!shrinkwrapFile) { + shrinkwrapIsUpToDate = false; + } else { + if ( + shrinkwrapFile.getWorkspaceKeys().length === 0 && + this.rushConfiguration.projects.length !== 0 && + !this.options.fullUpgrade + ) { + console.log(); + console.log( + colors.red( + 'The shrinkwrap file has not been updated to support workspaces. Run "rush update --full" to update ' + + 'the shrinkwrap file.' + ) + ); + throw new AlreadyReportedError(); + } + } + + // dependency name --> version specifier + const allExplicitPreferredVersions: Map = this.rushConfiguration + .getCommonVersions(this.options.variant) + .getAllPreferredVersions(); + + if (shrinkwrapFile) { + // Check any (explicitly) preferred dependencies first + allExplicitPreferredVersions.forEach((version: string, dependency: string) => { + const dependencySpecifier: DependencySpecifier = new DependencySpecifier(dependency, version); + + // The common package.json is used to ensure common versions are installed, so look for this workspace + // and validate that the requested dependency is specified + if ( + !shrinkwrapFile.hasCompatibleWorkspaceDependency( + dependencySpecifier, + WorkspaceInstallManager.getCommonWorkspaceKey(this.rushConfiguration) + ) + ) { + shrinkwrapWarnings.push( + `Missing dependency "${dependency}" (${version}) required by the preferred versions from ` + + RushConstants.commonVersionsFilename + ); + shrinkwrapIsUpToDate = false; + } + }); + + if (this._findOrphanedWorkspaceProjects(shrinkwrapFile)) { + // If there are any orphaned projects, then install would fail because the shrinkwrap + // contains references that refer to nonexistent file paths. + shrinkwrapIsUpToDate = false; + } + } + + // To generate the workspace file, we will add each project to the file as we loop through and validate + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile( + path.join(this.rushConfiguration.commonTempFolder, 'pnpm-workspace.yaml') + ); + + // Loop through the projects and add them to the workspace file. While we're at it, also validate that + // referenced workspace projects are valid, and check if the shrinkwrap file is already up-to-date. + for (const rushProject of this.rushConfiguration.projects) { + const packageJson: PackageJsonEditor = rushProject.packageJsonEditor; + workspaceFile.addPackage(rushProject.projectFolder); + + for (const { name, version, dependencyType } of [ + ...packageJson.dependencyList, + ...packageJson.devDependencyList + ]) { + const dependencySpecifier: DependencySpecifier = new DependencySpecifier(name, version); + + // Is there a locally built Rush project that could satisfy this dependency? + const referencedLocalProject: + | RushConfigurationProject + | undefined = this.rushConfiguration.getProjectByName(name); + + // Validate that local projects are referenced with workspace notation. If not, and it is not a + // cyclic dependency, then it needs to be updated to specify `workspace:*` explicitly. Currently only + // supporting versions and version ranges for specifying a local project. + if ( + (dependencySpecifier.specifierType === 'version' || + dependencySpecifier.specifierType === 'range') && + referencedLocalProject && + !rushProject.cyclicDependencyProjects.has(name) + ) { + // Make sure that this version is intended to target a local package. If not, then we will fail since it + // is not explicitly specified as a cyclic dependency. + if ( + !semver.satisfies( + referencedLocalProject.packageJsonEditor.version, + dependencySpecifier.versionSpecifier + ) + ) { + console.log(); + console.log( + colors.red( + `"${rushProject.packageName}" depends on package "${name}" (${version}) which exists ` + + 'within the workspace but cannot be fulfilled with the specified version range. Either ' + + 'specify a valid version range, or add the package as a cyclic dependency.' + ) + ); + throw new AlreadyReportedError(); + } + + if (!this.options.allowShrinkwrapUpdates) { + console.log(); + console.log( + colors.red( + `"${rushProject.packageName}" depends on package "${name}" (${version}) which exists within ` + + 'the workspace. Run "rush update" to update workspace references for this package.' + ) + ); + throw new AlreadyReportedError(); + } + + // We will update to `workspace:*` by default to ensure we're always using the workspace package. + packageJson.addOrUpdateDependency(name, 'workspace:*', dependencyType); + shrinkwrapIsUpToDate = false; + continue; + } else if (dependencySpecifier.specifierType === 'workspace') { + // Already specified as a local project. Allow the package manager to validate this + continue; + } + + // Allow the package manager to handle peer dependency resolution, since this is simply a constraint + // enforced by the package manager + if (dependencyType === DependencyType.Peer) { + continue; + } + + // It is not a local dependency, validate that it is compatible + if ( + shrinkwrapFile && + !shrinkwrapFile.hasCompatibleWorkspaceDependency( + dependencySpecifier, + shrinkwrapFile.getWorkspaceKeyByPath( + this.rushConfiguration.commonTempFolder, + rushProject.projectFolder + ) + ) + ) { + shrinkwrapWarnings.push( + `Missing dependency "${name}" (${version}) required by "${rushProject.packageName}"` + ); + shrinkwrapIsUpToDate = false; + } + } + + // Save the package.json if we modified the version references and warn that the package.json was modified + if (packageJson.saveIfModified()) { + console.log( + colors.yellow( + `"${rushProject.packageName}" depends on one or more workspace packages which did not use "workspace:" ` + + 'notation. The package.json has been modified and must be committed to source control.' + ) + ); + } + } + + const allPreferredVersions: Map = InstallHelpers.collectPreferredVersions( + this.rushConfiguration, + { + explicitPreferredVersions: allExplicitPreferredVersions, + variant: this.options.variant + } + ); + + // Write the common package.json + InstallHelpers.generateCommonPackageJson(this.rushConfiguration, allPreferredVersions); + + // Save the generated workspace file. Don't update the file timestamp unless the content has changed, + // since "rush install" will consider this timestamp + workspaceFile.save(workspaceFile.workspaceFilename, { onlyIfChanged: true }); + + stopwatch.stop(); + console.log(`Finished creating workspace (${stopwatch.toString()})`); + + return { shrinkwrapIsUpToDate, shrinkwrapWarnings }; + } + + protected canSkipInstall(lastModifiedDate: Date): boolean { + console.log( + os.EOL + + colors.bold( + `Checking ${RushConstants.nodeModulesFolderName} in ${this.rushConfiguration.commonTempFolder}` + ) + + os.EOL + ); + + // Based on timestamps, can we skip this install entirely? + const potentiallyChangedFiles: string[] = []; + + // Consider the timestamp on the node_modules folder; if someone tampered with it + // or deleted it entirely, then we can't skip this install + potentiallyChangedFiles.push( + path.join(this.rushConfiguration.commonTempFolder, RushConstants.nodeModulesFolderName) + ); + + // Additionally, if they pulled an updated npm-shrinkwrap.json file from Git, + // then we can't skip this install + potentiallyChangedFiles.push(this.rushConfiguration.getCommittedShrinkwrapFilename(this.options.variant)); + + // Add common-versions.json file to the potentially changed files list. + potentiallyChangedFiles.push(this.rushConfiguration.getCommonVersionsFilePath(this.options.variant)); + + if (this.rushConfiguration.packageManager === 'pnpm') { + // If the repo is using pnpmfile.js, consider that also + const pnpmFileFilename: string = this.rushConfiguration.getPnpmfilePath(this.options.variant); + + if (FileSystem.exists(pnpmFileFilename)) { + potentiallyChangedFiles.push(pnpmFileFilename); + } + + // Add workspace file. This file is only modified when workspace packages change. + const pnpmWorkspaceFilename: string = path.join( + this.rushConfiguration.commonTempFolder, + 'pnpm-workspace.yaml' + ); + + if (FileSystem.exists(pnpmWorkspaceFilename)) { + potentiallyChangedFiles.push(); + } + } + + // Also consider timestamps for all the project node_modules folders. + // Example: "C:\MyRepo\projects\projectA\node_modules" + potentiallyChangedFiles.push( + ...this.rushConfiguration.projects.map((x) => { + return path.join(x.projectFolder, RushConstants.nodeModulesFolderName); + }) + ); + + // NOTE: If any of the potentiallyChangedFiles does not exist, then isFileTimestampCurrent() + // returns false. + return Utilities.isFileTimestampCurrent(lastModifiedDate, potentiallyChangedFiles); + } + + /** + * Runs "npm install" in the common folder. + */ + protected async install(cleanInstall: boolean): Promise { + // Example: "C:\MyRepo\common\temp\npm-local\node_modules\.bin\npm" + const packageManagerFilename: string = this.rushConfiguration.packageManagerToolFilename; + + const packageManagerEnv: NodeJS.ProcessEnv = InstallHelpers.getPackageManagerEnvironment( + this.rushConfiguration, + this.options + ); + + const commonNodeModulesFolder: string = path.join( + this.rushConfiguration.commonTempFolder, + RushConstants.nodeModulesFolderName + ); + + // Is there an existing "node_modules" folder to consider? + if (FileSystem.exists(commonNodeModulesFolder)) { + // Should we delete the entire "node_modules" folder? + if (cleanInstall) { + // YES: Delete "node_modules" + + // Explain to the user why we are hosing their node_modules folder + console.log('Deleting files from ' + commonNodeModulesFolder); + + this.installRecycler.moveFolder(commonNodeModulesFolder); + + Utilities.createFolderWithRetry(commonNodeModulesFolder); + } + } + + // Run "npm install" in the common folder + const installArgs: string[] = ['install']; + this.pushConfigurationArgs(installArgs, this.options); + + console.log( + os.EOL + + colors.bold( + `Running "${this.rushConfiguration.packageManager} install" in` + + ` ${this.rushConfiguration.commonTempFolder}` + ) + + os.EOL + ); + + // If any diagnostic options were specified, then show the full command-line + if (this.options.debug || this.options.collectLogFile || this.options.networkConcurrency) { + console.log( + os.EOL + + colors.green('Invoking package manager: ') + + FileSystem.getRealPath(packageManagerFilename) + + ' ' + + installArgs.join(' ') + + os.EOL + ); + } + + try { + Utilities.executeCommandWithRetry( + this.options.maxInstallAttempts, + packageManagerFilename, + installArgs, + this.rushConfiguration.commonTempFolder, + packageManagerEnv, + false, + () => { + 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); + } + } + ); + + // Ensure that node_modules folders exist after install, since the timestamps on these folders are used + // to determine if the install can be skipped + const projectNodeModulesFolders: string[] = [ + path.join(this.rushConfiguration.commonTempFolder, RushConstants.nodeModulesFolderName), + ...this.rushConfiguration.projects.map((x) => { + return path.join(x.projectFolder, RushConstants.nodeModulesFolderName); + }) + ]; + + for (const nodeModulesFolder of projectNodeModulesFolders) { + FileSystem.ensureFolder(nodeModulesFolder); + } + } 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; + } + + console.log(''); + } + + /** + * Used when invoking the NPM tool. Appends the common configuration options + * to the command-line. + */ + protected pushConfigurationArgs(args: string[], options: IInstallManagerOptions): void { + super.pushConfigurationArgs(args, options); + + // Add workspace-specific args + if (this.rushConfiguration.packageManager === 'pnpm') { + args.push('--recursive'); + args.push('--link-workspace-packages', 'false'); + } + } + + /** + * Checks for projects that exist in the shrinkwrap file, but don't exist + * in rush.json. This might occur, e.g. if a project was recently deleted or renamed. + * + * @returns true if orphans were found, or false if everything is okay + */ + private _findOrphanedWorkspaceProjects(shrinkwrapFile: BaseShrinkwrapFile): boolean { + for (const workspaceKey of shrinkwrapFile.getWorkspaceKeys()) { + // Look for the RushConfigurationProject using the workspace key + let rushProjectPath: string; + if (this.rushConfiguration.packageManager === 'pnpm') { + // PNPM workspace keys are relative paths from the workspace root, which is the common temp folder + rushProjectPath = path.resolve(this.rushConfiguration.commonTempFolder, workspaceKey); + } else { + throw new InternalError('Orphaned workspaces cannot be checked for the provided package manager'); + } + + if (!this.rushConfiguration.tryGetProjectForPath(rushProjectPath)) { + console.log( + os.EOL + + colors.yellow( + Utilities.wrapWords( + `Your ${this.rushConfiguration.shrinkwrapFilePhrase} references a project at "${rushProjectPath}" ` + + 'which no longer exists.' + ) + ) + + os.EOL + ); + return true; // found one + } + } + + return false; // none found + } +} diff --git a/apps/rush-lib/src/logic/npm/NpmShrinkwrapFile.ts b/apps/rush-lib/src/logic/npm/NpmShrinkwrapFile.ts index a2267d4a49e..9f02b415259 100644 --- a/apps/rush-lib/src/logic/npm/NpmShrinkwrapFile.ts +++ b/apps/rush-lib/src/logic/npm/NpmShrinkwrapFile.ts @@ -1,6 +1,6 @@ import * as os from 'os'; -import { JsonFile, FileSystem } from '@rushstack/node-core-library'; +import { JsonFile, FileSystem, InternalError } from '@rushstack/node-core-library'; import { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; import { DependencySpecifier } from '../DependencySpecifier'; @@ -114,4 +114,22 @@ export class NpmShrinkwrapFile extends BaseShrinkwrapFile { return new DependencySpecifier(dependencySpecifier.packageName, dependencyJson.version); } + + /** @override */ + public getWorkspaceKeys(): ReadonlyArray { + throw new InternalError('Not implemented'); + } + + /** @override */ + public getWorkspaceKeyByPath(workspaceRoot: string, projectFolder: string): string { + throw new InternalError('Not implemented'); + } + + /** @override */ + protected getWorkspaceDependencyVersion( + dependencySpecifier: DependencySpecifier, + workspaceKey: string + ): DependencySpecifier | undefined { + throw new InternalError('Not implemented'); + } } diff --git a/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts b/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts index b2cd99f118e..5db6587ab25 100644 --- a/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts +++ b/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts @@ -15,8 +15,14 @@ import { BasePackage } from '../base/BasePackage'; import { RushConstants } from '../../logic/RushConstants'; import { IRushLinkJson } from '../../api/RushConfiguration'; import { RushConfigurationProject } from '../../api/RushConfigurationProject'; -import { PnpmShrinkwrapFile, IPnpmShrinkwrapDependencyYaml } from './PnpmShrinkwrapFile'; +import { + PnpmShrinkwrapFile, + IPnpmShrinkwrapDependencyYaml, + IPnpmShrinkwrapImporterYaml +} from './PnpmShrinkwrapFile'; import { PnpmProjectDependencyManifest } from './PnpmProjectDependencyManifest'; +import { PackageJsonDependency, DependencyType } from '../../api/PackageJsonEditor'; +import { DependencySpecifier } from '../DependencySpecifier'; // special flag for debugging, will print extra diagnostic information, // but comes with performance cost @@ -46,9 +52,18 @@ export class PnpmLinkManager extends BaseLinkManager { ); } + const useWorkspaces: boolean = + this._rushConfiguration.packageManager === 'pnpm' && + this._rushConfiguration.pnpmOptions && + this._rushConfiguration.pnpmOptions.useWorkspaces; + for (const rushProject of this._rushConfiguration.projects) { console.log(os.EOL + 'LINKING: ' + rushProject.packageName); - await this._linkProject(rushProject, rushLinkJson, pnpmShrinkwrapFile); + if (useWorkspaces) { + await this._linkWorkspaceProject(rushProject, rushLinkJson, pnpmShrinkwrapFile); + } else { + await this._linkProject(rushProject, rushLinkJson, pnpmShrinkwrapFile); + } } } else { console.log( @@ -290,6 +305,116 @@ export class PnpmLinkManager extends BaseLinkManager { }); } + /** + * This is called once for each local project from Rush.json. + * @param project The local project that we will create symlinks for + * @param rushLinkJson The common/temp/rush-link.json output file + */ + private async _linkWorkspaceProject( + project: RushConfigurationProject, + rushLinkJson: IRushLinkJson, + pnpmShrinkwrapFile: PnpmShrinkwrapFile + ): Promise { + // First, generate the local dependency graph. When using workspaces, Rush forces `workspace:` + // notation for all locally-referenced projects. + const localDependencies: PackageJsonDependency[] = [ + ...project.packageJsonEditor.dependencyList, + ...project.packageJsonEditor.devDependencyList + ].filter((x) => new DependencySpecifier(x.name, x.version).specifierType === 'workspace'); + + for (const { name } of localDependencies) { + const matchedRushPackage: + | RushConfigurationProject + | undefined = this._rushConfiguration.getProjectByName(name); + + if (matchedRushPackage) { + // We found a suitable match, so add the local package as a local link + let localLinks: string[] = rushLinkJson.localLinks[project.packageName]; + if (!localLinks) { + localLinks = []; + rushLinkJson.localLinks[project.packageName] = localLinks; + } + localLinks.push(name); + } else { + throw new InternalError( + `Cannot find dependency "${name}" for "${project.packageName}" in the Rush configuration` + ); + } + } + + const importerKey: string = pnpmShrinkwrapFile.getWorkspaceKeyByPath( + this._rushConfiguration.commonTempFolder, + project.projectFolder + ); + const workspaceImporter: + | IPnpmShrinkwrapImporterYaml + | undefined = pnpmShrinkwrapFile.getWorkspaceImporter(importerKey); + if (!workspaceImporter) { + throw new InternalError( + `Cannot find shrinkwrap entry using importer key for workspace project: ${importerKey}` + ); + } + const pnpmProjectDependencyManifest: PnpmProjectDependencyManifest = new PnpmProjectDependencyManifest({ + pnpmShrinkwrapFile, + project + }); + const useProjectDependencyManifest: boolean = !this._rushConfiguration.experimentsConfiguration + .configuration.legacyIncrementalBuildDependencyDetection; + + // Then, do non-local dependencies. Dev dependencies take priority over normal dependencies + const dependencies: PackageJsonDependency[] = [ + ...project.packageJsonEditor.dependencyList, + ...project.packageJsonEditor.devDependencyList + ].filter((x) => new DependencySpecifier(x.name, x.version).specifierType !== 'workspace'); + + for (const { name, dependencyType } of dependencies) { + // read the version number from the shrinkwrap entry + let version: string | undefined; + switch (dependencyType) { + case DependencyType.Regular: + version = (workspaceImporter.dependencies || {})[name]; + break; + case DependencyType.Dev: + version = (workspaceImporter.devDependencies || {})[name]; + break; + case DependencyType.Optional: + version = (workspaceImporter.optionalDependencies || {})[name]; + break; + case DependencyType.Peer: + // Peer dependencies do not need to be considered since they aren't a true + // dependency, and would be satisfied in the consuming package. They are + // also not specified in the workspace importer + continue; + } + + if (!version) { + // Optional dependencies by definition may not exist, so avoid throwing on these + if (dependencyType !== DependencyType.Optional) { + throw new InternalError( + `Cannot find shrinkwrap entry dependency "${name}" for workspace project: ${project.packageName}` + ); + } + continue; + } + + if (useProjectDependencyManifest) { + // Add to the manifest and provide all the parent dependencies. Peer dependencies are not mapped at + // the importer level, so provide an empty object for that + pnpmProjectDependencyManifest.addDependency(name, version, { + dependencies: { ...workspaceImporter.dependencies, ...workspaceImporter.devDependencies }, + optionalDependencies: { ...workspaceImporter.optionalDependencies }, + peerDependencies: {} + }); + } + } + + if (useProjectDependencyManifest) { + pnpmProjectDependencyManifest.save(); + } else { + pnpmProjectDependencyManifest.deleteIfExists(); + } + } + private _getPathToLocalInstallation(folderNameInLocalInstallationRoot: string): string { // See https://github.com/pnpm/pnpm/releases/tag/v4.0.0 if (this._pnpmVersion.major >= 4) { @@ -341,7 +466,8 @@ export class PnpmLinkManager extends BaseLinkManager { ); } - // read the version number from the shrinkwrap entry + // read the version number from the shrinkwrap entry and return if no version is specified + // and the dependency is optional const version: string | undefined = isOptional ? (parentShrinkwrapEntry.optionalDependencies || {})[dependencyName] : (parentShrinkwrapEntry.dependencies || {})[dependencyName]; @@ -370,7 +496,11 @@ export class PnpmLinkManager extends BaseLinkManager { !this._rushConfiguration.experimentsConfiguration.configuration .legacyIncrementalBuildDependencyDetection ) { - pnpmProjectDependencyManifest.addDependency(newLocalPackage, parentShrinkwrapEntry); + pnpmProjectDependencyManifest.addDependency( + newLocalPackage.name, + newLocalPackage.version!, + parentShrinkwrapEntry + ); } return newLocalPackage; diff --git a/apps/rush-lib/src/logic/pnpm/PnpmProjectDependencyManifest.ts b/apps/rush-lib/src/logic/pnpm/PnpmProjectDependencyManifest.ts index c07e8cc7200..a30a20c5fc5 100644 --- a/apps/rush-lib/src/logic/pnpm/PnpmProjectDependencyManifest.ts +++ b/apps/rush-lib/src/logic/pnpm/PnpmProjectDependencyManifest.ts @@ -12,7 +12,6 @@ import { } from './PnpmShrinkwrapFile'; import { RushConfigurationProject } from '../../api/RushConfigurationProject'; import { RushConstants } from '../RushConstants'; -import { BasePackage } from '../base/BasePackage'; import { DependencySpecifier } from '../DependencySpecifier'; export interface IPnpmProjectDependencyManifestOptions { @@ -58,12 +57,15 @@ export class PnpmProjectDependencyManifest { return path.join(project.projectRushTempFolder, RushConstants.projectDependencyManifestFilename); } - public addDependency(pkg: BasePackage, parentShrinkwrapEntry: IPnpmShrinkwrapDependencyYaml): void { - if (!pkg.version) { - throw new InternalError(`Version missing from dependency ${pkg.name}`); - } - - this._addDependencyInternal(pkg.name, pkg.version, parentShrinkwrapEntry); + public addDependency( + name: string, + version: string, + parentShrinkwrapEntry: Pick< + IPnpmShrinkwrapDependencyYaml, + 'dependencies' | 'optionalDependencies' | 'peerDependencies' + > + ): void { + this._addDependencyInternal(name, version, parentShrinkwrapEntry); } /** @@ -89,7 +91,10 @@ export class PnpmProjectDependencyManifest { private _addDependencyInternal( name: string, version: string, - parentShrinkwrapEntry: IPnpmShrinkwrapDependencyYaml, + parentShrinkwrapEntry: Pick< + IPnpmShrinkwrapDependencyYaml, + 'dependencies' | 'optionalDependencies' | 'peerDependencies' + >, throwIfShrinkwrapEntryMissing: boolean = true ): void { const shrinkwrapEntry: @@ -137,6 +142,16 @@ export class PnpmProjectDependencyManifest { } } + if ( + this._project.rushConfiguration.pnpmOptions && + this._project.rushConfiguration.pnpmOptions.useWorkspaces + ) { + // When using workspaces, hoisting of dependencies is not possible. Therefore, all packages that are consumed + // should be specified as direct dependencies in the shrinkwrap. Given this, there is no need to look for peer + // dependencies, since it is simply a constraint to be validated by the package manager. + return; + } + for (const peerDependencyName in shrinkwrapEntry.peerDependencies) { if (shrinkwrapEntry.peerDependencies.hasOwnProperty(peerDependencyName)) { // Peer dependencies come in the form of a semantic version range @@ -236,11 +251,17 @@ export class PnpmProjectDependencyManifest { const specifierMatches: RegExpExecArray | null = /^[^_]+_(.+)$/.exec(specifier); if (specifierMatches) { const combinedPeerDependencies: string = specifierMatches[1]; - // Parse "eslint@6.6.0+typescript@3.6.4" --> ["eslint@6.6.0", "typescript@3.6.4"] + // "eslint@6.6.0+typescript@3.6.4+@types+webpack@4.1.9" --> ["eslint@6.6.0", "typescript@3.6.4", "@types", "webpack@4.1.9"] const peerDependencies: string[] = combinedPeerDependencies.split('+'); - for (const peerDependencySpecifier of peerDependencies) { + for (let i = 0; i < peerDependencies.length; i++) { + // Scopes are also separated by '+', so reduce the proceeding value into it + if (peerDependencies[i].indexOf('@') === 0) { + peerDependencies[i] = `${peerDependencies[i]}/${peerDependencies[i + 1]}`; + peerDependencies.splice(i + 1, 1); + } + // Parse "eslint@6.6.0" --> "eslint", "6.6.0" - const peerMatches: RegExpExecArray | null = /^([^+@]+)@(.+)$/.exec(peerDependencySpecifier); + const peerMatches: RegExpExecArray | null = /^(@?[^+@]+)@(.+)$/.exec(peerDependencies[i]); if (peerMatches) { const peerDependencyName: string = peerMatches[1]; const peerDependencyVersion: string = peerMatches[2]; diff --git a/apps/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts b/apps/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts index 9c866d45eeb..b2008676e40 100644 --- a/apps/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts +++ b/apps/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts @@ -1,5 +1,6 @@ import * as yaml from 'js-yaml'; import * as os from 'os'; +import * as path from 'path'; import * as semver from 'semver'; import * as crypto from 'crypto'; import * as colors from 'colors'; @@ -48,6 +49,17 @@ export interface IPnpmShrinkwrapDependencyYaml { peerDependenciesMeta: { [dependency: string]: IPeerDependenciesMetaYaml }; } +export interface IPnpmShrinkwrapImporterYaml { + /** The list of resolved version numbers for direct dependencies */ + dependencies: { [dependency: string]: string }; + /** The list of resolved version numbers for dev dependencies */ + devDependencies: { [dependency: string]: string }; + /** The list of resolved version numbers for optional dependencies */ + optionalDependencies: { [dependency: string]: string }; + /** The list of specifiers used to resolve dependency versions */ + specifiers: { [dependency: string]: string }; +} + /** * This interface represents the raw pnpm-lock.YAML file * Example: @@ -82,6 +94,8 @@ export interface IPnpmShrinkwrapDependencyYaml { interface IPnpmShrinkwrapYaml { /** The list of resolved version numbers for direct dependencies */ dependencies: { [dependency: string]: string }; + /** The list of importers for local workspace projects */ + importers: { [relativePath: string]: IPnpmShrinkwrapImporterYaml }; /** The description of the solved graph */ packages: { [dependencyVersion: string]: IPnpmShrinkwrapDependencyYaml }; /** URL of the registry which was used */ @@ -197,6 +211,9 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { if (!this._shrinkwrapJson.dependencies) { this._shrinkwrapJson.dependencies = {}; } + if (!this._shrinkwrapJson.importers) { + this._shrinkwrapJson.importers = {}; + } if (!this._shrinkwrapJson.specifiers) { this._shrinkwrapJson.specifiers = {}; } @@ -419,7 +436,21 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { * @override */ protected serialize(): string { - let shrinkwrapContent: string = yaml.safeDump(this._shrinkwrapJson, SHRINKWRAP_YAML_FORMAT); + // Ensure that if any of the top-level properties are provided but empty that they are removed. We populate the object + // properties when we read the shrinkwrap but PNPM does not set these top-level properties unless they are present. + const shrinkwrapToSerialize: Partial = { ...this._shrinkwrapJson }; + for (const key of Object.keys(shrinkwrapToSerialize).filter((key) => + shrinkwrapToSerialize.hasOwnProperty(key) + )) { + if ( + typeof shrinkwrapToSerialize[key] === 'object' && + Object.entries(shrinkwrapToSerialize[key] || {}).length === 0 + ) { + delete shrinkwrapToSerialize[key]; + } + } + + let shrinkwrapContent: string = yaml.safeDump(shrinkwrapToSerialize, SHRINKWRAP_YAML_FORMAT); if (this._shrinkwrapHashEnabled) { this._shrinkwrapHash = crypto.createHash('sha1').update(shrinkwrapContent).digest('hex'); shrinkwrapContent = `${shrinkwrapContent.trimRight()}\n${PnpmShrinkwrapFile._shrinkwrapHashPrefix} ${ @@ -505,6 +536,66 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { return this._parsePnpmDependencyKey(packageName, dependencyKey); } + /** @override */ + public getWorkspaceKeys(): ReadonlyArray { + const result: string[] = []; + for (const key of Object.keys(this._shrinkwrapJson.importers)) { + // Avoid including the common workspace + if (key !== '.') { + result.push(key); + } + } + result.sort(); // make the result deterministic + return result; + } + + /** @override */ + public getWorkspaceKeyByPath(workspaceRoot: string, projectFolder: string): string { + return path.relative(workspaceRoot, projectFolder).replace(new RegExp(`\\${path.sep}`, 'g'), '/'); + } + + public getWorkspaceImporter(importerPath: string): IPnpmShrinkwrapImporterYaml | undefined { + return BaseShrinkwrapFile.tryGetValue(this._shrinkwrapJson.importers, importerPath); + } + + /** + * Gets the resolved version number of a dependency for a specific temp project. + * For PNPM, we can reuse the version that another project is using. + * Note that this function modifies the shrinkwrap data. + * + * @override + */ + protected getWorkspaceDependencyVersion( + dependencySpecifier: DependencySpecifier, + workspaceKey: string + ): DependencySpecifier | undefined { + // PNPM doesn't have the same advantage of NPM, where we can skip generate as long as the + // shrinkwrap file puts our dependency in either the top of the node_modules folder + // or underneath the package we are looking at. + // This is because the PNPM shrinkwrap file describes the exact links that need to be created + // to recreate the graph.. + // Because of this, we actually need to check for a version that this package is directly + // linked to. + + const packageName: string = dependencySpecifier.packageName; + const projectImporter: IPnpmShrinkwrapImporterYaml | undefined = this.getWorkspaceImporter(workspaceKey); + if (!projectImporter) { + return undefined; + } + + const allDependencies: { [dependency: string]: string } = { + ...(projectImporter.optionalDependencies || {}), + ...(projectImporter.dependencies || {}), + ...(projectImporter.devDependencies || {}) + }; + if (!allDependencies.hasOwnProperty(packageName)) { + return undefined; + } + + const dependencyKey: string = allDependencies[packageName]; + return this._parsePnpmDependencyKey(packageName, dependencyKey); + } + /** * Returns the version of a dependency being used by a given project */ diff --git a/apps/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts b/apps/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts new file mode 100644 index 00000000000..40909bd8d9f --- /dev/null +++ b/apps/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as globEscape from 'glob-escape'; +import * as os from 'os'; +import * as path from 'path'; +import * as yaml from 'js-yaml'; +import { FileSystem, Sort, Text } from '@rushstack/node-core-library'; + +import { BaseWorkspaceFile } from '../base/BaseWorkspaceFile'; + +// This is based on PNPM's own configuration: +// https://github.com/pnpm/pnpm-shrinkwrap/blob/master/src/write.ts +const WORKSPACE_YAML_FORMAT: yaml.DumpOptions = { + lineWidth: 1000, + noCompatMode: true, + noRefs: true, + sortKeys: true +}; + +/** + * This interface represents the raw pnpm-workspace.YAML file + * Example: + * { + * "packages": [ + * "../../apps/project1" + * ] + * } + */ +interface IPnpmWorkspaceYaml { + /** The list of local package directories */ + packages: string[]; +} + +export class PnpmWorkspaceFile extends BaseWorkspaceFile { + /** + * The filename of the workspace file. + */ + public readonly workspaceFilename: string; + + private _workspacePackages: Set; + + /** + * + @halfnibble +halfnibble 5 days ago Member +Empty comment. + +@D4N14L Reply… + */ + public constructor(workspaceYamlFilename: string) { + super(); + + this.workspaceFilename = workspaceYamlFilename; + let workspaceYaml: IPnpmWorkspaceYaml; + try { + // Populate with the existing file, or an empty list if the file doesn't exist + workspaceYaml = FileSystem.exists(workspaceYamlFilename) + ? yaml.safeLoad(FileSystem.readFile(workspaceYamlFilename).toString()) + : { packages: [] }; + } catch (error) { + throw new Error(`Error reading "${workspaceYamlFilename}":${os.EOL} ${error.message}`); + } + + this._workspacePackages = new Set(workspaceYaml.packages); + } + + /** @override */ + public addPackage(packagePath: string): void { + // Ensure the path is relative to the pnpm-workspace.yaml file + if (path.isAbsolute(packagePath)) { + packagePath = path.relative(path.dirname(this.workspaceFilename), packagePath); + } + + // Glob can't handle Windows paths + const globPath: string = Text.replaceAll(packagePath, '\\', '/'); + this._workspacePackages.add(globEscape(globPath)); + } + + /** @override */ + protected serialize(): string { + // Ensure stable sort order when serializing + Sort.sortSet(this._workspacePackages); + + const workspaceYaml: IPnpmWorkspaceYaml = { + packages: Array.from(this._workspacePackages) + }; + return yaml.safeDump(workspaceYaml, WORKSPACE_YAML_FORMAT); + } +} diff --git a/apps/rush-lib/src/logic/yarn/YarnShrinkwrapFile.ts b/apps/rush-lib/src/logic/yarn/YarnShrinkwrapFile.ts index 6182f5b42df..225d8e62482 100644 --- a/apps/rush-lib/src/logic/yarn/YarnShrinkwrapFile.ts +++ b/apps/rush-lib/src/logic/yarn/YarnShrinkwrapFile.ts @@ -247,4 +247,22 @@ export class YarnShrinkwrapFile extends BaseShrinkwrapFile { ): DependencySpecifier | undefined { throw new InternalError('Not implemented'); } + + /** @override */ + public getWorkspaceKeys(): ReadonlyArray { + throw new InternalError('Not implemented'); + } + + /** @override */ + public getWorkspaceKeyByPath(workspaceRoot: string, projectFolder: string): string { + throw new InternalError('Not implemented'); + } + + /** @override */ + protected getWorkspaceDependencyVersion( + dependencySpecifier: DependencySpecifier, + workspaceKey: string + ): DependencySpecifier | undefined { + throw new InternalError('Not implemented'); + } } diff --git a/apps/rush-lib/src/schemas/rush.schema.json b/apps/rush-lib/src/schemas/rush.schema.json index 2637f0872c1..e14e301826f 100644 --- a/apps/rush-lib/src/schemas/rush.schema.json +++ b/apps/rush-lib/src/schemas/rush.schema.json @@ -106,6 +106,14 @@ "preventManualShrinkwrapChanges": { "description": "If true, then \"rush install\" will report an error if manual modifications were made to the PNPM shrinkwrap file without running `rush update` afterwards. To temporarily disable this validation when invoking \"rush install\", use the \"--bypassPolicy\" command-line parameter. The default value is false.", "type": "boolean" + }, + "useWorkspaces": { + "description": "If true, then Rush will use the workspaces feature to install and link packages when invoking PNPM. The default value is false.", + "type": "boolean" + }, + "useShimPnpmfile": { + "description": "If true, then Rush will create a pnpmfile that runs before the provided pnpmfile. This shim pnpmfile is used to inject preferred versions support into the PNPM package resolver. The default value is false.", + "type": "boolean" } }, "additionalProperties": false diff --git a/apps/rush-lib/src/utilities/Utilities.ts b/apps/rush-lib/src/utilities/Utilities.ts index 3ca74182863..4f28aa8eb20 100644 --- a/apps/rush-lib/src/utilities/Utilities.ts +++ b/apps/rush-lib/src/utilities/Utilities.ts @@ -268,25 +268,20 @@ export class Utilities { } /* - * Returns true if outputFilename has a more recent last modified timestamp - * than all of the inputFilenames, which would imply that we don't need to rebuild it. - * Returns false if any of the files does not exist. + * Returns true if dateToCompare is more recent than all of the inputFilenames, which + * would imply that we don't need to rebuild it. Returns false if any of the files + * does not exist. * NOTE: The filenames can also be paths for directories, in which case the directory * timestamp is compared. */ - public static isFileTimestampCurrent(outputFilename: string, inputFilenames: string[]): boolean { - if (!FileSystem.exists(outputFilename)) { - return false; - } - const outputStats: fs.Stats = FileSystem.getStatistics(outputFilename); - + public static isFileTimestampCurrent(dateToCompare: Date, inputFilenames: string[]): boolean { for (const inputFilename of inputFilenames) { if (!FileSystem.exists(inputFilename)) { return false; } const inputStats: fs.Stats = FileSystem.getStatistics(inputFilename); - if (outputStats.mtime < inputStats.mtime) { + if (dateToCompare < inputStats.mtime) { return false; } } @@ -562,6 +557,23 @@ export class Utilities { FileSystem.writeFile(targetNpmrcPath, resultLines.join(os.EOL)); } + /** + * Copies the file "sourcePath" to "destinationPath", overwriting the target file location. + * If the source file does not exist, then the target file is deleted. + */ + public static syncFile(sourcePath: string, destinationPath: string): void { + if (FileSystem.exists(sourcePath)) { + console.log(`Updating ${destinationPath}`); + FileSystem.copyFile({ sourcePath, destinationPath }); + } else { + if (FileSystem.exists(destinationPath)) { + // If the source file doesn't exist and there is one in the target, delete the one in the target + console.log(`Deleting ${destinationPath}`); + FileSystem.deleteFile(destinationPath); + } + } + } + /** * syncNpmrc() copies the .npmrc file to the target folder, and also trims unusable lines from the .npmrc file. * If the source .npmrc file not exist, then syncNpmrc() will delete an .npmrc that is found in the target folder. diff --git a/apps/rush/package.json b/apps/rush/package.json index 59fa77eb437..145384ab6dc 100644 --- a/apps/rush/package.json +++ b/apps/rush/package.json @@ -34,7 +34,7 @@ "@rushstack/node-core-library": "3.24.1", "@microsoft/rush-lib": "5.26.0", "colors": "~1.2.1", - "semver": "~5.3.0" + "semver": "~7.3.0" }, "devDependencies": { "@microsoft/rush-stack-compiler-3.5": "0.6.0", @@ -42,7 +42,7 @@ "@rushstack/eslint-config": "0.5.8", "@types/jest": "25.2.1", "@types/node": "10.17.13", - "@types/semver": "5.3.33", + "@types/semver": "~7.2.0", "@types/sinon": "1.16.34", "chai": "~3.5.0", "gulp": "~4.0.2", diff --git a/build-tests/api-extractor-test-02/package.json b/build-tests/api-extractor-test-02/package.json index 9be9284c38d..ca5de8ea997 100644 --- a/build-tests/api-extractor-test-02/package.json +++ b/build-tests/api-extractor-test-02/package.json @@ -9,9 +9,9 @@ "build": "node build.js" }, "dependencies": { - "@types/semver": "5.3.33", + "@types/semver": "~7.2.0", "api-extractor-test-01": "1.0.0", - "semver": "~5.3.0" + "semver": "~7.3.0" }, "devDependencies": { "@microsoft/api-extractor": "7.8.11", diff --git a/common/reviews/api/node-core-library.api.md b/common/reviews/api/node-core-library.api.md index e910acfaf14..002a514eefa 100644 --- a/common/reviews/api/node-core-library.api.md +++ b/common/reviews/api/node-core-library.api.md @@ -480,6 +480,9 @@ export class LockFile { // @public export class MapExtensions { static mergeFromMap(targetMap: Map, sourceMap: ReadonlyMap): void; + static toObject(map: Map): { + [key: string]: TValue; + }; } // @public diff --git a/common/reviews/api/rush-lib.api.md b/common/reviews/api/rush-lib.api.md index 464ae5f6b6f..418985d3bd3 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -176,6 +176,8 @@ export interface _IPnpmOptionsJson extends IPackageManagerOptionsJsonBase { preventManualShrinkwrapChanges?: boolean; resolutionStrategy?: ResolutionStrategy; strictPeerDependencies?: boolean; + useShimPnpmfile?: boolean; + useWorkspaces?: boolean; } // @public @@ -289,6 +291,8 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration readonly preventManualShrinkwrapChanges: boolean; readonly resolutionStrategy: ResolutionStrategy; readonly strictPeerDependencies: boolean; + readonly useShimPnpmfile: boolean; + readonly useWorkspaces: boolean; } // @public diff --git a/core-build/gulp-core-build/package.json b/core-build/gulp-core-build/package.json index be9881a0199..c84d95e4da9 100644 --- a/core-build/gulp-core-build/package.json +++ b/core-build/gulp-core-build/package.json @@ -20,7 +20,7 @@ "@types/node": "10.17.13", "@types/node-notifier": "0.0.28", "@types/orchestrator": "0.0.30", - "@types/semver": "5.3.33", + "@types/semver": "~7.2.0", "@types/through2": "2.0.32", "@types/vinyl": "2.0.3", "@types/yargs": "0.0.34", @@ -46,7 +46,7 @@ "object-assign": "~4.1.0", "orchestrator": "~0.3.8", "pretty-hrtime": "~1.0.2", - "semver": "~5.3.0", + "semver": "~7.3.0", "through2": "~2.0.1", "vinyl": "~2.2.0", "xml": "~1.0.1", diff --git a/libraries/node-core-library/package.json b/libraries/node-core-library/package.json index 7bf4d95c03c..d14fbc7cf92 100644 --- a/libraries/node-core-library/package.json +++ b/libraries/node-core-library/package.json @@ -16,7 +16,7 @@ "colors": "~1.2.1", "fs-extra": "~7.0.1", "jju": "~1.4.0", - "semver": "~5.3.0", + "semver": "~7.3.0", "timsort": "~0.3.0", "z-schema": "~3.18.3" }, @@ -27,7 +27,7 @@ "@types/fs-extra": "7.0.0", "@types/jest": "25.2.1", "@types/jju": "1.4.1", - "@types/semver": "5.3.33", + "@types/semver": "~7.2.0", "@types/timsort": "0.3.0", "@types/z-schema": "3.16.31", "gulp": "~4.0.2" diff --git a/libraries/node-core-library/src/MapExtensions.ts b/libraries/node-core-library/src/MapExtensions.ts index b84ba96a960..e31e3b70e7b 100644 --- a/libraries/node-core-library/src/MapExtensions.ts +++ b/libraries/node-core-library/src/MapExtensions.ts @@ -19,4 +19,19 @@ export class MapExtensions { targetMap.set(pair[0], pair[1]); } } + + /** + * Converts a string-keyed map to an object. + * @remarks + * This function has the same effect as Object.fromEntries(map.entries()) + * in supported versions of Node (\>= 12.0.0). + * @param map - The map that the object properties will be sourced from + */ + public static toObject(map: Map): { [key: string]: TValue } { + const object: { [key: string]: TValue } = {}; + for (const [key, value] of map.entries()) { + object[key] = value; + } + return object; + } } From e6d78e7c55212c1e5492cb80425b7897dfc6e473 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Wed, 17 Jun 2020 12:40:26 -0700 Subject: [PATCH 03/33] Rush update --- common/config/rush/pnpm-lock.yaml | 195 ++++++++++++++++-------------- 1 file changed, 104 insertions(+), 91 deletions(-) diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index b3338c44220..33912f0bbef 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -115,7 +115,7 @@ dependencies: '@types/orchestrator': 0.0.30 '@types/read-package-tree': 5.1.0 '@types/resolve': 1.17.1 - '@types/semver': 5.3.33 + '@types/semver': 7.2.0 '@types/serve-static': 1.13.1 '@types/sinon': 1.16.34 '@types/source-map': 0.5.0 @@ -202,7 +202,7 @@ dependencies: pseudolocale: 1.1.0 read-package-tree: 5.1.6 resolve: 1.17.0 - semver: 5.3.0 + semver: 7.3.2 sinon: 1.17.7 source-map: 0.6.1 strict-uri-encode: 2.0.0 @@ -1290,6 +1290,12 @@ packages: dev: false resolution: integrity: sha512-UwrBgjsRS8BSsckIEdrAhIAmdh0MJidtKTvD3S6tpMq6qHLY3uGaNYcRDUjPxpF4hOAOEbMNSXhhfxmNHB1QNQ== + /@types/semver/7.2.0: + dependencies: + '@types/node': 10.17.13 + dev: false + resolution: + integrity: sha512-TbB0A8ACUWZt3Y6bQPstW9QNbhNeebdgLX4T/ZfkrswAfUzRiXrgd9seol+X379Wa589Pu4UEx9Uok0D4RjRCQ== /@types/serve-static/1.13.1: dependencies: '@types/express-serve-static-core': 4.11.0 @@ -11118,6 +11124,13 @@ packages: hasBin: true resolution: integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + /semver/7.3.2: + dev: false + engines: + node: '>=10' + hasBin: true + resolution: + integrity: sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== /send/0.13.2: dependencies: debug: 2.2.0 @@ -13634,7 +13647,7 @@ packages: dev: false name: '@rush-temp/api-documenter-test' resolution: - integrity: sha512-5fGJCDu4OUAYbH8EkuKhdmkQNu8nKoADiLE++wIePzoxYcEdpJiEzRTKPvlf+i6dEzgrbXc8p4jyNaGTcjUGvw== + integrity: sha512-TXX2XGFWXT9L/c0EBNCSf4t4nRNVKWtMfOqiXPXhiuDYqIc1ics4bdDN+hYkY8IRaN5e7iLbjmcXle1hnhiFsg== tarball: 'file:projects/api-documenter-test.tgz' version: 0.0.0 'file:projects/api-documenter.tgz': @@ -13652,7 +13665,7 @@ packages: dev: false name: '@rush-temp/api-documenter' resolution: - integrity: sha512-8/TjMsLB3VXipgUdG65DMSUfILeLvNeolcw/iQMfDGTFmmCoov4KmntumO25SflYW+3r1Xu/Rt6+GUj3lVFMHQ== + integrity: sha512-Jwy59tLl94t+w9ux4spjg+fD5oM35QHCgH5shwmW/0uWj3QgPBhYR2XkkSn7UbsIShHjYUYaHx7qcfGxCpM18Q== tarball: 'file:projects/api-documenter.tgz' version: 0.0.0 'file:projects/api-extractor-lib1-test.tgz': @@ -13663,7 +13676,7 @@ packages: dev: false name: '@rush-temp/api-extractor-lib1-test' resolution: - integrity: sha512-Xzh9GhmiSz68h1vA2bMwjriDI3rBAoVC0XEwmgFT0oJecdPYBwgMamQspN4+XUPsngnP90cywqCmiRALYseGaQ== + integrity: sha512-OXk5XZCTQOPnO2fV/SPxjtcqEg6x3x9wtzzAUFqV9TR7i4+xot1txuh4hly1iSQ/Fk1zwD/wtQ3RScsZwsJ+LQ== tarball: 'file:projects/api-extractor-lib1-test.tgz' version: 0.0.0 'file:projects/api-extractor-lib2-test.tgz': @@ -13675,7 +13688,7 @@ packages: dev: false name: '@rush-temp/api-extractor-lib2-test' resolution: - integrity: sha512-DqJ7flaonsHdwCzHEmejl/vElduivAHnsmOqy2ir8eP/uleH/53+AQPKMKVwRTm1neQ2BdpHjA8/ll+LK9S+sQ== + integrity: sha512-9JMVBlxvcnFoYcghe7tgx7PbEyoNOSK5yrJv2DjmvYwKipIWkTlmYe5G3TfuCzWZgC27x9zOXKw9P3KaVluBoA== tarball: 'file:projects/api-extractor-lib2-test.tgz' version: 0.0.0 'file:projects/api-extractor-lib3-test.tgz': @@ -13687,7 +13700,7 @@ packages: dev: false name: '@rush-temp/api-extractor-lib3-test' resolution: - integrity: sha512-qn3dJExOE0lF5CuuWioFvsT/TfdKiwXb5nM/MXVqU8m+ud+H3QC7eOdTLLImtURDXPuB0n2JYbDdQR2Ou1Y03g== + integrity: sha512-Xaq+4t3d/tRnbJuMVT5CsQSeVHMcgZ7Q6fLIUNF7By2wbtmuCzwFK/yVTIf4NlMBr8vM4FshtACBd3H+tU6Z2A== tarball: 'file:projects/api-extractor-lib3-test.tgz' version: 0.0.0 'file:projects/api-extractor-model.tgz': @@ -13701,7 +13714,7 @@ packages: dev: false name: '@rush-temp/api-extractor-model' resolution: - integrity: sha512-EiVGSwj6CQfR8u2ZrKlWk3eibHjPZJNBwx0hEOjNXH0kaH5V/irkHjoz3itcZ2tTt25K9MpjdTIwAJ4LUvIlug== + integrity: sha512-pn9wP3/peGZ42JnBGtVUL4GaTRkYMXnrG9xAJXieof1RHwRbLjo2IwSs9kkB1MgXdP8752grmv/LGy9ElBzGIA== tarball: 'file:projects/api-extractor-model.tgz' version: 0.0.0 'file:projects/api-extractor-scenarios.tgz': @@ -13715,7 +13728,7 @@ packages: dev: false name: '@rush-temp/api-extractor-scenarios' resolution: - integrity: sha512-eeprV1Hg7PUGrs31Ju/kg4DCxnucdwBeDrWuiyg9WivTPPA8irwuyGB0JFi4ox/68TN2vafN8MFfHSimUMAkNw== + integrity: sha512-ISTb01zEOBAFoVnxIQcjLa+axmu6q8+/AwDj9qHszO3ycXmtpPer9EPxvbQedCNpD3Tp3MbIMghloXFn2njnCA== tarball: 'file:projects/api-extractor-scenarios.tgz' version: 0.0.0 'file:projects/api-extractor-test-01.tgz': @@ -13729,20 +13742,20 @@ packages: dev: false name: '@rush-temp/api-extractor-test-01' resolution: - integrity: sha512-7m3rCYBWUP40+bJvzPHUGBajox5Y9TveLj9qPDMtnepMX2xFyS+DdcXLn2kGblGOjyocRCx6TVRYx0e0iV3xmw== + integrity: sha512-vLsN73xcEaa7VWtft1ijyOFIU/z0RYHMRaaO7eIWMcKggEJy9gq1226GbPz6sBKDoURfGThanjTnxyA5P46dHw== tarball: 'file:projects/api-extractor-test-01.tgz' version: 0.0.0 'file:projects/api-extractor-test-02.tgz': dependencies: '@types/node': 10.17.13 - '@types/semver': 5.3.33 + '@types/semver': 7.2.0 fs-extra: 7.0.1 - semver: 5.3.0 + semver: 7.3.2 typescript: 3.7.5 dev: false name: '@rush-temp/api-extractor-test-02' resolution: - integrity: sha512-iAvKcNza4aLBiiQGnQMYEbXiNcsnyBtzkUKggLVItkfhDrQ6uTJBQb6TuvC9Qbiyca464MR5+5ZApqw4VZihmw== + integrity: sha512-UWLrF7+wwRKN4hj/jnAih0LgsK+d+AcmYdmOt+ZHkENca4c3iKxi6NxMazohUvWx1gbU/3fqjJrtfClFkIjEzQ== tarball: 'file:projects/api-extractor-test-02.tgz' version: 0.0.0 'file:projects/api-extractor-test-03.tgz': @@ -13754,7 +13767,7 @@ packages: dev: false name: '@rush-temp/api-extractor-test-03' resolution: - integrity: sha512-Hnl2/AlPf1xPy9p4WwMLgfW7V5ovlPlj1N+vlWAqmWYvXwpnPeLc7jQ86MhZbQlPQAF7XBJnJIOgbZJHGx//eQ== + integrity: sha512-ZvlDjrJG25V7ogORzsOPh4nVRVeG/nrL76fjzlBBgloKTx8/IDbpesiwir9eFgL6mZKjW7Tsl69ueatf2x5NQQ== tarball: 'file:projects/api-extractor-test-03.tgz' version: 0.0.0 'file:projects/api-extractor-test-04.tgz': @@ -13764,7 +13777,7 @@ packages: dev: false name: '@rush-temp/api-extractor-test-04' resolution: - integrity: sha512-Gj7Fn99dXgg7VUaI4HX167pC+RYkbbgmYwuzdr6KJID72H22GY9L6jQLACIlcHySueqFyPGOb2kvA6TgAVV8aw== + integrity: sha512-s45r5nn8wd/ecEtyShun4nvzyPU2mXboK9/frShX7Y0JdAj18E+IsZhebTFw3Yh06BQEHQ0c8Emeuo1ddF8mug== tarball: 'file:projects/api-extractor-test-04.tgz' version: 0.0.0 'file:projects/api-extractor.tgz': @@ -13785,7 +13798,7 @@ packages: dev: false name: '@rush-temp/api-extractor' resolution: - integrity: sha512-0aZmDupa/qOxG8aBPYOPhBEfKXv6CfBGouUoa/4VxABut9CVlfNn71YynqvzMv20lpnNp6ccTSX9fsgBBK+ozQ== + integrity: sha512-zAIJZu4aoegbuP1jhaZpuooIXr5RVTVGmBhCJweCvMGN/hcOGQDayvuCKIiNraVY3s2bLm923kHyGvsQ7dRGqQ== tarball: 'file:projects/api-extractor.tgz' version: 0.0.0 'file:projects/debug-certificate-manager.tgz': @@ -13800,7 +13813,7 @@ packages: dev: false name: '@rush-temp/debug-certificate-manager' resolution: - integrity: sha512-s/VmqhN3n22a0NfWbFBURLnz675u6lguHAex6OgBQ5476jn7suhPGq/RwTwWfyrDAfO3Bv3akUa7nmvLHUMC9Q== + integrity: sha512-wcf4B1/hCvvDpxBWob0a4IZiCup9VhTxXtx0LmzD5VT7kZysgbQtKl+ZMr98emwRsOlKH7Y+f7WWWumu8+wDNA== tarball: 'file:projects/debug-certificate-manager.tgz' version: 0.0.0 'file:projects/doc-plugin-rush-stack.tgz': @@ -13813,7 +13826,7 @@ packages: dev: false name: '@rush-temp/doc-plugin-rush-stack' resolution: - integrity: sha512-lQRPjWf7r9BDl/furiWLdk/XvSUxS3OL79F0Yrl0n1vwlNh6Glm9h7Rhka+JLqy1dm+kCMXbEpTqNEdcLCj+Rg== + integrity: sha512-J8hwYfq7UkBY8LzBW68c+g5WL9iz7aaTpOiB945ODU5WXa2kqZp4Ed+KUPqP8+gfJDmUt1cmsVb7MgOkNd+KIQ== tarball: 'file:projects/doc-plugin-rush-stack.tgz' version: 0.0.0 'file:projects/eslint-config.tgz': @@ -13831,7 +13844,7 @@ packages: dev: false name: '@rush-temp/eslint-config' resolution: - integrity: sha512-U1nJ0l/SlzYM6dIJJTBgNFoy7FDECPTP3atBidNTlsGgUKQ/uVQHbMCvsesTBHnU5tf79bo08wl295pozULliQ== + integrity: sha512-nf6kyKroqvfYn9e2eBHBsKDVwJHSA43JWHRGM1qZQO5ux1ZENDUOpEVXQADMHOUvNz1p6NOVzHPrjrWKjyigDg== tarball: 'file:projects/eslint-config.tgz' version: 0.0.0 'file:projects/eslint-plugin.tgz': @@ -13850,14 +13863,14 @@ packages: dev: false name: '@rush-temp/eslint-plugin' resolution: - integrity: sha512-s9s4gMrf1l7ZB5LiNqoBanhfcP3JPbK1FHiH+ie9GkZOnIPc60oVoG9sM+f5maC/gDaGpgGCGn5uR6dOxfZXng== + integrity: sha512-8J4XtiI3vFv11k4IwnvyZddLYNpxxQOrPq9zGP4nFi4J1+JVA2ZZyss6mHZqeEOyL2go/p8/yhy/e1SyII+5Kg== tarball: 'file:projects/eslint-plugin.tgz' version: 0.0.0 'file:projects/generate-api-docs.tgz': dev: false name: '@rush-temp/generate-api-docs' resolution: - integrity: sha512-5gDOHK/fKc9p1/pHZ0wx0zkRXxq0OKwlhi8VIAuP4mTG7nO/L8HM7rsGdSTnI2l1bRVjzgy8SRne5/9aHSTqlw== + integrity: sha512-q9r1RYGZpWLK/9ajxkG0iQFnA2MzMCfdssBuQZbvRZukBVdAoZZO+yoLPghcNz6hn2Ej2pH/PGH3jVf3JtiYHw== tarball: 'file:projects/generate-api-docs.tgz' version: 0.0.0 'file:projects/gulp-core-build-mocha.tgz': @@ -13878,7 +13891,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-mocha' resolution: - integrity: sha512-N76Yr/3dJlyMGKbsBtccdIVNbJDti5z2xH/IGEytVtMIiWmWzazfDYfd8sJhjGNIQw+8+9afDQMNZVvXDJPjeg== + integrity: sha512-5XFZ4zKZ+jSbHg1PTJhjkQitggcKTxTfU5LbqnFCVlwj/Ee1QKIbVY30dTPeY4MBxh+oYuTSluB6r3CYk6nsnQ== tarball: 'file:projects/gulp-core-build-mocha.tgz' version: 0.0.0 'file:projects/gulp-core-build-sass.tgz': @@ -13901,7 +13914,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-sass' resolution: - integrity: sha512-yW8koqBhdJXC9lSOes/3TPcxw/0sT175OpSrqNZRRIHoRl+ieadSz+s9TCWQJuFz8ty16uCFxftI3N46scgvjw== + integrity: sha512-tV37KXx2KBrZENRA591k0mDm9jNmDdvidrDNqokQ/jThNGeez+jxW+dXGdXuZxJDHIKux/pt1Cy+ID9mkPI6oQ== tarball: 'file:projects/gulp-core-build-sass.tgz' version: 0.0.0 'file:projects/gulp-core-build-serve.tgz': @@ -13924,7 +13937,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-serve' resolution: - integrity: sha512-J7P2mnkA1Vtx1NheTAHSji21YsgsDZm2g3YDVCqYmLnqP6O2mhLVGS9zfVp3G/grxYWKkB50jvyE7ZGpOomKAg== + integrity: sha512-8dE7gW6ZRhwy5gshaobZMXlz7fEshUr3Czt9oynRMsW+4kH5zksNkDYz2T6cDFf7vERBuAx1Yl9hnVtSoV1sRg== tarball: 'file:projects/gulp-core-build-serve.tgz' version: 0.0.0 'file:projects/gulp-core-build-typescript.tgz': @@ -13943,7 +13956,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-typescript' resolution: - integrity: sha512-2fRvEU4bwwwxdhtvUHm4nTHCGJtb09rDV7U0AQJHbZrTHMhnNmZ2xJaDh/eM/HRFA59mxMwWU2LDcVL9u4MVig== + integrity: sha512-4ezZkd375+anny07SVyoennfj1OonWtucAmP2wyKgcaWjqV+Toy+1rr10fqT+PbS+NF+n4alg9vOPzghKZYYkA== tarball: 'file:projects/gulp-core-build-typescript.tgz' version: 0.0.0 'file:projects/gulp-core-build-webpack.tgz': @@ -13961,7 +13974,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-webpack' resolution: - integrity: sha512-eJw+Ra+P3mKw5sFejXEDr9ljASKOODHngAlRP9rDSUa8/3Do04nhVdQxPnE68Q0yYEEl6KKHdbdA9CjnPLr9aA== + integrity: sha512-EehzSsLEKMUGg6xr7ecVwQvfjIlEUZZ5Z6dX2rwaEfcDJHzuHjHdEHVXcF7u1qlcGd1WghX+fatdUamU2drnqQ== tarball: 'file:projects/gulp-core-build-webpack.tgz' version: 0.0.0 'file:projects/gulp-core-build.tgz': @@ -13979,7 +13992,7 @@ packages: '@types/node': 10.17.13 '@types/node-notifier': 0.0.28 '@types/orchestrator': 0.0.30 - '@types/semver': 5.3.33 + '@types/semver': 7.2.0 '@types/through2': 2.0.32 '@types/vinyl': 2.0.3 '@types/yargs': 0.0.34 @@ -14005,7 +14018,7 @@ packages: object-assign: 4.1.1 orchestrator: 0.3.8 pretty-hrtime: 1.0.3 - semver: 5.3.0 + semver: 7.3.2 through2: 2.0.5 vinyl: 2.2.0 xml: 1.0.1 @@ -14014,7 +14027,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build' resolution: - integrity: sha512-/XcLA6xdPMr2LAZsHDEMYNNEWCtMbuZx+bARRaIud9YDvC4oR2XKxypa4sGP3SP9KKFoz5iya1VEWX7OO9+KsQ== + integrity: sha512-AtxLC2CPpx+TqjehqEiqreFh6W4OpmWqXP0w8z64IeNhHmHmTRxuwYmJlzXWDz6/FmNHJHjSlObvDXogMBAC7A== tarball: 'file:projects/gulp-core-build.tgz' version: 0.0.0 'file:projects/load-themed-styles.tgz': @@ -14028,7 +14041,7 @@ packages: dev: false name: '@rush-temp/load-themed-styles' resolution: - integrity: sha512-4jVtBAM5fZ2x5ZIFF7xk2q88y32gUwr6X7M18za5RaTYOVrpQ4QtdfZvkzFqEnq35r/R0CEEhyoo7sn0nsswBw== + integrity: sha512-clKNvHSGnf6JdfGGk9xMPMNI1F3l2i82EJa8lY0JLsLaAuQ210pzOfbuRwf33xR9/A2LhKrCZtMdcoUMFv66Ug== tarball: 'file:projects/load-themed-styles.tgz' version: 0.0.0 'file:projects/loader-load-themed-styles.tgz': @@ -14044,7 +14057,7 @@ packages: dev: false name: '@rush-temp/loader-load-themed-styles' resolution: - integrity: sha512-/mRWnWpe7blfxG5SqhOjj0E24rZBe7JM8zMYN9oLMJvZMBeLu1w0JwR7V0QfRabkLKuEl4ugFjEv39XzH4Vexw== + integrity: sha512-u9gJyiFoEmZ5y4OjvBp+kdDirFC5n3MudWbayhnPVv5UNs9oSNg12aayItj4X/Qm2wpCQUVtvcOJFJqNqVBqkA== tarball: 'file:projects/loader-load-themed-styles.tgz' version: 0.0.0 'file:projects/loader-raw-script.tgz': @@ -14059,7 +14072,7 @@ packages: dev: false name: '@rush-temp/loader-raw-script' resolution: - integrity: sha512-ZJDZw5gouOj6vMvIWZli9M0ttpsAcwvjlWzFD4gKEWARsuZLw3ZX6T7pSQf+C6LudNY4VkpSHtWOxIMdgWP0Ew== + integrity: sha512-lJRwBGhEq3QoT2Xjv+Ayt41tzPCLR7rWhxbooBphE0qZn4MXFfrMEZbX2oJa9Sb/B14MZkqx8j0CVvV5WotyQA== tarball: 'file:projects/loader-raw-script.tgz' version: 0.0.0 'file:projects/localization-plugin-test-01.tgz': @@ -14074,7 +14087,7 @@ packages: dev: false name: '@rush-temp/localization-plugin-test-01' resolution: - integrity: sha512-QHhYt+zdw1SOiwXVahksumclQzzvW3UNtesUb/go+8u9eV9RaxuAws96JUpchyjLO+dDGADkzuAHR5GBsSqPeA== + integrity: sha512-XPFx/W6mKgQuSDsEk0maae4ZCH2VCvmDGYBXMwdp5urK4nmw5B3tqYKs5sRJopbsUGzFAzriW1WASNC3SvKQPw== tarball: 'file:projects/localization-plugin-test-01.tgz' version: 0.0.0 'file:projects/localization-plugin-test-02.tgz': @@ -14091,7 +14104,7 @@ packages: dev: false name: '@rush-temp/localization-plugin-test-02' resolution: - integrity: sha512-zQq32ePCwtsFlKDRWANJG0cQil/E0R6Dk0gNHyRSSZ3QkBVZnKLnl8y78m2vm7I0AKR8PVxZGg1kRM0fZ97MlQ== + integrity: sha512-w+8luyyxPHtKa2oMSZw+P7yLpM9hXD4yhwy+HgGcuqGnhfMx1uG1PvPM1VDjS8x95/vcj6pGHqW+mP0Zp+i/VA== tarball: 'file:projects/localization-plugin-test-02.tgz' version: 0.0.0 'file:projects/localization-plugin-test-03.tgz': @@ -14106,7 +14119,7 @@ packages: dev: false name: '@rush-temp/localization-plugin-test-03' resolution: - integrity: sha512-/EV8sjIZNNdo2AOjC4JrKnjeinXGhIfqp7wN7/WiFb57O6gkrW+JNF8js9nijLy5ioOgZZrs8SX+npM+5Z09dA== + integrity: sha512-sTyftdYindCyrrOnCnGYU01Em30MaxamMmJnQ1utCggKqOtwuDo7yh0DBlsAjbrD+QD0tjDbVLKzk99ta3UbFA== tarball: 'file:projects/localization-plugin-test-03.tgz' version: 0.0.0 'file:projects/localization-plugin.tgz': @@ -14127,7 +14140,7 @@ packages: dev: false name: '@rush-temp/localization-plugin' resolution: - integrity: sha512-HWHktzogB6ljtHkcqixLYI5Z6eyrmQjrZEpF22FyA15C0ysAyHJBcFGOS9O9fla62Kly4+3x7jaQ0iRxCE4lZw== + integrity: sha512-VGY+u0C5ywUsbUmQH5y0LDjwj+lsvbU7JY1ueQ2FmQAIuSmkAcUa3sCLGC6VwvRuOwBJOuS9GwZ0TnG1OLgyzg== tarball: 'file:projects/localization-plugin.tgz' version: 0.0.0 'file:projects/node-core-library.tgz': @@ -14138,20 +14151,20 @@ packages: '@types/jest': 25.2.1 '@types/jju': 1.4.1 '@types/node': 10.17.13 - '@types/semver': 5.3.33 + '@types/semver': 7.2.0 '@types/timsort': 0.3.0 '@types/z-schema': 3.16.31 colors: 1.2.5 fs-extra: 7.0.1 gulp: 4.0.2 jju: 1.4.0 - semver: 5.3.0 + semver: 7.3.2 timsort: 0.3.0 z-schema: 3.18.4 dev: false name: '@rush-temp/node-core-library' resolution: - integrity: sha512-KbpKrFYw8ix5FRrjSRFUbJpF/fwMkXi/FNFGMR4RcNI7MkVwuh7MB+28MuYYh75qCeTacs/oJ4Bj/EkNY7FaKA== + integrity: sha512-fv6ABTvDWODQPGdweV5+tOv48waDjIutpFk7MotmaytCVH1URqoEACu1Kp1B2fGTYGLQO72H7uoXTWM3WoqTgg== tarball: 'file:projects/node-core-library.tgz' version: 0.0.0 'file:projects/node-library-build-eslint-test.tgz': @@ -14164,7 +14177,7 @@ packages: dev: false name: '@rush-temp/node-library-build-eslint-test' resolution: - integrity: sha512-ZopfSJK357sf69EDvR+Q8oeyHzgIwNYX33sXTxieIIoRVLPYwBJwGTzvi4ALCvcSn9GKLTj34mztCQ2WS8KAOg== + integrity: sha512-wIE10iNotS0fEVHHC06Ii8rYUwmMNrsWSpYmPEUfBSn88xxeWjX3shXdMq9FcE2zdHvnvjkLqYai6DBBNMcEZA== tarball: 'file:projects/node-library-build-eslint-test.tgz' version: 0.0.0 'file:projects/node-library-build-tslint-test.tgz': @@ -14177,7 +14190,7 @@ packages: dev: false name: '@rush-temp/node-library-build-tslint-test' resolution: - integrity: sha512-9Ri18p3xprEwYWB9lEupqxSbLD0OYvByFm0wgyupNnQWNpQQ6akbKNrtJ2p+pCJhsU6BOoiAiPE62a4ZOz7aEA== + integrity: sha512-OIXHyd75mDt9Epal63vQVMIS/CSC2d/wDqoSKA04j5Qx9aU+UWHChXt4Ox7WNEzeUiyun6jXNc8IX56ZCmkN7A== tarball: 'file:projects/node-library-build-tslint-test.tgz' version: 0.0.0 'file:projects/node-library-build.tgz': @@ -14188,7 +14201,7 @@ packages: dev: false name: '@rush-temp/node-library-build' resolution: - integrity: sha512-SLgyd48UKfUsL++tg2ikOOBQrtzqDt6GLAHY36r8sgHoxGF/qhNgEVr7KRmJI+PmV3I4qdcoiizeLhwB+Ehu+g== + integrity: sha512-3y7+vQ7ZhYy5DHVmXyRfQob4hIAWJ0JWRBpn7kmoUWuMXuuMUbSKP1Rq4FNRmE5+lIXlOmsibzwJu5cD8zI80w== tarball: 'file:projects/node-library-build.tgz' version: 0.0.0 'file:projects/package-deps-hash.tgz': @@ -14202,7 +14215,7 @@ packages: dev: false name: '@rush-temp/package-deps-hash' resolution: - integrity: sha512-GZcMF9QvJBODbYZo+f1o4qbQJ7RV3Y4rzLkIaja7QiVCvP6o5Vd1uU/AOXVNV3rtxLdbjux0aN+BgZ7pKpbsKQ== + integrity: sha512-0RrXA1YHv5w/0+7Usobjto78GUox8WGLX6KQu8jxabePYrqeCW1tFSKGjCJcv73acpSTgWKZ9dZuwWgz5Sx6OQ== tarball: 'file:projects/package-deps-hash.tgz' version: 0.0.0 'file:projects/repo-toolbox.tgz': @@ -14212,7 +14225,7 @@ packages: dev: false name: '@rush-temp/repo-toolbox' resolution: - integrity: sha512-o00o8i2vaipPVKkNwZcPwx69yE2j0uS+FgEyK8hw1x4qpfu18js+p4lICZJmnrrXgL/EdmmzZMX/2RfeUUFGSw== + integrity: sha512-TrIQ3Y132JyWgkDS1++9pv/uj0RAiKTSTF7lb0iGbWoIgHWdL/axJjhttF42AEcgEtcTOG6WUkgEVlswdvD7tA== tarball: 'file:projects/repo-toolbox.tgz' version: 0.0.0 'file:projects/rush-buildxl.tgz': @@ -14223,7 +14236,7 @@ packages: dev: false name: '@rush-temp/rush-buildxl' resolution: - integrity: sha512-5ZqLtSQiIW/r6Hdy9H+6mwAW7V7Wv0sSKv8/Q/Xnczq6ax55l1WT2djRocuk92XHigJeMcEEbwLn0xVrnPVaIw== + integrity: sha512-FG1gZPrX4lwo+SulIcjAiKo/4VCokZP/bI95czvyjOh3qLuK7PePWq9eSBLtBGczOj6V29Cc0pDL50OSS0VnhQ== tarball: 'file:projects/rush-buildxl.tgz' version: 0.0.0 'file:projects/rush-lib.tgz': @@ -14241,7 +14254,7 @@ packages: '@types/npm-packlist': 1.1.1 '@types/read-package-tree': 5.1.0 '@types/resolve': 1.17.1 - '@types/semver': 5.3.33 + '@types/semver': 7.2.0 '@types/strict-uri-encode': 2.0.0 '@types/tar': 4.0.3 '@types/wordwrap': 1.0.0 @@ -14266,7 +14279,7 @@ packages: npm-packlist: 2.1.2 read-package-tree: 5.1.6 resolve: 1.17.0 - semver: 5.3.0 + semver: 7.3.2 strict-uri-encode: 2.0.0 tar: 5.0.5 true-case-path: 2.2.1 @@ -14275,7 +14288,7 @@ packages: dev: false name: '@rush-temp/rush-lib' resolution: - integrity: sha512-R/yehJRKgcHDqb5D6xznaEEsHDc+CATn9+dQYSmCDpeABxRY/yt7xAO1JL0psLK0S5yev141mXMcBG4E1Bj9kQ== + integrity: sha512-rw9dkkbqx7iVFsr/KYOkJd/Rs7GS8XM4CjfB9tjARtrGKHjzjvuWHWdRQbjoGJyLyXPfuyweux1Y7Ac3uTpGtQ== tarball: 'file:projects/rush-lib.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.4-library-test.tgz': @@ -14285,7 +14298,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.4-library-test' resolution: - integrity: sha512-wZd9J87rkM3OUGiCKJVuOpnNxCM/K4E9DjptkR6Je+blwR6C3veADR4lrlJ2dYcyqKv06ymr3LXCnD8GviAHSQ== + integrity: sha512-2v78Iif8yBORoAjZLV1IYwU1o27RyITRo4ZP6/jEFNea65pHIFHPgw/v9XvcYOnzQadpEiuyDx6+zcjy1Ck6gw== tarball: 'file:projects/rush-stack-compiler-2.4-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.4.tgz': @@ -14302,7 +14315,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.4' resolution: - integrity: sha512-aeB8r5YnbXKEMrvsuOD9peUX0IPLzA5IIEZ300Ez8T6Z+phUMgAB5WRlA49AWxYGL5tebhb9WrLiDXRu8pM57Q== + integrity: sha512-57P6ZVFgRpKnp/3ZrL0EYiDlzkTEqRhlZeUE6lZYdwp9Mzr0Xzlrx+5p7MjT8t9k9b2pvx2IFwbcEzyllaoZMw== tarball: 'file:projects/rush-stack-compiler-2.4.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.7-library-test.tgz': @@ -14312,7 +14325,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.7-library-test' resolution: - integrity: sha512-rUnkvJt3TY+bxRym7UOyZjsmA8blrr3JWuDc6PtMsqofqbGe03oEbhgjYIw9zwH3VJ2uIF+3PTjbOqQOiF3txQ== + integrity: sha512-hMkhP7E+CWZEmP9IUPqcjkxaRBztoMG0V2rvXwE3pPqabMgyRKmqlxARCwFbVBTECgfoeF3rSh5MXqlqfMvv9Q== tarball: 'file:projects/rush-stack-compiler-2.7-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.7.tgz': @@ -14329,7 +14342,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.7' resolution: - integrity: sha512-gTnGqZ7inGvmu6PHwkL1pvVUJmleoAezVeXsFNJ/Fo8Aate3Wsps9v7ofSAhIBrbZeYBubQDM7Mqn8uZItC/gg== + integrity: sha512-UC9Hv2u9wjj+uZ1CkWpcEsWC3Ke5kqkIZJTAY7TzYYTxRapqZwJOvp0zE23bqaLisToMqxnNfnNuvC/9CdGNEw== tarball: 'file:projects/rush-stack-compiler-2.7.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.8-library-test.tgz': @@ -14339,7 +14352,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.8-library-test' resolution: - integrity: sha512-r2EUCsVpjknBuzZs2tj23NI416qL34tb+pX3m8vZMkjWNLXvbVjOTnvreND80KxgXGQ9tVl5trAwM033hlKH1w== + integrity: sha512-ylHQuTGU6bSmSJpDxTbU2OWz5aU1n/OadUTaSXBpRgJmwo6i3nMri3kPY2jZ/nIPpdBCm7pAUsjpM20zXp98/A== tarball: 'file:projects/rush-stack-compiler-2.8-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.8.tgz': @@ -14356,7 +14369,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.8' resolution: - integrity: sha512-G6irQE9f6PTRzJATk9rUOnxGTtJa4ZTSoXB3rS6rw14CQYhOwDcXyIRumoJF3p8tikRi5sDPXpdSdccAgXv61Q== + integrity: sha512-Xyli6uxNrVQRV0ZNdm8El2zKhmpnB0zmA/xhUj8T4fO6oT+N5xuFzV2PwNKVg6plbD4962xE0H8eICKmg/6VTA== tarball: 'file:projects/rush-stack-compiler-2.8.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.9-library-test.tgz': @@ -14366,7 +14379,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.9-library-test' resolution: - integrity: sha512-U7Pc7r/KZE33V/aTeAqJrQR4GPSZYzsKLt7yqYl3+UxCrqFZUAWpCtrAEBfMXNeeg0GBRnPEZ0zGExZG89+AFw== + integrity: sha512-4M9DvDPj55BdSjhXaURSX3ecYXtyFQjWgzjyR3UsFn5xYFWLvbuwEMAOUScVXw6rZtbT07mp35ZRFoi4JWaSPw== tarball: 'file:projects/rush-stack-compiler-2.9-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.9.tgz': @@ -14383,7 +14396,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.9' resolution: - integrity: sha512-7XzWltLvjR3ERWhJ6nAoL1/v1l00WTyhdpY0DF7ycqTlo/9vMVFFhudiL2iaUWuoNtxgvdkp1RRoVu7RLvwDcQ== + integrity: sha512-UQFb882awER9Y2RBIh3aEvlrsku1TJ8W65iULFkUAjSIwNdg6L6ff6kqkNjKg58w8DHQ8LP9JTABf1/z3RfvTA== tarball: 'file:projects/rush-stack-compiler-2.9.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.0-library-test.tgz': @@ -14393,7 +14406,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.0-library-test' resolution: - integrity: sha512-Ys2OCAVxLr/HvEJD4YNuCWtZQoBdKhEtdGCCT5297GCgW7i94r6we0M87t3O63VR4meDkpszO44KNOI25cwVcA== + integrity: sha512-oY3sGqtHbDeVODrDnMVxqe22w3RbMahHFY7+2w83GMIUgtBIRIlfoYTvnSfQ2iIUGl1pjqPYbN0jW9jdePG/4Q== tarball: 'file:projects/rush-stack-compiler-3.0-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.0.tgz': @@ -14410,7 +14423,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.0' resolution: - integrity: sha512-Op8d4SA/OXSc2pw/YZnRC1Fn+4VLAIEtaCZ+Rz3FGWDNKuYXs5OQr8LxcgJmJxr1shSYekhkxWtUgsVq9eZlaQ== + integrity: sha512-LieTrQ5hGWMaYZY1Rd654W1Sr95/WHv+RyRxPwrjd82VrFcdfWw8DpCG0weIt9b7ejBmHOjL2dphAJEoEDp9Aw== tarball: 'file:projects/rush-stack-compiler-3.0.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.1-library-test.tgz': @@ -14420,7 +14433,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.1-library-test' resolution: - integrity: sha512-j5yRgdoEcCrk1IRT0Yh4rvpd3/bbNrEVAcyU2+Iw8MALU0/o8uxoxeFjtjAzCONdkSBkRSSsNK9NZy61esabPg== + integrity: sha512-fBo+TTntb9Y0ljrlwaojekjry5AloO0xyOUqAMS8aS4ua0yt8xnUggWYxRU/9I3rHgiChUYwcDlRj0j/TkCzEw== tarball: 'file:projects/rush-stack-compiler-3.1-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.1.tgz': @@ -14437,7 +14450,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.1' resolution: - integrity: sha512-FC1e2jU6b7ulSZi3Icpe4rNs+WO3+NhiS7nVWo4kg+Qd2OKcBvBcGtufIh47hsnFQZFFaPyYG1RnakmLwAowuA== + integrity: sha512-KarOZC0BcXyg2ZWFZw5jTpDE9MCulfq/W1P8ZOUIA7/iS7keRqUb5UtJQxq+dWtjPusgYPoxhGXEQUVBPEvclg== tarball: 'file:projects/rush-stack-compiler-3.1.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.2-library-test.tgz': @@ -14447,7 +14460,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.2-library-test' resolution: - integrity: sha512-7iz9JockwzYTHEu/L4ofCiSZ5edA4seybl6qoB7dhHGbetfKk5bFEfnAvZEL31GpYI4/9zINVgdxOlgcWaS+Qg== + integrity: sha512-nhxrLyS3GRHnFOxTpGLLlZVCyxE5RtWhO0tmGnQiZ/NJC7JcgIn7vEKNUIjpIgiOrSc87aXBYOzN80UiSAMxlg== tarball: 'file:projects/rush-stack-compiler-3.2-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.2.tgz': @@ -14464,7 +14477,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.2' resolution: - integrity: sha512-TdULgV+5LM93cOOtxkO1FbifSZ3DL+rsCgliNMHgNYSSFouQE6BzesjobC4BmyWFImViVfJLASir4FwVru6IkQ== + integrity: sha512-9BmcH3cHS5YgNEXJbspDEJ+KhyJadTerPBtupqKUsukdXgnfWRsw+wUinr9rpD8fz+Fs7I/GB9/zFIwk8mcokA== tarball: 'file:projects/rush-stack-compiler-3.2.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.3-library-test.tgz': @@ -14474,7 +14487,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.3-library-test' resolution: - integrity: sha512-dAPQM1uirk16+qGfwCec9IROVz71FhB1rnv9+UwhEsBMEcHl4HFDFK8hCgfWqWUMlE6oBzzxMirT+kVBYtS5Pg== + integrity: sha512-X/2xMB7l6ADEkmqtSxDphN0oqNEsSJB4IalCd/Cw66GZP3mRWGKBg3aq+Hx1JEn9t0FUa5JcLxpx4frzbRNQGw== tarball: 'file:projects/rush-stack-compiler-3.3-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.3.tgz': @@ -14491,7 +14504,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.3' resolution: - integrity: sha512-mvpNTFYjG8MtMPojDDh1hbAlKaZpevMNBTcXY+jDZktBMfAzisvmqZtvBBuSKe5+zhBD9u/+5ilY5wj6icndVw== + integrity: sha512-zNkp3TWnAcK0zPiOGxpT9VfPei5ip4x31ZDwZs0aX9o2XPzCxCvG4P7ck4U9MnylnN03VGtZHJ3HRVdhjnkcUg== tarball: 'file:projects/rush-stack-compiler-3.3.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.4-library-test.tgz': @@ -14501,7 +14514,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.4-library-test' resolution: - integrity: sha512-ZbivHNUjN4+/DhjvNs2H+M5VSnDg4/wXhC6XCPjRB2kEsHcbPy/MB+ha84CdiWHhMMJQLRp2zjMrjJwXuM2WCg== + integrity: sha512-hqKwsfxgJJNQU4YgC8DwEaOJYUElDMaLnfw2Asra2zE4IOJQDczqyIR0wP/7yI7bfPNwaUigN+sLl4c2BKEjEQ== tarball: 'file:projects/rush-stack-compiler-3.4-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.4.tgz': @@ -14518,7 +14531,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.4' resolution: - integrity: sha512-M5+T1UKrwmAkbjqK+1Dxlgk7Gs7t/gKLO73kK6xadt+WljEUfVzYZELYGTZsfPMyWSEo97sq3GsZrGMhAfm+Gg== + integrity: sha512-prGtvvhsIEDPrtgR7nAV/qLX9kgpQYFz19BnkMtjRfRCBf3pwL+W1X7lwLbUgj7qosjLt8Jh1UIvbX63ldVOqw== tarball: 'file:projects/rush-stack-compiler-3.4.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.5-library-test.tgz': @@ -14528,7 +14541,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.5-library-test' resolution: - integrity: sha512-twhTH4z3DZnMW80Wnks750VJBpBqrW+aG2U4hFFQdS/1vdQZMgDqHuUZ/xVUdvPoWm3iQY9oQ4M7Fa7XN2zNMA== + integrity: sha512-8pqwhi6Rq8ntcpvx6G0OSWk4HSOw3ICCtxqNr9EwKi2CPWBhjhiXEkkhs2bp0GXgLjfavDVZosR3Ta0UbPpw0Q== tarball: 'file:projects/rush-stack-compiler-3.5-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.5.tgz': @@ -14545,7 +14558,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.5' resolution: - integrity: sha512-lHKG3W43Fo67kVo06NvhL1p+ilYiATOCA5P3f0DeGZrMA5wvgVRsHhZ6NM2kflw1Yw8O7rFzMKyHZleOw9EzOg== + integrity: sha512-pg+nSIUt9aGFRkoGPFVnVfK6Sbh//gQRrX8hWxEXSLtB0wwrw/TaLMxuJSE6qPLN1xuc90XKHP5LjGr9ZXCNew== tarball: 'file:projects/rush-stack-compiler-3.5.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.6-library-test.tgz': @@ -14555,7 +14568,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.6-library-test' resolution: - integrity: sha512-vn++jRalZzzY6UgLh/J/RXiGVN1VUJ0ot0XjcsgJ/2Euf2IaUdU1EZA6Sa8uI3zbHxgPK+uZbqGgPJUKigg1+g== + integrity: sha512-+y+e5tTG6/MgmKykS1AFhqQWKDvDa+y0EtJJnQJ0R90S9sQdEyyRsHI2V6sUVy6HWb34xTnlWUnXuBvkEk0f/Q== tarball: 'file:projects/rush-stack-compiler-3.6-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.6.tgz': @@ -14572,7 +14585,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.6' resolution: - integrity: sha512-e5w4B+72i2s0D7CRxkj4Le5sRHw0aOb8xw8sjLn9FwoSdKA9fc12S8g1N1jdkKJSPxnulZGpNRBlB9CWpZugkQ== + integrity: sha512-eYCoOrDyiJDR8yEkiIikL/m46rZGwmYdOUyutBUcl8LtXVuHfBdL2t4YB2u9p16fOtbMA59Ji00bHzmueGVDdA== tarball: 'file:projects/rush-stack-compiler-3.6.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.7-library-test.tgz': @@ -14582,7 +14595,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.7-library-test' resolution: - integrity: sha512-O0/2UTda/4cFhvPpGZXwPzajkONYUU1oboAJq8cypmqAPWffmzKiI5YJLZEKCzpKuYJbHXKgI+/JVLcvdew20Q== + integrity: sha512-3Y4p/vdIkwhVX2O699pDU4pKQ5DPW5M8jBGn9d8cmJPkQxdXuyD4+2Muf/PUIJSgIkaHh3nER0MCL3gVtKqE5w== tarball: 'file:projects/rush-stack-compiler-3.7-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.7.tgz': @@ -14599,7 +14612,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.7' resolution: - integrity: sha512-Lnzim9tMDFcrbN8zCEYBb/8m1m7ZXDNTTCXDLdWyNVvvOVMJnBHt7y5/WZuhEeBClBnuhA9/VYvpVn08kJ0UWw== + integrity: sha512-fu+y4D9ubcWWcxfLm9KwXH4cRHLXz07RUxNQUpDVvJZt3CP22mTgz8oqE/sRjvAeNbVuTzD5zUmh7g0YuXc0fw== tarball: 'file:projects/rush-stack-compiler-3.7.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.8-library-test.tgz': @@ -14609,7 +14622,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.8-library-test' resolution: - integrity: sha512-lTgqOFzebnh6/CpNx4R6nJWyLmwA3N/gh0o9uDmN/3XUngHyvSmVaPOmMEJARmcJlAVtygk6QlLMYmfSXPcvTQ== + integrity: sha512-WEPjJLl/NCyk1+pNzegflvuq5oEVIjJfe9JaPMkd4DgDa8McNRJdeYVBNrl2hFH16n1MxUiFJH7QMgHRArLSfA== tarball: 'file:projects/rush-stack-compiler-3.8-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.8.tgz': @@ -14626,7 +14639,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.8' resolution: - integrity: sha512-6Mi8UxqL6NMirkpDA/e+wQpHH+08m/Mde03de5g7sM8GRXbQEuNCidEKUCnC2vYa9AJLxQJwSLk6Aslp2ShVnQ== + integrity: sha512-0sRxabQ8klB4RtahkVubv7gmpzhNOGMau6PMH8w522W/9QVLHwxgZivMNUAIR/AesKCBDyC0h4UqQAI65MJg5Q== tarball: 'file:projects/rush-stack-compiler-3.8.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.9-library-test.tgz': @@ -14636,7 +14649,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.9-library-test' resolution: - integrity: sha512-7u4jI0r+mgBxO8FDulKwvTX2s2PduonHFAxSSbatu/aOaj04wzzKcqINplWbkh3Cm2MX4gzLByYV1xQnLpZHAA== + integrity: sha512-RYQBHxw8QLidr3+xWFXLTZ/bRq55yb0sg95IMgY4ZG4IqcuqazmR7cfr8k0h26lpCRJUIwSTrjXULHtN0Qau/A== tarball: 'file:projects/rush-stack-compiler-3.9-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.9.tgz': @@ -14653,14 +14666,14 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.9' resolution: - integrity: sha512-SrVuAqENR6feWYjpjLU3qZBlOMMzYC9jLbJvWcsPsNCCUVRzChsrb0ov9bXTFGoIKxwQnB7lZ8pRC0yYvLFRyw== + integrity: sha512-DohfyyEzS9DVMho2kA29fZzE8TxdCKJyymcQ5/SHYMbFF1/tcdD5lL5kMNPLTJz/IdsjoLQ7MEvkUIQmn0i+eQ== tarball: 'file:projects/rush-stack-compiler-3.9.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-shared.tgz': dev: false name: '@rush-temp/rush-stack-compiler-shared' resolution: - integrity: sha512-3DA+ZdhWSjTNrAVaC6G9AizudJaiO82PoNgCTQ/3PQ4g4J9xx6BrNv+sVPv/4h5ST2WQhdHiY9OW0/2xWDWY/A== + integrity: sha512-B/FgBb0ekMVleIdND/Bsh+UjT7JH07tE06QHduB3wOCxNn8NxSsc3XzRb2Gb9XI7LEc+/Raa7cywXdKhwTTi8g== tarball: 'file:projects/rush-stack-compiler-shared.tgz' version: 0.0.0 'file:projects/rush.tgz': @@ -14669,17 +14682,17 @@ packages: '@types/jest': 25.2.1 '@types/mocha': 5.2.5 '@types/node': 10.17.13 - '@types/semver': 5.3.33 + '@types/semver': 7.2.0 '@types/sinon': 1.16.34 chai: 3.5.0 colors: 1.2.5 gulp: 4.0.2 - semver: 5.3.0 + semver: 7.3.2 sinon: 1.17.7 dev: false name: '@rush-temp/rush' resolution: - integrity: sha512-Xr9FSIjsx12eDeFcATCKyPZobDfbyMRB5nfWj3+s/cwzehxxvuCxt6AEk2AkGXUipgrMqm8odV4qwaJ6vYqshA== + integrity: sha512-ZvLxIYiPjbmHAsDHIIE9hPwidL6PCH3SWwEU50fKRxRR6awT8c9NXIB6FKkjlJ8cVLpCTCxAtqp4XfoVLR46kg== tarball: 'file:projects/rush.tgz' version: 0.0.0 'file:projects/rushell.tgz': @@ -14692,7 +14705,7 @@ packages: dev: false name: '@rush-temp/rushell' resolution: - integrity: sha512-HAw9cYEpa/3EhPOe9wJvZUit1Wv0JYdsnkhqrfVc7V0DAetWjkVJ04M5b5hq6DndllcTYeDjvALtMn1B/RLMcQ== + integrity: sha512-dipxANGemIA9EpAjTGKfmIEF8gjGBK26fbWcK0VkFtmtpXy92FeGF/VsGIb3YOFzU1ldkl1yaDClTQjtglun2w== tarball: 'file:projects/rushell.tgz' version: 0.0.0 'file:projects/set-webpack-public-path-plugin.tgz': @@ -14712,7 +14725,7 @@ packages: dev: false name: '@rush-temp/set-webpack-public-path-plugin' resolution: - integrity: sha512-gBsfvOd/3S00choyTEY4FL3Oen/7+/+zqh/CA6bYgKw3g5i6ziCJT0wrdNsNDqPjzpQIzw99UiY/Yr5THGVWeg== + integrity: sha512-qusGxbGhGj78SgupkBiW6FnrT0P9di5UfVruaLS21hbG8d8dlBOXyxi8fZW74o7ruDuDz2aIKnkJnn3fWuOF/g== tarball: 'file:projects/set-webpack-public-path-plugin.tgz' version: 0.0.0 'file:projects/stream-collator.tgz': @@ -14728,7 +14741,7 @@ packages: dev: false name: '@rush-temp/stream-collator' resolution: - integrity: sha512-1f0L1wJRpwb/NXPqdS8c/pfyP461LY3LtkfUmvCngsXIhjcu+V5SOHgA+RLN6L/MIAz9VUdu5yL1Vl2bKMjA7g== + integrity: sha512-iEwUuzQEhf6ZUEPKd1LiFS9QKfKuPMOJUhCBao87juV/2uJF3WIcG6V9WjscjClI0GKXFesvykpddCcKPE6b7w== tarball: 'file:projects/stream-collator.tgz' version: 0.0.0 'file:projects/ts-command-line-test.tgz': @@ -14739,7 +14752,7 @@ packages: dev: false name: '@rush-temp/ts-command-line-test' resolution: - integrity: sha512-PF0W2WNYpnAIej7J5Y5d5G00q2NWwjGkzjiBRQkw0SXGGSRpFmfnW7OaO/lHL9tonTbaLO1h97CLbinSgMyR/w== + integrity: sha512-vFZJ1Qfi9GFAtOMkAoGvGPmmtXEGK53RSneMS6Spdpt1HtYi/0iNcl202dqsGoxBwc8SDJcI2tjc2tDT+Vz0BA== tarball: 'file:projects/ts-command-line-test.tgz' version: 0.0.0 'file:projects/ts-command-line.tgz': @@ -14755,7 +14768,7 @@ packages: dev: false name: '@rush-temp/ts-command-line' resolution: - integrity: sha512-3c0Dm8DFwkjX4FVA3ItPTt1sowqFSDXX5jC4b/mbB6Edm6E0UrYIeoNzrQwUNlfyzNIUkch+Yz9UJxOda6hwDA== + integrity: sha512-nX8i0DpfELk1LGXQqcy9CKGPRwLmOGzHVVF/CXCCZmyheXJQAc5g22VXYdQW0xRkHU7HKyKa8DbcpOAZSjoWUw== tarball: 'file:projects/ts-command-line.tgz' version: 0.0.0 'file:projects/typings-generator.tgz': @@ -14768,7 +14781,7 @@ packages: dev: false name: '@rush-temp/typings-generator' resolution: - integrity: sha512-Bjp19dJTfczpo2j5koFbvwqwPDiAcC/SFdAu9mje5TdJn3zjRcNGHzBi24lNELswB/xFaNhXJ9fC8heRwekzyQ== + integrity: sha512-PSvE7VbftzMXJeP3dLJEN1IOlLBrfXud4FAtgZRIgGZvy/sx0TqkL3VYScNrndVEBaCvgGUMsGRAC5eeThXcvg== tarball: 'file:projects/typings-generator.tgz' version: 0.0.0 'file:projects/web-library-build-test.tgz': @@ -14780,7 +14793,7 @@ packages: dev: false name: '@rush-temp/web-library-build-test' resolution: - integrity: sha512-6u+043pskfcvVA1AATbIYvee+L4EPaP9C4XYLMrH2wJqtzbyKPTr2nEOTTLswf7zT51AsrJQWudXp/J29jlkiQ== + integrity: sha512-3+hYz6E6JAUPZHqeriKpF1MKUfnuY9nUbJXnHUAPdQhebI1ldgKOQ4zyn+LBg1jcw4YEb0DCfvnDEb5VI7V9ig== tarball: 'file:projects/web-library-build-test.tgz' version: 0.0.0 'file:projects/web-library-build.tgz': @@ -14792,7 +14805,7 @@ packages: dev: false name: '@rush-temp/web-library-build' resolution: - integrity: sha512-NU/fcSow7XkIdAULYDYGzve0H3SJ0it0txm4j14S/2SvzOaYDvas5CfNsj84o+z5+SYds0P2nHQ6llCR15kM8Q== + integrity: sha512-nD1tSW0ehEoMAghr3KS+p192wGTl/MKEcPRRwhRV/mMtiB5n9OQSJGJHZisEbymgo8kFrF6pLFMgD8t5fLuGeQ== tarball: 'file:projects/web-library-build.tgz' version: 0.0.0 registry: '' @@ -14913,7 +14926,7 @@ specifiers: '@types/orchestrator': 0.0.30 '@types/read-package-tree': 5.1.0 '@types/resolve': 1.17.1 - '@types/semver': 5.3.33 + '@types/semver': ~7.2.0 '@types/serve-static': 1.13.1 '@types/sinon': 1.16.34 '@types/source-map': 0.5.0 @@ -15000,7 +15013,7 @@ specifiers: pseudolocale: ~1.1.0 read-package-tree: ~5.1.5 resolve: ~1.17.0 - semver: ~5.3.0 + semver: ~7.3.0 sinon: ~1.17.3 source-map: ~0.6.1 strict-uri-encode: ~2.0.0 @@ -15025,4 +15038,4 @@ specifiers: xmldoc: ~1.1.2 yargs: ~4.6.0 z-schema: ~3.18.3 -# shrinkwrap hash: da1b183013f5b9337a45ba9ea584835ba0c592b8 +# shrinkwrap hash: 8bc86b40cebd75f1d7bdf06001439e8ebfed61be From cadb3f67feb00590cab23c21b477a07c1e9419cb Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Wed, 17 Jun 2020 13:01:01 -0700 Subject: [PATCH 04/33] Rush change --- .../supportWorkspaces2_2020-06-17-19-59.json | 11 +++++++++++ .../rush/supportWorkspaces2_2020-06-17-19-59.json | 11 +++++++++++ .../supportWorkspaces2_2020-06-17-19-59.json | 11 +++++++++++ 3 files changed, 33 insertions(+) create mode 100644 common/changes/@microsoft/gulp-core-build/supportWorkspaces2_2020-06-17-19-59.json create mode 100644 common/changes/@microsoft/rush/supportWorkspaces2_2020-06-17-19-59.json create mode 100644 common/changes/@rushstack/node-core-library/supportWorkspaces2_2020-06-17-19-59.json diff --git a/common/changes/@microsoft/gulp-core-build/supportWorkspaces2_2020-06-17-19-59.json b/common/changes/@microsoft/gulp-core-build/supportWorkspaces2_2020-06-17-19-59.json new file mode 100644 index 00000000000..629de4dfae3 --- /dev/null +++ b/common/changes/@microsoft/gulp-core-build/supportWorkspaces2_2020-06-17-19-59.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@microsoft/gulp-core-build", + "comment": "", + "type": "none" + } + ], + "packageName": "@microsoft/gulp-core-build", + "email": "3473356+D4N14L@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@microsoft/rush/supportWorkspaces2_2020-06-17-19-59.json b/common/changes/@microsoft/rush/supportWorkspaces2_2020-06-17-19-59.json new file mode 100644 index 00000000000..0143cb521c2 --- /dev/null +++ b/common/changes/@microsoft/rush/supportWorkspaces2_2020-06-17-19-59.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "", + "type": "none" + } + ], + "packageName": "@microsoft/rush", + "email": "3473356+D4N14L@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/node-core-library/supportWorkspaces2_2020-06-17-19-59.json b/common/changes/@rushstack/node-core-library/supportWorkspaces2_2020-06-17-19-59.json new file mode 100644 index 00000000000..2f920ab86a1 --- /dev/null +++ b/common/changes/@rushstack/node-core-library/supportWorkspaces2_2020-06-17-19-59.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@rushstack/node-core-library", + "comment": "Add a utility method to convert a map into an object", + "type": "minor" + } + ], + "packageName": "@rushstack/node-core-library", + "email": "3473356+D4N14L@users.noreply.github.com" +} \ No newline at end of file From 7acf1eddd311c293db9ed201c13f9b21b14a976f Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Wed, 17 Jun 2020 13:12:46 -0700 Subject: [PATCH 05/33] Lint --- apps/rush-lib/src/logic/pnpm/PnpmProjectDependencyManifest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/rush-lib/src/logic/pnpm/PnpmProjectDependencyManifest.ts b/apps/rush-lib/src/logic/pnpm/PnpmProjectDependencyManifest.ts index a30a20c5fc5..a374ada4795 100644 --- a/apps/rush-lib/src/logic/pnpm/PnpmProjectDependencyManifest.ts +++ b/apps/rush-lib/src/logic/pnpm/PnpmProjectDependencyManifest.ts @@ -253,7 +253,7 @@ export class PnpmProjectDependencyManifest { const combinedPeerDependencies: string = specifierMatches[1]; // "eslint@6.6.0+typescript@3.6.4+@types+webpack@4.1.9" --> ["eslint@6.6.0", "typescript@3.6.4", "@types", "webpack@4.1.9"] const peerDependencies: string[] = combinedPeerDependencies.split('+'); - for (let i = 0; i < peerDependencies.length; i++) { + for (let i: number = 0; i < peerDependencies.length; i++) { // Scopes are also separated by '+', so reduce the proceeding value into it if (peerDependencies[i].indexOf('@') === 0) { peerDependencies[i] = `${peerDependencies[i]}/${peerDependencies[i + 1]}`; From f35d08bdd6333309d6da496ccb5eaaf8779e93e4 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Fri, 19 Jun 2020 14:10:26 -0700 Subject: [PATCH 06/33] Add new test files --- .../test/workspacePackages/a/CHANGELOG.json | 10 +++ .../test/workspacePackages/a/package.json | 5 ++ .../test/workspacePackages/b/package.json | 8 +++ .../test/workspacePackages/c/package.json | 9 +++ .../workspacePackages/common/package.json | 7 +++ .../cyclic-dep-1/package.json | 8 +++ .../cyclic-dep-2/package.json | 8 +++ .../cyclic-dep-explicit-1/package.json | 8 +++ .../cyclic-dep-explicit-2/package.json | 8 +++ .../test/workspacePackages/d/package.json | 8 +++ .../logic/test/workspacePackages/rush.json | 61 +++++++++++++++++++ .../logic/test/workspaceRepo/a/package.json | 5 ++ .../logic/test/workspaceRepo/b/package.json | 8 +++ .../logic/test/workspaceRepo/c/package.json | 8 +++ .../logic/test/workspaceRepo/changes/a.json | 9 +++ .../logic/test/workspaceRepo/changes/b.json | 9 +++ .../logic/test/workspaceRepo/changes/c.json | 9 +++ .../logic/test/workspaceRepo/changes/d.json | 9 +++ .../common/config/rush/version-policies.json | 17 ++++++ .../logic/test/workspaceRepo/d/package.json | 8 +++ .../logic/test/workspaceRepo/e/package.json | 8 +++ .../logic/test/workspaceRepo/f/package.json | 8 +++ .../logic/test/workspaceRepo/g/package.json | 8 +++ .../src/logic/test/workspaceRepo/rush.json | 47 ++++++++++++++ 24 files changed, 293 insertions(+) create mode 100644 apps/rush-lib/src/logic/test/workspacePackages/a/CHANGELOG.json create mode 100644 apps/rush-lib/src/logic/test/workspacePackages/a/package.json create mode 100644 apps/rush-lib/src/logic/test/workspacePackages/b/package.json create mode 100644 apps/rush-lib/src/logic/test/workspacePackages/c/package.json create mode 100644 apps/rush-lib/src/logic/test/workspacePackages/common/package.json create mode 100644 apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-1/package.json create mode 100644 apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-2/package.json create mode 100644 apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-explicit-1/package.json create mode 100644 apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-explicit-2/package.json create mode 100644 apps/rush-lib/src/logic/test/workspacePackages/d/package.json create mode 100644 apps/rush-lib/src/logic/test/workspacePackages/rush.json create mode 100644 apps/rush-lib/src/logic/test/workspaceRepo/a/package.json create mode 100644 apps/rush-lib/src/logic/test/workspaceRepo/b/package.json create mode 100644 apps/rush-lib/src/logic/test/workspaceRepo/c/package.json create mode 100644 apps/rush-lib/src/logic/test/workspaceRepo/changes/a.json create mode 100644 apps/rush-lib/src/logic/test/workspaceRepo/changes/b.json create mode 100644 apps/rush-lib/src/logic/test/workspaceRepo/changes/c.json create mode 100644 apps/rush-lib/src/logic/test/workspaceRepo/changes/d.json create mode 100644 apps/rush-lib/src/logic/test/workspaceRepo/common/config/rush/version-policies.json create mode 100644 apps/rush-lib/src/logic/test/workspaceRepo/d/package.json create mode 100644 apps/rush-lib/src/logic/test/workspaceRepo/e/package.json create mode 100644 apps/rush-lib/src/logic/test/workspaceRepo/f/package.json create mode 100644 apps/rush-lib/src/logic/test/workspaceRepo/g/package.json create mode 100644 apps/rush-lib/src/logic/test/workspaceRepo/rush.json diff --git a/apps/rush-lib/src/logic/test/workspacePackages/a/CHANGELOG.json b/apps/rush-lib/src/logic/test/workspacePackages/a/CHANGELOG.json new file mode 100644 index 00000000000..ad83830451d --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspacePackages/a/CHANGELOG.json @@ -0,0 +1,10 @@ +{ + "name": "a", + "entries": [ + { + "version": "1.0.0", + "date": "Fri, Jul 21, 2017 22:30:12 PM", + "comments": {} + } + ] +} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/workspacePackages/a/package.json b/apps/rush-lib/src/logic/test/workspacePackages/a/package.json new file mode 100644 index 00000000000..e57f46f8473 --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspacePackages/a/package.json @@ -0,0 +1,5 @@ +{ + "name": "a", + "version": "1.0.0", + "description": "Test package a" +} diff --git a/apps/rush-lib/src/logic/test/workspacePackages/b/package.json b/apps/rush-lib/src/logic/test/workspacePackages/b/package.json new file mode 100644 index 00000000000..ca4d5662d97 --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspacePackages/b/package.json @@ -0,0 +1,8 @@ +{ + "name": "b", + "version": "1.0.0", + "description": "Test package b", + "dependencies": { + "a": "workspace:>=1.0.0 <2.0.0" + } +} diff --git a/apps/rush-lib/src/logic/test/workspacePackages/c/package.json b/apps/rush-lib/src/logic/test/workspacePackages/c/package.json new file mode 100644 index 00000000000..91588ae3627 --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspacePackages/c/package.json @@ -0,0 +1,9 @@ +{ + "name": "c", + "version": "1.0.0", + "description": "Test package c", + "dependencies": { + "b": "workspace:>=1.0.0 <2.0.0", + "handlebars": "~4.0.11" + } +} diff --git a/apps/rush-lib/src/logic/test/workspacePackages/common/package.json b/apps/rush-lib/src/logic/test/workspacePackages/common/package.json new file mode 100644 index 00000000000..d49725bee24 --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspacePackages/common/package.json @@ -0,0 +1,7 @@ +{ + "dependencies": {}, + "description": "Temporary file generated by the Rush tool", + "name": "rush-common", + "private": true, + "version": "0.0.0" +} diff --git a/apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-1/package.json b/apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-1/package.json new file mode 100644 index 00000000000..855f3fd74cb --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-1/package.json @@ -0,0 +1,8 @@ +{ + "name": "cyclic-dep-1", + "version": "1.0.0", + "description": "cyclic-dep-1", + "dependencies": { + "cyclic-dep-2": "workspace:>=1.0.0 <2.0.0" + } +} diff --git a/apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-2/package.json b/apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-2/package.json new file mode 100644 index 00000000000..c07faa152ca --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-2/package.json @@ -0,0 +1,8 @@ +{ + "name": "cyclic-dep-2", + "version": "1.0.0", + "description": "cyclic-dep-2", + "dependencies": { + "cyclic-dep-1": "workspace:>=1.0.0 <2.0.0" + } +} diff --git a/apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-explicit-1/package.json b/apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-explicit-1/package.json new file mode 100644 index 00000000000..441e0e17faa --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-explicit-1/package.json @@ -0,0 +1,8 @@ +{ + "name": "cyclic-dep-explicit-1", + "version": "1.0.0", + "description": "cyclic-dep-explicit-1", + "dependencies": { + "cyclic-dep-explicit-2": "workspace:>=1.0.0 <2.0.0" + } +} diff --git a/apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-explicit-2/package.json b/apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-explicit-2/package.json new file mode 100644 index 00000000000..6308d48dec1 --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspacePackages/cyclic-dep-explicit-2/package.json @@ -0,0 +1,8 @@ +{ + "name": "cyclic-dep-explicit-2", + "version": "1.0.0", + "description": "cyclic-dep-explicit-2", + "dependencies": { + "cyclic-dep-explicit-1": ">=1.0.0 <2.0.0" + } +} diff --git a/apps/rush-lib/src/logic/test/workspacePackages/d/package.json b/apps/rush-lib/src/logic/test/workspacePackages/d/package.json new file mode 100644 index 00000000000..f6ae89b73d6 --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspacePackages/d/package.json @@ -0,0 +1,8 @@ +{ + "name": "d", + "version": "1.0.0", + "description": "Test package d", + "dependencies": { + "c": "workspace:1.0.0" + } +} diff --git a/apps/rush-lib/src/logic/test/workspacePackages/rush.json b/apps/rush-lib/src/logic/test/workspacePackages/rush.json new file mode 100644 index 00000000000..4c4825157f4 --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspacePackages/rush.json @@ -0,0 +1,61 @@ +{ + "npmVersion": "3.10.8", + "rushVersion": "1.0.5", + "projectFolderMinDepth": 1, + "hotfixChangeEnabled": true, + "approvedPackagesPolicy": { + "reviewCategories": ["first-party", "third-party", "prototype"], + "ignoredNpmScopes": ["@types", "@internal"] + }, + "projects": [ + { + "packageName": "a", + "projectFolder": "a", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "b", + "projectFolder": "b", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "c", + "projectFolder": "c", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "d", + "projectFolder": "d", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "cyclic-dep-1", + "projectFolder": "cyclic-dep-1", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "cyclic-dep-2", + "projectFolder": "cyclic-dep-2", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "cyclic-dep-explicit-1", + "projectFolder": "cyclic-dep-explicit-1", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "cyclic-dep-explicit-2", + "projectFolder": "cyclic-dep-explicit-2", + "reviewCategory": "third-party", + "shouldPublish": true, + "cyclicDependencyProjects": ["cyclic-dep-explicit-1"] + } + ] +} diff --git a/apps/rush-lib/src/logic/test/workspaceRepo/a/package.json b/apps/rush-lib/src/logic/test/workspaceRepo/a/package.json new file mode 100644 index 00000000000..e57f46f8473 --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspaceRepo/a/package.json @@ -0,0 +1,5 @@ +{ + "name": "a", + "version": "1.0.0", + "description": "Test package a" +} diff --git a/apps/rush-lib/src/logic/test/workspaceRepo/b/package.json b/apps/rush-lib/src/logic/test/workspaceRepo/b/package.json new file mode 100644 index 00000000000..1707e03417a --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspaceRepo/b/package.json @@ -0,0 +1,8 @@ +{ + "name": "b", + "version": "2.0.0", + "description": "Test package b", + "dependencies": { + "a": "workspace:~1.0.0" + } +} diff --git a/apps/rush-lib/src/logic/test/workspaceRepo/c/package.json b/apps/rush-lib/src/logic/test/workspaceRepo/c/package.json new file mode 100644 index 00000000000..436566d07c7 --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspaceRepo/c/package.json @@ -0,0 +1,8 @@ +{ + "name": "c", + "version": "3.1.1", + "description": "Test package c", + "dependencies": { + "b": "workspace:>=2.0.0 <3.0.0" + } +} diff --git a/apps/rush-lib/src/logic/test/workspaceRepo/changes/a.json b/apps/rush-lib/src/logic/test/workspaceRepo/changes/a.json new file mode 100644 index 00000000000..43f7263c5e8 --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspaceRepo/changes/a.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "patch", + "comment": "Patching a" + } + ] +} diff --git a/apps/rush-lib/src/logic/test/workspaceRepo/changes/b.json b/apps/rush-lib/src/logic/test/workspaceRepo/changes/b.json new file mode 100644 index 00000000000..6e3320bd6e8 --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspaceRepo/changes/b.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "b", + "type": "patch", + "comment": "Patching b" + } + ] +} diff --git a/apps/rush-lib/src/logic/test/workspaceRepo/changes/c.json b/apps/rush-lib/src/logic/test/workspaceRepo/changes/c.json new file mode 100644 index 00000000000..81eaa9cb51c --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspaceRepo/changes/c.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "c", + "type": "patch", + "comment": "Patching c" + } + ] +} diff --git a/apps/rush-lib/src/logic/test/workspaceRepo/changes/d.json b/apps/rush-lib/src/logic/test/workspaceRepo/changes/d.json new file mode 100644 index 00000000000..abccc8a5d4e --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspaceRepo/changes/d.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "d", + "type": "patch", + "comment": "Patching d" + } + ] +} diff --git a/apps/rush-lib/src/logic/test/workspaceRepo/common/config/rush/version-policies.json b/apps/rush-lib/src/logic/test/workspaceRepo/common/config/rush/version-policies.json new file mode 100644 index 00000000000..ad0b40cd496 --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspaceRepo/common/config/rush/version-policies.json @@ -0,0 +1,17 @@ +[ + { + "policyName": "testPolicy1", + "definitionName": "lockStepVersion", + "version": "10.10.0", + "nextBump": "patch" + }, + { + "policyName": "testPolicy2", + "definitionName": "individualVersion", + "lockedMajor": 5 + }, + { + "policyName": "testPolicy3", + "definitionName": "individualVersion" + } +] diff --git a/apps/rush-lib/src/logic/test/workspaceRepo/d/package.json b/apps/rush-lib/src/logic/test/workspaceRepo/d/package.json new file mode 100644 index 00000000000..d3ff1341f07 --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspaceRepo/d/package.json @@ -0,0 +1,8 @@ +{ + "name": "d", + "version": "4.1.1", + "description": "Test package d", + "dependencies": { + "b": "workspace:>=2.0.0 <3.0.0" + } +} diff --git a/apps/rush-lib/src/logic/test/workspaceRepo/e/package.json b/apps/rush-lib/src/logic/test/workspaceRepo/e/package.json new file mode 100644 index 00000000000..e25c11d8daf --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspaceRepo/e/package.json @@ -0,0 +1,8 @@ +{ + "name": "e", + "version": "10.10.0", + "description": "Test package e", + "dependencies": { + "c": "workspace:~3.1.1" + } +} diff --git a/apps/rush-lib/src/logic/test/workspaceRepo/f/package.json b/apps/rush-lib/src/logic/test/workspaceRepo/f/package.json new file mode 100644 index 00000000000..be93f30c2c5 --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspaceRepo/f/package.json @@ -0,0 +1,8 @@ +{ + "name": "f", + "version": "1.0.0", + "description": "Test package f", + "dependencies": { + "a": "workspace:~1.0.0" + } +} diff --git a/apps/rush-lib/src/logic/test/workspaceRepo/g/package.json b/apps/rush-lib/src/logic/test/workspaceRepo/g/package.json new file mode 100644 index 00000000000..58fb54644ea --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspaceRepo/g/package.json @@ -0,0 +1,8 @@ +{ + "name": "g", + "version": "0.0.1", + "description": "Test package g", + "devDependencies": { + "a": "workspace:~1.0.0" + } +} diff --git a/apps/rush-lib/src/logic/test/workspaceRepo/rush.json b/apps/rush-lib/src/logic/test/workspaceRepo/rush.json new file mode 100644 index 00000000000..c5bc0d96fc2 --- /dev/null +++ b/apps/rush-lib/src/logic/test/workspaceRepo/rush.json @@ -0,0 +1,47 @@ +{ + "npmVersion": "3.10.8", + "rushVersion": "1.0.5", + + "projects": [ + { + "packageName": "a", + "projectFolder": "a", + "reviewCategory": "third-party", + "versionPolicyName": "testPolicy1" + }, + { + "packageName": "b", + "projectFolder": "b", + "reviewCategory": "third-party", + "versionPolicyName": "testPolicy1" + }, + { + "packageName": "c", + "projectFolder": "c", + "reviewCategory": "third-party", + "versionPolicyName": "testPolicy2" + }, + { + "packageName": "d", + "projectFolder": "d", + "reviewCategory": "third-party", + "versionPolicyName": "testPolicy3" + }, + { + "packageName": "e", + "projectFolder": "e", + "reviewCategory": "third-party", + "versionPolicyName": "testPolicy1" + }, + { + "packageName": "f", + "projectFolder": "f", + "reviewCategory": "third-party" + }, + { + "packageName": "g", + "projectFolder": "g", + "reviewCategory": "third-party" + } + ] +} From 5b49dd8634533d1df91b463989cec7aeaf8be7d3 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Fri, 19 Jun 2020 16:52:27 -0700 Subject: [PATCH 07/33] Add 'rush add' support for workspace projects --- apps/rush-lib/src/cli/actions/AddAction.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/rush-lib/src/cli/actions/AddAction.ts b/apps/rush-lib/src/cli/actions/AddAction.ts index 32cd2e44af5..9955d986340 100644 --- a/apps/rush-lib/src/cli/actions/AddAction.ts +++ b/apps/rush-lib/src/cli/actions/AddAction.ts @@ -10,6 +10,7 @@ import { RushConfigurationProject } from '../../api/RushConfigurationProject'; import { BaseRushAction } from './BaseRushAction'; import { RushCommandLineParser } from '../RushCommandLineParser'; import { PackageJsonUpdater, SemVerStyle } from '../../logic/PackageJsonUpdater'; +import { DependencySpecifier } from '../../logic/DependencySpecifier'; export class AddAction extends BaseRushAction { private _allFlag: CommandLineFlagParameter; @@ -128,8 +129,11 @@ export class AddAction extends BaseRushAction { throw new Error(`The package name "${packageName}" is not valid.`); } - if (version && version !== 'latest' && !semver.validRange(version) && !semver.valid(version)) { - throw new Error(`The SemVer specifier "${version}" is not valid.`); + if (version && version !== 'latest') { + const specifier: DependencySpecifier = new DependencySpecifier(packageName, version); + if (!semver.validRange(specifier.versionSpecifier) && !semver.valid(specifier.versionSpecifier)) { + throw new Error(`The SemVer specifier "${version}" is not valid.`); + } } const updater: PackageJsonUpdater = new PackageJsonUpdater(this.rushConfiguration, this.rushGlobalFolder); From 078d7b014553d21b431324fecc399bc99f4f0c51 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Fri, 19 Jun 2020 16:52:55 -0700 Subject: [PATCH 08/33] Add workspaces versioning support and tests --- apps/rush-lib/src/logic/PackageJsonUpdater.ts | 86 +++++---- apps/rush-lib/src/logic/PublishUtilities.ts | 62 +++++-- .../src/logic/test/ChangeManager.test.ts | 169 ++++++++++++++++++ .../src/logic/test/VersionManager.test.ts | 81 +++++++++ 4 files changed, 357 insertions(+), 41 deletions(-) diff --git a/apps/rush-lib/src/logic/PackageJsonUpdater.ts b/apps/rush-lib/src/logic/PackageJsonUpdater.ts index 0f0a541ff93..31a58e09895 100644 --- a/apps/rush-lib/src/logic/PackageJsonUpdater.ts +++ b/apps/rush-lib/src/logic/PackageJsonUpdater.ts @@ -329,7 +329,18 @@ export class PackageJsonUpdater { RushConstants.defaultMaxInstallAttempts ); + const useWorkspaces: boolean = !!( + this._rushConfiguration.pnpmOptions && this._rushConfiguration.pnpmOptions.useWorkspaces + ); + const workspacePrefix: string = 'workspace:'; + + // Trim 'workspace:' notation from the spec, since we're going to be tweaking the range + if (useWorkspaces && initialSpec && initialSpec.startsWith(workspacePrefix)) { + initialSpec = initialSpec.substring(workspacePrefix.length).trim(); + } + let selectedVersion: string | undefined; + let selectedVersionPrefix: string = ''; if (initialSpec && initialSpec !== 'latest') { console.log(colors.gray('Finding versions that satisfy the selector: ') + initialSpec); @@ -338,7 +349,14 @@ export class PackageJsonUpdater { if (localProject !== undefined) { const version: string = localProject.packageJson.version; if (semver.satisfies(version, initialSpec)) { - selectedVersion = version; + // For workspaces, assume that specifying the exact version means you always want to consume + // the local project. Otherwise, use the exact local package version + if (useWorkspaces) { + selectedVersion = semver.clean(initialSpec) === semver.clean(version) ? '*' : initialSpec; + selectedVersionPrefix = workspacePrefix; + } else { + selectedVersion = version; + } } else { throw new Error( `The dependency being added ("${packageName}") is a project in the local Rush repository, ` + @@ -399,7 +417,14 @@ export class PackageJsonUpdater { } if (localProject !== undefined) { - selectedVersion = localProject.packageJson.version; + // For workspaces, assume that no specified version range means you always want to consume + // the local project. Otherwise, use the exact local package version + if (useWorkspaces) { + selectedVersion = '*'; + selectedVersionPrefix = workspacePrefix; + } else { + selectedVersion = localProject.packageJson.version; + } } else { console.log(`Querying NPM registry for latest version of "${packageName}"...`); @@ -424,41 +449,40 @@ export class PackageJsonUpdater { console.log(); - switch (rangeStyle) { - case SemVerStyle.Caret: { - console.log( - colors.grey( - `Assigning version "^${selectedVersion}" for "${packageName}" because the "--caret"` + - ` flag was specified.` - ) - ); - return `^${selectedVersion}`; - } + let reasonForModification: string = ''; + if (selectedVersion !== '*') { + switch (rangeStyle) { + case SemVerStyle.Caret: { + selectedVersionPrefix += '^'; + reasonForModification = ' because the "--caret" flag was specified'; + break; + } - case SemVerStyle.Exact: { - console.log( - colors.grey( - `Assigning version "${selectedVersion}" for "${packageName}" because the "--exact"` + - ` flag was specified.` - ) - ); - return selectedVersion; - } + case SemVerStyle.Exact: { + reasonForModification = ' because the "--exact" flag was specified'; + break; + } - case SemVerStyle.Tilde: { - console.log(colors.gray(`Assigning version "~${selectedVersion}" for "${packageName}".`)); - return `~${selectedVersion}`; - } + case SemVerStyle.Tilde: { + selectedVersionPrefix += '~'; + break; + } - case SemVerStyle.Passthrough: { - console.log(colors.gray(`Assigning version "${selectedVersion}" for "${packageName}".`)); - return selectedVersion; - } + case SemVerStyle.Passthrough: { + break; + } - default: { - throw new Error(`Unexpected SemVerStyle ${rangeStyle}.`); + default: { + throw new Error(`Unexpected SemVerStyle ${rangeStyle}.`); + } } } + + const normalizedVersion: string = selectedVersionPrefix + selectedVersion; + console.log( + colors.gray(`Assigning version "${normalizedVersion}" for "${packageName}"${reasonForModification}.`) + ); + return normalizedVersion; } private _collectAllDownstreamDependencies( diff --git a/apps/rush-lib/src/logic/PublishUtilities.ts b/apps/rush-lib/src/logic/PublishUtilities.ts index 427cc04f1b5..8ccd8017e8b 100644 --- a/apps/rush-lib/src/logic/PublishUtilities.ts +++ b/apps/rush-lib/src/logic/PublishUtilities.ts @@ -19,6 +19,7 @@ import { execSync } from 'child_process'; import { PrereleaseToken } from './PrereleaseToken'; import { ChangeFiles } from './ChangeFiles'; import { RushConfiguration } from '../api/RushConfiguration'; +import { DependencySpecifier } from './DependencySpecifier'; export interface IChangeInfoHash { [key: string]: IChangeInfo; @@ -220,9 +221,16 @@ export class PublishUtilities { dependencyName: string, newProjectVersion: string ): string { - const currentDependencyVersion: string = dependencies[dependencyName]; + const currentDependencySpecifier: DependencySpecifier = new DependencySpecifier( + dependencyName, + dependencies[dependencyName] + ); + const currentDependencyVersion: string = currentDependencySpecifier.versionSpecifier; let newDependencyVersion: string; - if (PublishUtilities.isRangeDependency(currentDependencyVersion)) { + + if (currentDependencyVersion === '*') { + newDependencyVersion = '*'; + } else if (PublishUtilities.isRangeDependency(currentDependencyVersion)) { newDependencyVersion = PublishUtilities._getNewRangeDependency(newProjectVersion); } else if (currentDependencyVersion.lastIndexOf('~', 0) === 0) { newDependencyVersion = '~' + newProjectVersion; @@ -231,7 +239,9 @@ export class PublishUtilities { } else { newDependencyVersion = newProjectVersion; } - return newDependencyVersion; + return currentDependencySpecifier.specifierType === 'workspace' + ? `workspace:${newDependencyVersion}` + : newDependencyVersion; } private static _getReleaseType(changeType: ChangeType): semver.ReleaseType { @@ -411,7 +421,13 @@ export class PublishUtilities { // TODO: treat prerelease version the same as non-prerelease version. // For prerelease, the newVersion needs to be appended with prerelease name. // And dependency should specify the specific prerelease version. - dependencies[depName] = PublishUtilities._getChangeInfoNewVersion(depChange, prereleaseToken); + const currentSpecifier: DependencySpecifier = new DependencySpecifier( + depName, + dependencies[depName] + ); + const newVersion: string = PublishUtilities._getChangeInfoNewVersion(depChange, prereleaseToken); + dependencies[depName] = + currentSpecifier.specifierType === 'workspace' ? `workspace:${newVersion}` : newVersion; } else if (depChange && depChange.changeType! >= ChangeType.hotfix) { PublishUtilities._updateDependencyVersion( packageName, @@ -615,7 +631,10 @@ export class PublishUtilities { dependencies[change.packageName] && !PublishUtilities._isCyclicDependency(allPackages, parentPackageName, change.packageName) ) { - const requiredVersion: string = dependencies[change.packageName]; + const requiredVersion: string = new DependencySpecifier( + change.packageName, + dependencies[change.packageName] + ).versionSpecifier; const alwaysUpdate: boolean = !!prereleaseToken && prereleaseToken.hasValue && !allChanges.hasOwnProperty(parentPackageName); @@ -670,13 +689,35 @@ export class PublishUtilities { allPackages: Map, rushConfiguration: RushConfiguration ): void { - const currentDependencyVersion: string = dependencies[dependencyName]; - - dependencies[dependencyName] = PublishUtilities.getNewDependencyVersion( + let currentDependencyVersion: string | undefined = dependencies[dependencyName]; + let newDependencyVersion: string = PublishUtilities.getNewDependencyVersion( dependencies, dependencyName, dependencyChange.newVersion! ); + dependencies[dependencyName] = newDependencyVersion; + + // "*" is a special case for workspace ranges, since it will publish using the exact + // version of the local dependency, so we need to modify what we write for our change + // comment + const currentDependencySpecifier: DependencySpecifier = new DependencySpecifier( + dependencyName, + currentDependencyVersion + ); + currentDependencyVersion = + currentDependencySpecifier.specifierType === 'workspace' && + currentDependencySpecifier.versionSpecifier === '*' + ? undefined + : currentDependencySpecifier.versionSpecifier; + + const newDependencySpecifier: DependencySpecifier = new DependencySpecifier( + dependencyName, + newDependencyVersion + ); + newDependencyVersion = + newDependencySpecifier.specifierType === 'workspace' && newDependencySpecifier.versionSpecifier === '*' + ? dependencyChange.newVersion! + : newDependencySpecifier.versionSpecifier; // Add dependency version update comment. PublishUtilities._addChange( @@ -684,8 +725,9 @@ export class PublishUtilities { packageName: packageName, changeType: ChangeType.dependency, comment: - `Updating dependency "${dependencyName}" from \`${currentDependencyVersion}\`` + - ` to \`${dependencies[dependencyName]}\`` + `Updating dependency "${dependencyName}" ` + + (currentDependencyVersion ? `from \`${currentDependencyVersion}\` ` : '') + + `to \`${newDependencyVersion}\`` }, allChanges, allPackages, diff --git a/apps/rush-lib/src/logic/test/ChangeManager.test.ts b/apps/rush-lib/src/logic/test/ChangeManager.test.ts index 77e9467fb86..c55398c6570 100644 --- a/apps/rush-lib/src/logic/test/ChangeManager.test.ts +++ b/apps/rush-lib/src/logic/test/ChangeManager.test.ts @@ -161,3 +161,172 @@ describe('ChangeManager', () => { }); /* eslint-enable dot-notation */ }); + +describe('WorkspaceChangeManager', () => { + const rushJsonFile: string = path.resolve(__dirname, 'workspacePackages', 'rush.json'); + let rushConfiguration: RushConfiguration; + let changeManager: ChangeManager; + + beforeEach(() => { + rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + changeManager = new ChangeManager(rushConfiguration); + }); + + /* eslint-disable dot-notation */ + it('can apply changes to the package.json files in the dictionary', () => { + changeManager.load(path.join(__dirname, 'multipleChanges')); + changeManager.apply(false); + + expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('2.0.0'); + expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.1'); + expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( + 'workspace:>=2.0.0 <3.0.0' + ); + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.0'); + expect(changeManager.allPackages.get('c')!.packageJson.dependencies!['b']).toEqual( + 'workspace:>=1.0.1 <2.0.0' + ); + }); + + it('can update explicit version dependency', () => { + changeManager.load(path.join(__dirname, 'explicitVersionChange')); + changeManager.apply(false); + + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.1'); + expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.1'); + expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual('workspace:1.0.1'); + }); + + it('can update explicit cyclic dependency', () => { + changeManager.load(path.join(__dirname, 'cyclicDepsExplicit')); + changeManager.apply(false); + + expect(changeManager.allPackages.get('cyclic-dep-explicit-1')!.packageJson.version).toEqual('2.0.0'); + expect( + changeManager.allPackages.get('cyclic-dep-explicit-1')!.packageJson.dependencies![ + 'cyclic-dep-explicit-2' + ] + ).toEqual('workspace:>=1.0.0 <2.0.0'); + expect(changeManager.allPackages.get('cyclic-dep-explicit-2')!.packageJson.version).toEqual('1.0.0'); + expect( + changeManager.allPackages.get('cyclic-dep-explicit-2')!.packageJson.dependencies![ + 'cyclic-dep-explicit-1' + ] + ).toEqual('>=1.0.0 <2.0.0'); + }); + + it('can update root with patch change for prerelease', () => { + const prereleaseName: string = 'alpha.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); + + changeManager.load(path.join(__dirname, 'rootPatchChange'), prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( + 'workspace:1.0.1-' + prereleaseName + ); + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual( + 'workspace:1.0.1-' + prereleaseName + ); + }); + + it('can update non-root with patch change for prerelease', () => { + const prereleaseName: string = 'beta.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); + + changeManager.load(path.join(__dirname, 'explicitVersionChange'), prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.0'); + expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.0'); + expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( + 'workspace:>=1.0.0 <2.0.0' + ); + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual( + 'workspace:1.0.1-' + prereleaseName + ); + }); + + it('can update cyclic dependency for non-explicit prerelease', () => { + const prereleaseName: string = 'beta.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); + + changeManager.load(path.join(__dirname, 'cyclicDeps'), prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.version).toEqual( + '2.0.0-' + prereleaseName + ); + expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.dependencies!['cyclic-dep-2']).toEqual( + 'workspace:1.0.1-' + prereleaseName + ); + expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.version).toEqual( + '1.0.1-' + prereleaseName + ); + expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.dependencies!['cyclic-dep-1']).toEqual( + 'workspace:2.0.0-' + prereleaseName + ); + }); + + it('can update root with patch change for adding version suffix', () => { + const suffix: string = 'dk.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); + + changeManager.load(path.join(__dirname, 'rootPatchChange'), prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( + 'workspace:1.0.0-' + suffix + ); + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual( + 'workspace:1.0.0-' + suffix + ); + }); + + it('can update non-root with patch change for version suffix', () => { + const suffix: string = 'dk.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); + + changeManager.load(path.join(__dirname, 'explicitVersionChange'), prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.0'); + expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.0'); + expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( + 'workspace:>=1.0.0 <2.0.0' + ); + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual( + 'workspace:1.0.0-' + suffix + ); + }); + + it('can update cyclic dependency for non-explicit suffix', () => { + const suffix: string = 'dk.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); + + changeManager.load(path.join(__dirname, 'cyclicDeps'), prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.dependencies!['cyclic-dep-2']).toEqual( + 'workspace:1.0.0-' + suffix + ); + expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.dependencies!['cyclic-dep-1']).toEqual( + 'workspace:1.0.0-' + suffix + ); + }); + /* eslint-enable dot-notation */ +}); diff --git a/apps/rush-lib/src/logic/test/VersionManager.test.ts b/apps/rush-lib/src/logic/test/VersionManager.test.ts index 3fde036e6a9..e0438bfb2a8 100644 --- a/apps/rush-lib/src/logic/test/VersionManager.test.ts +++ b/apps/rush-lib/src/logic/test/VersionManager.test.ts @@ -98,3 +98,84 @@ describe('VersionManager', () => { }); /* eslint-enable dot-notation */ }); + +describe('WorkspaceVersionManager', () => { + const rushJsonFile: string = path.resolve(__dirname, 'workspaceRepo', 'rush.json'); + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + let versionManager: VersionManager; + + beforeEach(() => { + versionManager = new VersionManager( + rushConfiguration, + 'test@microsoft.com', + rushConfiguration.versionPolicyConfiguration + ); + }); + + /* eslint-disable dot-notation */ + describe('ensure', () => { + it('fixes lock step versions', () => { + versionManager.ensure('testPolicy1'); + const updatedPackages: Map = versionManager.updatedProjects; + const expectedVersion: string = '10.10.0'; + expect(updatedPackages.size).toEqual(6); + expect(updatedPackages.get('a')!.version).toEqual(expectedVersion); + expect(updatedPackages.get('b')!.version).toEqual(expectedVersion); + expect(updatedPackages.get('b')!.dependencies!['a']).toEqual(`workspace:~${expectedVersion}`); + expect(updatedPackages.get('c')!.version).toEqual('3.1.1'); + expect(updatedPackages.get('c')!.dependencies!['b']).toEqual(`workspace:>=10.10.0 <11.0.0`); + expect(updatedPackages.get('d')!.version).toEqual('4.1.1'); + expect(updatedPackages.get('d')!.dependencies!['b']).toEqual(`workspace:>=10.10.0 <11.0.0`); + expect(updatedPackages.get('f')!.version).toEqual('1.0.0'); + expect(updatedPackages.get('f')!.dependencies!['a']).toEqual(`workspace:~10.10.0`); + expect(updatedPackages.get('g')!.devDependencies!['a']).toEqual(`workspace:~10.10.0`); + + const changeFiles: Map = versionManager.changeFiles; + expect(changeFiles.size).toEqual(4); + expect(_getChanges(changeFiles, 'a')!).toHaveLength(1); + expect(_getChanges(changeFiles, 'a')![0].changeType).toEqual(ChangeType.none); + expect(_getChanges(changeFiles, 'b')!).toHaveLength(1); + expect(_getChanges(changeFiles, 'b')![0].changeType).toEqual(ChangeType.none); + expect(_getChanges(changeFiles, 'c')!).toHaveLength(2); + expect(_getChanges(changeFiles, 'c')![0].changeType).toEqual(ChangeType.patch); + expect(_getChanges(changeFiles, 'c')![1].changeType).toEqual(ChangeType.dependency); + expect(_getChanges(changeFiles, 'd')!).toHaveLength(2); + expect(_getChanges(changeFiles, 'd')![0].changeType).toEqual(ChangeType.patch); + expect(_getChanges(changeFiles, 'd')![1].changeType).toEqual(ChangeType.dependency); + }); + + it('fixes major version for individual version policy', () => { + versionManager.ensure('testPolicy2'); + const updatedPackages: Map = versionManager.updatedProjects; + expect(updatedPackages.size).toEqual(2); + expect(updatedPackages.get('c')!.version).toEqual('5.0.0'); + expect(updatedPackages.get('c')!.dependencies!['b']).toEqual(`workspace:>=2.0.0 <3.0.0`); + expect(updatedPackages.get('e')!.version).toEqual('10.10.0'); + expect(updatedPackages.get('e')!.dependencies!['c']).toEqual('workspace:~5.0.0'); + }); + + it('does not change packageJson if not needed by individual version policy', () => { + versionManager.ensure('testPolicy3'); + const updatedPackages: Map = versionManager.updatedProjects; + expect(updatedPackages.size).toEqual(0); + }); + }); + + describe('bump', () => { + it('bumps to prerelease version', () => { + versionManager.bump('testPolicy1', BumpType.prerelease, 'dev', false); + const updatedPackages: Map = versionManager.updatedProjects; + const expectedVersion: string = '10.10.1-dev.0'; + + const changeFiles: Map = versionManager.changeFiles; + + expect(updatedPackages.get('a')!.version).toEqual(expectedVersion); + expect(updatedPackages.get('b')!.version).toEqual(expectedVersion); + expect(updatedPackages.get('e')!.version).toEqual(expectedVersion); + expect(updatedPackages.get('g')!.devDependencies!['a']).toEqual(`workspace:~${expectedVersion}`); + expect(_getChanges(changeFiles, 'a')).not.toBeDefined(); + expect(_getChanges(changeFiles, 'b')).not.toBeDefined(); + }); + }); + /* eslint-enable dot-notation */ +}); From f73c79dd2aff7d0554ce971273a591ebc36bc558 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Wed, 24 Jun 2020 12:34:20 -0700 Subject: [PATCH 09/33] Make pnpmfile shim workspace-only --- apps/rush-lib/src/api/RushConfiguration.ts | 19 --- .../src/logic/base/BaseInstallManager.ts | 116 +----------------- .../installManager/WorkspaceInstallManager.ts | 116 +++++++++++++++++- .../src/logic/pnpm/PnpmWorkspaceFile.ts | 8 +- apps/rush-lib/src/schemas/rush.schema.json | 4 - 5 files changed, 118 insertions(+), 145 deletions(-) diff --git a/apps/rush-lib/src/api/RushConfiguration.ts b/apps/rush-lib/src/api/RushConfiguration.ts index 80ff3b041b4..0338bb6c108 100644 --- a/apps/rush-lib/src/api/RushConfiguration.ts +++ b/apps/rush-lib/src/api/RushConfiguration.ts @@ -172,10 +172,6 @@ export interface IPnpmOptionsJson extends IPackageManagerOptionsJsonBase { * {@inheritDoc PnpmOptionsConfiguration.useWorkspaces} */ useWorkspaces?: boolean; - /** - * {@inheritDoc PnpmOptionsConfiguration.useShimPnpmfile} - */ - useShimPnpmfile?: boolean; } /** @@ -362,20 +358,6 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration */ public readonly useWorkspaces: boolean; - /** - * If true, then Rush will create a pnpmfile that runs before the provided pnpmfile. This shim - * pnpmfile is used to inject preferred versions support into the PNPM package resolver. - * - * @remarks - * Preferred versions are supported using pnpmfile by substituting any dependency version specifier - * for the preferred version during package resolution. This is only done if the preferred version range - * is a subset of the dependency version range. Allowed alternate versions are not modified. The pnpmfile - * shim will subsequently call into the provided pnpmfile, if one exists. - * - * The default value is false. (For now.) - */ - public readonly useShimPnpmfile: boolean; - /** @internal */ public constructor(json: IPnpmOptionsJson, commonTempFolder: string) { super(json); @@ -391,7 +373,6 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration this.resolutionStrategy = json.resolutionStrategy || 'fewer-dependencies'; this.preventManualShrinkwrapChanges = !!json.preventManualShrinkwrapChanges; this.useWorkspaces = !!json.useWorkspaces; - this.useShimPnpmfile = !!json.useShimPnpmfile; } } diff --git a/apps/rush-lib/src/logic/base/BaseInstallManager.ts b/apps/rush-lib/src/logic/base/BaseInstallManager.ts index 610ab2df85b..05181d54923 100644 --- a/apps/rush-lib/src/logic/base/BaseInstallManager.ts +++ b/apps/rush-lib/src/logic/base/BaseInstallManager.ts @@ -9,14 +9,7 @@ import HttpsProxyAgent = require('https-proxy-agent'); import * as os from 'os'; import * as path from 'path'; import * as semver from 'semver'; -import { - FileSystem, - JsonFile, - JsonObject, - MapExtensions, - PosixModeBits, - NewlineKind -} from '@rushstack/node-core-library'; +import { FileSystem, JsonFile, JsonObject, PosixModeBits, NewlineKind } from '@rushstack/node-core-library'; import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; import { ApprovedPackagesChecker } from '../ApprovedPackagesChecker'; @@ -363,16 +356,6 @@ export abstract class BaseInstallManager { // ensure that we remove any old one that may be hanging around Utilities.syncFile(committedPnpmFilePath, tempPnpmFilePath); - - // shim support for common versions resolution into the pnpmfile. We want to ensure that it is enabled - // when requested or when using workspaces, since workspaces support preferred versions differently - if ( - this.rushConfiguration.pnpmOptions && - (this.rushConfiguration.pnpmOptions.useShimPnpmfile || - this.rushConfiguration.pnpmOptions.useWorkspaces) - ) { - await this.createShimPnpmfile(tempPnpmFilePath); - } } // Allow for package managers to do their own preparation and check that the shrinkwrap is up to date @@ -520,103 +503,6 @@ export abstract class BaseInstallManager { } } - protected async createShimPnpmfile(filename: string): Promise { - // Get the versions we want to add to the shim pnpmfile - const allPreferredVersions: Map = InstallHelpers.collectPreferredVersions( - this.rushConfiguration, - this.options - ); - const allowedAlternativeVersions: Map< - string, - ReadonlyArray - > = this.rushConfiguration.getCommonVersions(this.options.variant).allowedAlternativeVersions; - - const clientPnpmfileName: string = 'clientPnpmfile.js'; - const pnpmfileContent: string[] = [ - '// THIS IS A GENERATED FILE. DO NOT MODIFY.', - '"use strict";', - 'module.exports = { hooks: { readPackage, afterAllResolved } };', - - // Obtain the original pnpmfile provided by the repo, if it exists. - 'const { existsSync } = require("fs");', - 'const clientPnpmfile = ', - ` existsSync("${clientPnpmfileName}") ? require("./${path.basename( - clientPnpmfileName, - '.js' - )}") : undefined;`, - // We will require semver from this path on disk, since this is the version of semver shipping with Rush - `const semver = require(${JSON.stringify(require.resolve('semver'))});`, - - // Include all the preferredVersions and allowedAlternativeVersions directly since there is no need to - // generate them on the fly - `const allPreferredVersions = ${JSON.stringify(MapExtensions.toObject(allPreferredVersions))};`, - `const allowedAlternativeVersions = ${JSON.stringify( - MapExtensions.toObject(allowedAlternativeVersions) - )};`, - - // Call the original pnpmfile (if it exists) - 'function afterAllResolved(lockfile, context) {', - ' return (clientPnpmfile && clientPnpmfile.hooks && clientPnpmfile.hooks.afterAllResolved)', - ' ? clientPnpmfile.hooks.afterAllResolved(lockfile, context)', - ' : lockfile;', - '}', - - // Set the preferred versions in the package, then call the original pnpmfile (if it exists) - 'function readPackage(pkg, context) {', - ' setPreferredVersions(pkg.dependencies);', - ' setPreferredVersions(pkg.devDependencies);', - ' setPreferredVersions(pkg.optionalDependencies);', - ' return (clientPnpmfile && clientPnpmfile.hooks && clientPnpmfile.hooks.readPackage)', - ' ? clientPnpmfile.hooks.readPackage(pkg, context)', - ' : pkg;', - '}', - - // Set the preferred versions on the dependency map. If the version on the map is an allowedAlternativeVersion - // then skip it. Otherwise, check to ensure that the common version is a subset of the specified version. If - // it is, then replace the specified version with the preferredVersion - 'function setPreferredVersions(dependencies) {', - ' for (const name of Object.keys(dependencies || {})) {', - ' if (allPreferredVersions.hasOwnProperty(name)) {', - ' const preferredVersion = allPreferredVersions[name];', - ' const version = dependencies[name];', - ' if (allowedAlternativeVersions.hasOwnProperty(name)) {', - ' const allowedAlternatives = allowedAlternativeVersions[name];', - ' if (allowedAlternatives && allowedAlternatives.indexOf(version) > -1) {', - ' continue;', - ' }', - ' }', - ' let isValidRange = false;', - ' try {', - ' isValidRange = !!semver.validRange(preferredVersion) && !!semver.validRange(version);', - ' } catch {', - ' }', - ' if (isValidRange && semver.subset(preferredVersion, version)) {', - ' dependencies[name] = preferredVersion;', - ' }', - ' }', - ' }', - '}' - ]; - - // Attempt to move the existing pnpmfile if there is one - try { - const pnpmfileDir: string = path.dirname(filename); - await FileSystem.moveAsync({ - sourcePath: filename, - destinationPath: path.join(pnpmfileDir, clientPnpmfileName) - }); - } catch (error) { - if (!FileSystem.isNotExistError(error)) { - throw error; - } - } - - // Write the shim pnpmfile to the original file path - await FileSystem.writeFileAsync(filename, pnpmfileContent.join(NewlineKind.Lf), { - ensureFolderExists: true - }); - } - private _checkIfReleaseIsPublished(): Promise { return Promise.resolve().then(() => { const lastCheckFile: string = path.join( diff --git a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts index 5a168e208b7..4f7963fb3e6 100644 --- a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -5,7 +5,7 @@ import * as colors from 'colors'; import * as os from 'os'; import * as path from 'path'; import * as semver from 'semver'; -import { FileSystem, InternalError } from '@rushstack/node-core-library'; +import { FileSystem, InternalError, MapExtensions, NewlineKind } from '@rushstack/node-core-library'; import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; import { BaseInstallManager, IInstallManagerOptions } from '../base/BaseInstallManager'; @@ -69,6 +69,17 @@ export class WorkspaceInstallManager extends BaseInstallManager { os.EOL + colors.bold('Updating workspace files in ' + this.rushConfiguration.commonTempFolder) ); + // Shim support for common versions resolution into the pnpmfile. When using workspaces, there are no + // "hoisted" packages, so we need to apply the correct versions to indirect dependencies through the + // pnpmfile. + if (this.rushConfiguration.packageManager === 'pnpm') { + const tempPnpmFilePath: string = path.join( + this.rushConfiguration.commonTempFolder, + RushConstants.pnpmfileFilename + ); + await this.createShimPnpmfile(tempPnpmFilePath); + } + const shrinkwrapWarnings: string[] = []; // We will start with the assumption that it's valid, and then set it to false if @@ -421,6 +432,109 @@ export class WorkspaceInstallManager extends BaseInstallManager { console.log(''); } + /** + * Preferred versions are supported using pnpmfile by substituting any dependency version specifier + * for the preferred version during package resolution. This is only done if the preferred version range + * is a subset of the dependency version range. Allowed alternate versions are not modified. The pnpmfile + * shim will subsequently call into the provided pnpmfile, if one exists. + */ + protected async createShimPnpmfile(filename: string): Promise { + // Get the versions we want to add to the shim pnpmfile + const allPreferredVersions: Map = InstallHelpers.collectPreferredVersions( + this.rushConfiguration, + this.options + ); + const allowedAlternativeVersions: Map< + string, + ReadonlyArray + > = this.rushConfiguration.getCommonVersions(this.options.variant).allowedAlternativeVersions; + + const clientPnpmfileName: string = 'clientPnpmfile.js'; + const pnpmfileContent: string[] = [ + '// THIS IS A GENERATED FILE. DO NOT MODIFY.', + '"use strict";', + 'module.exports = { hooks: { readPackage, afterAllResolved } };', + + // Obtain the original pnpmfile provided by the repo, if it exists. + 'const { existsSync } = require("fs");', + 'const clientPnpmfile = ', + ` existsSync("${clientPnpmfileName}") ? require("./${path.basename( + clientPnpmfileName, + '.js' + )}") : undefined;`, + // We will require semver from this path on disk, since this is the version of semver shipping with Rush + `const semver = require(${JSON.stringify(require.resolve('semver'))});`, + + // Include all the preferredVersions and allowedAlternativeVersions directly since there is no need to + // generate them on the fly + `const allPreferredVersions = ${JSON.stringify(MapExtensions.toObject(allPreferredVersions))};`, + `const allowedAlternativeVersions = ${JSON.stringify( + MapExtensions.toObject(allowedAlternativeVersions) + )};`, + + // Call the original pnpmfile (if it exists) + 'function afterAllResolved(lockfile, context) {', + ' return (clientPnpmfile && clientPnpmfile.hooks && clientPnpmfile.hooks.afterAllResolved)', + ' ? clientPnpmfile.hooks.afterAllResolved(lockfile, context)', + ' : lockfile;', + '}', + + // Set the preferred versions in the package, then call the original pnpmfile (if it exists) + 'function readPackage(pkg, context) {', + ' setPreferredVersions(pkg.dependencies);', + ' setPreferredVersions(pkg.devDependencies);', + ' setPreferredVersions(pkg.optionalDependencies);', + ' return (clientPnpmfile && clientPnpmfile.hooks && clientPnpmfile.hooks.readPackage)', + ' ? clientPnpmfile.hooks.readPackage(pkg, context)', + ' : pkg;', + '}', + + // Set the preferred versions on the dependency map. If the version on the map is an allowedAlternativeVersion + // then skip it. Otherwise, check to ensure that the common version is a subset of the specified version. If + // it is, then replace the specified version with the preferredVersion + 'function setPreferredVersions(dependencies) {', + ' for (const name of Object.keys(dependencies || {})) {', + ' if (allPreferredVersions.hasOwnProperty(name)) {', + ' const preferredVersion = allPreferredVersions[name];', + ' const version = dependencies[name];', + ' if (allowedAlternativeVersions.hasOwnProperty(name)) {', + ' const allowedAlternatives = allowedAlternativeVersions[name];', + ' if (allowedAlternatives && allowedAlternatives.indexOf(version) > -1) {', + ' continue;', + ' }', + ' }', + ' let isValidRange = false;', + ' try {', + ' isValidRange = !!semver.validRange(preferredVersion) && !!semver.validRange(version);', + ' } catch {', + ' }', + ' if (isValidRange && semver.subset(preferredVersion, version)) {', + ' dependencies[name] = preferredVersion;', + ' }', + ' }', + ' }', + '}' + ]; + + // Attempt to move the existing pnpmfile if there is one + try { + const pnpmfileDir: string = path.dirname(filename); + await FileSystem.moveAsync({ + sourcePath: filename, + destinationPath: path.join(pnpmfileDir, clientPnpmfileName) + }); + } catch (error) { + if (!FileSystem.isNotExistError(error)) { + throw error; + } + } + + // Write the shim pnpmfile to the original file path + await FileSystem.writeFileAsync(filename, pnpmfileContent.join(NewlineKind.Lf), { + ensureFolderExists: true + }); + } + /** * Used when invoking the NPM tool. Appends the common configuration options * to the command-line. diff --git a/apps/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts b/apps/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts index 40909bd8d9f..dd3618a549c 100644 --- a/apps/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts +++ b/apps/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts @@ -41,12 +41,8 @@ export class PnpmWorkspaceFile extends BaseWorkspaceFile { private _workspacePackages: Set; /** - * - @halfnibble -halfnibble 5 days ago Member -Empty comment. - -@D4N14L Reply… + * The PNPM workspace file is used to specify the location of workspaces relative to the root + * of your PNPM install. */ public constructor(workspaceYamlFilename: string) { super(); diff --git a/apps/rush-lib/src/schemas/rush.schema.json b/apps/rush-lib/src/schemas/rush.schema.json index e14e301826f..800142df43d 100644 --- a/apps/rush-lib/src/schemas/rush.schema.json +++ b/apps/rush-lib/src/schemas/rush.schema.json @@ -110,10 +110,6 @@ "useWorkspaces": { "description": "If true, then Rush will use the workspaces feature to install and link packages when invoking PNPM. The default value is false.", "type": "boolean" - }, - "useShimPnpmfile": { - "description": "If true, then Rush will create a pnpmfile that runs before the provided pnpmfile. This shim pnpmfile is used to inject preferred versions support into the PNPM package resolver. The default value is false.", - "type": "boolean" } }, "additionalProperties": false From 85885a72924737e3e7b627941ce2c12b816a3b51 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Wed, 24 Jun 2020 12:35:38 -0700 Subject: [PATCH 10/33] Allow exact ranges to be used for workspace range conversion --- .../logic/installManager/WorkspaceInstallManager.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts index 4f7963fb3e6..48284aa4b58 100644 --- a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -199,8 +199,14 @@ export class WorkspaceInstallManager extends BaseInstallManager { throw new AlreadyReportedError(); } - // We will update to `workspace:*` by default to ensure we're always using the workspace package. - packageJson.addOrUpdateDependency(name, 'workspace:*', dependencyType); + // We will update to `workspace` notation. If the version specified is a range, then use the provided range. + // Otherwise, use `workspace:*` to ensure we're always using the workspace package. + const workspaceRange: string = + !!semver.validRange(dependencySpecifier.versionSpecifier) && + !semver.valid(dependencySpecifier.versionSpecifier) + ? dependencySpecifier.versionSpecifier + : '*'; + packageJson.addOrUpdateDependency(name, `workspace:${workspaceRange}`, dependencyType); shrinkwrapIsUpToDate = false; continue; } else if (dependencySpecifier.specifierType === 'workspace') { From debf80f50b352aafa503af701a27172995631f51 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Wed, 24 Jun 2020 14:49:51 -0700 Subject: [PATCH 11/33] Add repo-state.json to be used by workspaces to validate common versions --- .../src/api/CommonVersionsConfiguration.ts | 16 +++- apps/rush-lib/src/api/RepoStateFile.ts | 91 +++++++++++++++++++ apps/rush-lib/src/api/RushConfiguration.ts | 24 +++++ apps/rush-lib/src/logic/RushConstants.ts | 6 ++ .../logic/installManager/InstallHelpers.ts | 2 +- .../installManager/WorkspaceInstallManager.ts | 64 ++++++------- .../src/schemas/repo-state.schema.json | 18 ++++ common/reviews/api/rush-lib.api.md | 6 +- 8 files changed, 189 insertions(+), 38 deletions(-) create mode 100644 apps/rush-lib/src/api/RepoStateFile.ts create mode 100644 apps/rush-lib/src/schemas/repo-state.schema.json diff --git a/apps/rush-lib/src/api/CommonVersionsConfiguration.ts b/apps/rush-lib/src/api/CommonVersionsConfiguration.ts index 674db10321b..f0887e91fb9 100644 --- a/apps/rush-lib/src/api/CommonVersionsConfiguration.ts +++ b/apps/rush-lib/src/api/CommonVersionsConfiguration.ts @@ -1,13 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import * as crypto from 'crypto'; import * as path from 'path'; import { JsonFile, JsonSchema, MapExtensions, ProtectableMap, - FileSystem + FileSystem, + Sort } from '@rushstack/node-core-library'; import { PackageNameParsers } from './PackageNameParsers'; import { JsonSchemaUrls } from '../logic/JsonSchemaUrls'; @@ -148,6 +150,18 @@ export class CommonVersionsConfiguration { return this._filePath; } + /** + * Get a sha1 hash of the preferred versions. + */ + public get preferredVersionsHash(): string { + // Sort so that the hash is stable + const preferredVersionsToHash: Map = new Map( + this._preferredVersions.protectedView + ); + Sort.sortMapKeys(preferredVersionsToHash); + return crypto.createHash('sha1').update(JSON.stringify(preferredVersionsToHash)).digest('hex'); + } + /** * Writes the "common-versions.json" file to disk, using the filename that was passed to loadFromFile(). */ diff --git a/apps/rush-lib/src/api/RepoStateFile.ts b/apps/rush-lib/src/api/RepoStateFile.ts new file mode 100644 index 00000000000..3982a2cd201 --- /dev/null +++ b/apps/rush-lib/src/api/RepoStateFile.ts @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'path'; +import { FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; + +/** + * This interface represents the raw pnpm-workspace.YAML file + * Example: + * { + * "preferredVersionsHash": "..." + * } + */ +interface IRepoStateJson { + /** A hash of the CommonVersionsConfiguration.preferredVersions field */ + preferredVersionsHash?: string; +} + +/** + * Th + */ +export class RepoStateFile { + private static _jsonSchema: JsonSchema = JsonSchema.fromFile( + path.join(__dirname, '../schemas/repo-state.schema.json') + ); + private _repoStateFilePath: string; + private _preferredVersionsHash: string | undefined; + private _modified: boolean = false; + + private constructor(repoStateJson: IRepoStateJson | undefined, filePath: string) { + this._repoStateFilePath = filePath; + + if (repoStateJson) { + this._preferredVersionsHash = repoStateJson.preferredVersionsHash; + } + } + + /** + * Get the absolute file path of the repo-state.json file. + */ + public get filePath(): string { + return this._repoStateFilePath; + } + + /** + * The hash of all preferred versions at the end of the last update. + */ + public get preferredVersionsHash(): string | undefined { + return this._preferredVersionsHash; + } + + public set preferredVersionsHash(hash: string | undefined) { + if (this._preferredVersionsHash !== hash) { + this._preferredVersionsHash = hash; + this._modified = true; + } + } + + /** + * Loads the repo-state.json data from the specified file path. + * If the file has not been created yet, then an empty object is returned. + */ + public static loadFromFile(jsonFilename: string): RepoStateFile { + let repoStateJson: IRepoStateJson | undefined = undefined; + + if (FileSystem.exists(jsonFilename)) { + repoStateJson = JsonFile.loadAndValidate(jsonFilename, RepoStateFile._jsonSchema); + } + return new RepoStateFile(repoStateJson, jsonFilename); + } + + /** + * Writes the "repo-state.json" file to disk, using the filename that was passed to loadFromFile(). + */ + public saveIfModified(): boolean { + if (this._modified) { + JsonFile.save(this._serialize(), this._repoStateFilePath, { updateExistingFile: true }); + this._modified = false; + return true; + } + + return false; + } + + private _serialize(): IRepoStateJson { + const repoStateJson: IRepoStateJson = { + preferredVersionsHash: this.preferredVersionsHash + }; + return repoStateJson; + } +} diff --git a/apps/rush-lib/src/api/RushConfiguration.ts b/apps/rush-lib/src/api/RushConfiguration.ts index 0338bb6c108..1188f922e39 100644 --- a/apps/rush-lib/src/api/RushConfiguration.ts +++ b/apps/rush-lib/src/api/RushConfiguration.ts @@ -24,6 +24,7 @@ import { YarnPackageManager } from './packageManager/YarnPackageManager'; import { PnpmPackageManager } from './packageManager/PnpmPackageManager'; import { ExperimentsConfiguration } from './ExperimentsConfiguration'; import { PackageNameParsers } from './PackageNameParsers'; +import { RepoStateFile } from './RepoStateFile'; const MINIMUM_SUPPORTED_RUSH_JSON_VERSION: string = '0.0.0'; const DEFAULT_BRANCH: string = 'master'; @@ -38,6 +39,7 @@ const knownRushConfigFilenames: string[] = [ '.npmrc-publish', RushConstants.pinnedVersionsFilename, RushConstants.commonVersionsFilename, + RushConstants.repoStateFilename, RushConstants.browserApprovedPackagesFilename, RushConstants.nonbrowserApprovedPackagesFilename, RushConstants.versionPoliciesFilename, @@ -1438,6 +1440,28 @@ export class RushConfiguration { return CommonVersionsConfiguration.loadFromFile(commonVersionsFilename); } + /** + * Gets the path to the repo-state.json file for a specific variant. + * @param variant - The name of the current variant in use by the active command. + */ + public getRepoStateFilePath(variant?: string | undefined): string { + const repoStateFilename: string = path.join( + this.commonRushConfigFolder, + ...(variant ? [RushConstants.rushVariantsFolderName, variant] : []), + RushConstants.repoStateFilename + ); + return repoStateFilename; + } + + /** + * Gets the contents from the repo-state.json file for a specific variant. + * @param variant - The name of the current variant in use by the active command. + */ + public getRepoState(variant?: string | undefined): RepoStateFile { + const repoStateFilename: string = this.getRepoStateFilePath(variant); + return RepoStateFile.loadFromFile(repoStateFilename); + } + /** * Gets the committed shrinkwrap file name for a specific variant. * @param variant - The name of the current variant in use by the active command. diff --git a/apps/rush-lib/src/logic/RushConstants.ts b/apps/rush-lib/src/logic/RushConstants.ts index 983511d0848..b3c05bf6b29 100644 --- a/apps/rush-lib/src/logic/RushConstants.ts +++ b/apps/rush-lib/src/logic/RushConstants.ts @@ -119,6 +119,12 @@ export class RushConstants { */ public static readonly commonVersionsFilename: string = 'common-versions.json'; + /** + * The filename ("repo-state.json") for a file used by Rush to + * store the state of various features as they stand in the repo. + */ + public static readonly repoStateFilename: string = 'repo-state.json'; + /** * The name of the per-project folder where project-specific Rush files are stored. For example, * the package-deps files, which are used by commands to determine if a particular project needs to be rebuilt. diff --git a/apps/rush-lib/src/logic/installManager/InstallHelpers.ts b/apps/rush-lib/src/logic/installManager/InstallHelpers.ts index 102c5dcf19f..2551d489bf9 100644 --- a/apps/rush-lib/src/logic/installManager/InstallHelpers.ts +++ b/apps/rush-lib/src/logic/installManager/InstallHelpers.ts @@ -115,7 +115,7 @@ export class InstallHelpers { public static generateCommonPackageJson( rushConfiguration: RushConfiguration, - dependencies: Map + dependencies: Map = new Map() ): void { const commonPackageJson: IPackageJson = { dependencies: {}, diff --git a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts index 48284aa4b58..1226bdc8e28 100644 --- a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -19,6 +19,8 @@ import { RushConstants } from '../../logic/RushConstants'; import { Stopwatch } from '../../utilities/Stopwatch'; import { Utilities } from '../../utilities/Utilities'; import { InstallHelpers } from './InstallHelpers'; +import { CommonVersionsConfiguration } from '../../api/CommonVersionsConfiguration'; +import { RepoStateFile } from '../../api/RepoStateFile'; /** * This class implements common logic between "rush install" and "rush update". @@ -105,32 +107,7 @@ export class WorkspaceInstallManager extends BaseInstallManager { } } - // dependency name --> version specifier - const allExplicitPreferredVersions: Map = this.rushConfiguration - .getCommonVersions(this.options.variant) - .getAllPreferredVersions(); - if (shrinkwrapFile) { - // Check any (explicitly) preferred dependencies first - allExplicitPreferredVersions.forEach((version: string, dependency: string) => { - const dependencySpecifier: DependencySpecifier = new DependencySpecifier(dependency, version); - - // The common package.json is used to ensure common versions are installed, so look for this workspace - // and validate that the requested dependency is specified - if ( - !shrinkwrapFile.hasCompatibleWorkspaceDependency( - dependencySpecifier, - WorkspaceInstallManager.getCommonWorkspaceKey(this.rushConfiguration) - ) - ) { - shrinkwrapWarnings.push( - `Missing dependency "${dependency}" (${version}) required by the preferred versions from ` + - RushConstants.commonVersionsFilename - ); - shrinkwrapIsUpToDate = false; - } - }); - if (this._findOrphanedWorkspaceProjects(shrinkwrapFile)) { // If there are any orphaned projects, then install would fail because the shrinkwrap // contains references that refer to nonexistent file paths. @@ -138,6 +115,18 @@ export class WorkspaceInstallManager extends BaseInstallManager { } } + // If preferred versions have been updated, then we can't be certain of the state of the shrinkwrap + const repoState: RepoStateFile = this.rushConfiguration.getRepoState(this.options.variant); + const commonVersions: CommonVersionsConfiguration = this.rushConfiguration.getCommonVersions( + this.options.variant + ); + if (repoState.preferredVersionsHash !== commonVersions.preferredVersionsHash) { + shrinkwrapWarnings.push( + `Preferred versions from ${RushConstants.commonVersionsFilename} have been modified.` + ); + shrinkwrapIsUpToDate = false; + } + // To generate the workspace file, we will add each project to the file as we loop through and validate const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile( path.join(this.rushConfiguration.commonTempFolder, 'pnpm-workspace.yaml') @@ -249,16 +238,8 @@ export class WorkspaceInstallManager extends BaseInstallManager { } } - const allPreferredVersions: Map = InstallHelpers.collectPreferredVersions( - this.rushConfiguration, - { - explicitPreferredVersions: allExplicitPreferredVersions, - variant: this.options.variant - } - ); - // Write the common package.json - InstallHelpers.generateCommonPackageJson(this.rushConfiguration, allPreferredVersions); + InstallHelpers.generateCommonPackageJson(this.rushConfiguration); // Save the generated workspace file. Don't update the file timestamp unless the content has changed, // since "rush install" will consider this timestamp @@ -436,6 +417,21 @@ export class WorkspaceInstallManager extends BaseInstallManager { } console.log(''); + + // We need to update the repo state with the information from the install + const repoState: RepoStateFile = this.rushConfiguration.getRepoState(this.options.variant); + const commonVersions: CommonVersionsConfiguration = this.rushConfiguration.getCommonVersions( + this.options.variant + ); + repoState.preferredVersionsHash = commonVersions.preferredVersionsHash; + if (repoState.saveIfModified()) { + console.log( + colors.yellow( + `${RushConstants.repoStateFilename} has been modified and must be committed to source control.` + ) + ); + console.log(''); + } } /** diff --git a/apps/rush-lib/src/schemas/repo-state.schema.json b/apps/rush-lib/src/schemas/repo-state.schema.json new file mode 100644 index 00000000000..9bfb102ac97 --- /dev/null +++ b/apps/rush-lib/src/schemas/repo-state.schema.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Rush repo-state.json file", + "description": "For use with the Rush tool, this file tracks the state of various features in the Rush repo. See http://rushjs.io for details.", + + "type": "object", + "properties": { + "$schema": { + "description": "Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.", + "type": "string" + }, + "preferredVersionsHash": { + "description": "A hash of \"preferred versions\" for the repository. This hash is used to determine whether or not preferred versions have been modified prior to install.", + "type": "string" + } + }, + "additionalProperties": false +} diff --git a/common/reviews/api/rush-lib.api.md b/common/reviews/api/rush-lib.api.md index 418985d3bd3..5ff693226e3 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -71,6 +71,7 @@ export class CommonVersionsConfiguration { readonly implicitlyPreferredVersions: boolean | undefined; static loadFromFile(jsonFilename: string): CommonVersionsConfiguration; readonly preferredVersions: Map; + readonly preferredVersionsHash: string; save(): boolean; readonly xstitchPreferredVersions: Map; } @@ -176,7 +177,6 @@ export interface _IPnpmOptionsJson extends IPackageManagerOptionsJsonBase { preventManualShrinkwrapChanges?: boolean; resolutionStrategy?: ResolutionStrategy; strictPeerDependencies?: boolean; - useShimPnpmfile?: boolean; useWorkspaces?: boolean; } @@ -291,7 +291,6 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration readonly preventManualShrinkwrapChanges: boolean; readonly resolutionStrategy: ResolutionStrategy; readonly strictPeerDependencies: boolean; - readonly useShimPnpmfile: boolean; readonly useWorkspaces: boolean; } @@ -335,6 +334,9 @@ export class RushConfiguration { getCommonVersionsFilePath(variant?: string | undefined): string; getPnpmfilePath(variant?: string | undefined): string; getProjectByName(projectName: string): RushConfigurationProject | undefined; + // Warning: (ae-forgotten-export) The symbol "RepoStateFile" needs to be exported by the entry point index.d.ts + getRepoState(variant?: string | undefined): RepoStateFile; + getRepoStateFilePath(variant?: string | undefined): string; readonly gitAllowedEmailRegExps: string[]; readonly gitSampleEmail: string; readonly gitVersionBumpCommitMessage: string | undefined; From 9b738c87094b4dd3a92dfb381f5cde2254388dd0 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Wed, 24 Jun 2020 15:53:05 -0700 Subject: [PATCH 12/33] Rush update --- common/config/rush/pnpm-lock.yaml | 795 +++++++++++++++++++++++++----- 1 file changed, 666 insertions(+), 129 deletions(-) diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 33912f0bbef..16df155e6d0 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -3,6 +3,7 @@ dependencies: '@jest/reporters': 25.4.0 '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 + '@microsoft/rush-stack-compiler-3.9': 0.2.1 '@microsoft/teams-js': 1.3.0-beta.4 '@microsoft/tsdoc': 0.12.19 '@pnpm/link-bins': 5.1.7 @@ -21,6 +22,7 @@ dependencies: '@rush-temp/debug-certificate-manager': 'file:projects/debug-certificate-manager.tgz' '@rush-temp/doc-plugin-rush-stack': 'file:projects/doc-plugin-rush-stack.tgz' '@rush-temp/eslint-config': 'file:projects/eslint-config.tgz' + '@rush-temp/eslint-patch': 'file:projects/eslint-patch.tgz' '@rush-temp/eslint-plugin': 'file:projects/eslint-plugin.tgz' '@rush-temp/generate-api-docs': 'file:projects/generate-api-docs.tgz' '@rush-temp/gulp-core-build': 'file:projects/gulp-core-build.tgz' @@ -29,6 +31,7 @@ dependencies: '@rush-temp/gulp-core-build-serve': 'file:projects/gulp-core-build-serve.tgz' '@rush-temp/gulp-core-build-typescript': 'file:projects/gulp-core-build-typescript.tgz' '@rush-temp/gulp-core-build-webpack': 'file:projects/gulp-core-build-webpack.tgz' + '@rush-temp/heft': 'file:projects/heft.tgz' '@rush-temp/load-themed-styles': 'file:projects/load-themed-styles.tgz' '@rush-temp/loader-load-themed-styles': 'file:projects/loader-load-themed-styles.tgz' '@rush-temp/loader-raw-script': 'file:projects/loader-raw-script.tgz' @@ -86,8 +89,8 @@ dependencies: '@types/autoprefixer': 9.7.2 '@types/chalk': 0.4.31 '@types/clean-css': 4.2.1 - '@types/eslint': 6.1.3 - '@types/estree': 0.0.39 + '@types/eslint': 7.2.0 + '@types/estree': 0.0.44 '@types/express': 4.11.0 '@types/express-serve-static-core': 4.11.0 '@types/fs-extra': 7.0.0 @@ -120,7 +123,7 @@ dependencies: '@types/sinon': 1.16.34 '@types/source-map': 0.5.0 '@types/strict-uri-encode': 2.0.0 - '@types/tapable': 1.0.4 + '@types/tapable': 1.0.5 '@types/tar': 4.0.3 '@types/through2': 2.0.32 '@types/timsort': 0.3.0 @@ -133,10 +136,10 @@ dependencies: '@types/xmldoc': 1.1.4 '@types/yargs': 0.0.34 '@types/z-schema': 3.16.31 - '@typescript-eslint/eslint-plugin': 2.3.3_5b3b7d3a75edb27abc53579646941536 - '@typescript-eslint/experimental-utils': 2.3.3_eslint@6.5.1 - '@typescript-eslint/parser': 2.3.3_eslint@6.5.1 - '@typescript-eslint/typescript-estree': 2.3.3 + '@typescript-eslint/eslint-plugin': 3.3.0_5230966e5e0a36b5cf15b6a6401aaf8c + '@typescript-eslint/experimental-utils': 3.3.0_eslint@7.2.0+typescript@3.5.3 + '@typescript-eslint/parser': 3.3.0_eslint@7.2.0+typescript@3.5.3 + '@typescript-eslint/typescript-estree': 3.3.0_typescript@3.5.3 '@yarnpkg/lockfile': 1.0.2 argparse: 1.0.10 autoprefixer: 9.8.0 @@ -151,9 +154,9 @@ dependencies: decomment: 0.9.2 del: 2.2.2 end-of-stream: 1.1.0 - eslint: 6.5.1 + eslint: 7.2.0 eslint-plugin-promise: 4.2.1 - eslint-plugin-react: 7.16.0_eslint@6.5.1 + eslint-plugin-react: 7.20.0_eslint@7.2.0 eslint-plugin-security: 1.4.0 eslint-plugin-tsdoc: 0.2.5 express: 4.16.4 @@ -207,6 +210,7 @@ dependencies: source-map: 0.6.1 strict-uri-encode: 2.0.0 sudo: 1.0.3 + tapable: 1.1.3 tar: 5.0.5 through2: 2.0.5 timsort: 0.3.0 @@ -364,6 +368,13 @@ packages: hasBin: true resolution: integrity: sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ== + /@babel/runtime-corejs3/7.10.3: + dependencies: + core-js-pure: 3.6.5 + regenerator-runtime: 0.13.5 + dev: false + resolution: + integrity: sha512-HA7RPj5xvJxQl429r5Cxr2trJwOfPjKiqhCXcdQPSqO2G0RHPZpXu4fkYmBaTKCp2c/jRaMK9GB/lN+7zvvFPw== /@babel/template/7.10.1: dependencies: '@babel/code-frame': 7.10.1 @@ -611,6 +622,13 @@ packages: dev: false resolution: integrity: sha512-OWiIC3+Rnv6WzmwuOZkbpHGw9kSKTlzFZBrBwDVEkXp0SP1LsWOy7BALIR1RdTmaM9tRMzKZsjRWz4MWqXJdCQ== + /@microsoft/api-extractor-model/7.8.8: + dependencies: + '@microsoft/tsdoc': 0.12.19 + '@rushstack/node-core-library': 3.24.1 + dev: false + resolution: + integrity: sha512-oiUkYZmBUUd1afxkOXDgdaz/ROnNQT72xHE1ALHJzlCUWnAhQcWjVUOr9WnigIOJp1fiwfA6F2l1wUgDzFQ6Iw== /@microsoft/api-extractor/7.7.9: dependencies: '@microsoft/api-extractor-model': 7.7.8 @@ -626,6 +644,21 @@ packages: hasBin: true resolution: integrity: sha512-sXobUDKsKx2apisLFhk5gxBPBfnCbM31hpmQwqHAbwZ7ak4Sj7I+OcN41hSwbIQksZnk2OSbu+WElEehHiS+xA== + /@microsoft/api-extractor/7.8.12: + dependencies: + '@microsoft/api-extractor-model': 7.8.8 + '@microsoft/tsdoc': 0.12.19 + '@rushstack/node-core-library': 3.24.1 + '@rushstack/ts-command-line': 4.4.2 + colors: 1.2.5 + lodash: 4.17.15 + resolve: 1.17.0 + source-map: 0.6.1 + typescript: 3.7.5 + dev: false + hasBin: true + resolution: + integrity: sha512-tXJAlJCZ96Offii+4QelYOYbESc5az7MeJ34+EnluE1Exx0ksCsuZuKuyOBWqEandnEJ8tT3eMs8b/bvjH/2QA== /@microsoft/gulp-core-build-mocha/3.8.8: dependencies: '@microsoft/gulp-core-build': 3.15.5 @@ -717,6 +750,21 @@ packages: hasBin: true resolution: integrity: sha512-gGqzxa4yVPXJJXUDddc/iHDSxs9Iv9Bmsh7PC+8KKgxtBOunW0HFojhF/N4XlhHheXYx0gNjRXHjJgom3KVXMA== + /@microsoft/rush-stack-compiler-3.9/0.2.1: + dependencies: + '@microsoft/api-extractor': 7.8.12 + '@rushstack/eslint-config': 0.5.8_eslint@6.5.1+typescript@3.9.5 + '@rushstack/node-core-library': 3.24.1 + '@types/node': 10.17.13 + eslint: 6.5.1 + import-lazy: 4.0.0 + tslint: 5.20.1 + tslint-microsoft-contrib: 6.2.0_tslint@5.20.1 + typescript: 3.9.5 + dev: false + hasBin: true + resolution: + integrity: sha512-lQsycWewyzbqDuRlluim2jEf1zXdeyg8XZOQ8PEvwebfljiW8KGHShcBCVLHbZt1ZGqQY/flj3E/10jK18b9Xg== /@microsoft/teams-js/1.3.0-beta.4: dev: false resolution: @@ -852,6 +900,25 @@ packages: typescript: '>=3.0.0' resolution: integrity: sha512-AB7wAXYTuF0z1x9BpFM6Nm0hyk9v94k55w0bZHDJJoptopEOsoEEFf4QVnNRCnYi6JAABzOtvq2vW4g4mAx+Xw== + /@rushstack/eslint-config/0.5.8_eslint@6.5.1+typescript@3.9.5: + dependencies: + '@rushstack/eslint-plugin': 0.3.2_eslint@6.5.1 + '@typescript-eslint/eslint-plugin': 2.3.3_bb9a6dbd05774a8f63383c04291d931e + '@typescript-eslint/experimental-utils': 2.3.3_eslint@6.5.1 + '@typescript-eslint/parser': 2.3.3_eslint@6.5.1 + '@typescript-eslint/typescript-estree': 2.3.3 + eslint: 6.5.1 + eslint-plugin-promise: 4.2.1 + eslint-plugin-react: 7.16.0_eslint@6.5.1 + eslint-plugin-security: 1.4.0 + eslint-plugin-tsdoc: 0.2.5 + typescript: 3.9.5 + dev: false + peerDependencies: + eslint: ^5.0.0 || ^6.0.0 + typescript: '>=3.0.0' + resolution: + integrity: sha512-SOY3oh/dlISms1UyZiXyTwlY3L+NKtwVvIuWka7GSagfL+KQFvZcVLD8/Ab0skAc4tokVu5SrPrdDiLVAraoMA== /@rushstack/eslint-plugin/0.3.1_eslint@6.5.1: dependencies: eslint: 6.5.1 @@ -860,6 +927,14 @@ packages: eslint: ^5.0.0 || ^6.0.0 resolution: integrity: sha512-7C1tEdlNTxd8YP852jZnA1RAFEtKTEM112nPQWqyYp5IFHvNEnIaOSvHzutmTItjUCk/S7OygqK6oJyd4xQltQ== + /@rushstack/eslint-plugin/0.3.2_eslint@6.5.1: + dependencies: + eslint: 6.5.1 + dev: false + peerDependencies: + eslint: ^5.0.0 || ^6.0.0 + resolution: + integrity: sha512-Fzg91tfXtft6IdZlE6altWXuglGT29P/6ZfFGj9IVM8FIEAjMrO7MELINF5LssbFG0Xlu7306cBJVRAyzOCPCw== /@rushstack/node-core-library/3.19.4: dependencies: '@types/node': 10.17.13 @@ -884,6 +959,18 @@ packages: dev: false resolution: integrity: sha512-gKE/OXH5GAj8yJ1kEyRW68UekJernilZ3QTRgmQ0MUHBCQmtZ9Q6T5PQ1sVbcL4teH8BMdpZeFy1DKnHs8h3PA== + /@rushstack/node-core-library/3.24.1: + dependencies: + '@types/node': 10.17.13 + colors: 1.2.5 + fs-extra: 7.0.1 + jju: 1.4.0 + semver: 5.3.0 + timsort: 0.3.0 + z-schema: 3.18.4 + dev: false + resolution: + integrity: sha512-A21eDQwXAD9bZnvJZIEIhD171EQEWWo2afRs0sSUJ5FpMFpoDwx5DOY4hDE7dnczSKRmKsiDBV8hTSKhJrsw/A== /@rushstack/ts-command-line/4.3.11: dependencies: '@types/argparse': 1.0.33 @@ -892,6 +979,14 @@ packages: dev: false resolution: integrity: sha512-Jzu52EzzHmIuc4dCrK+jLKwFCrrCtVBPCxeMFtHlODXkZ61IlVW+a+rRATkNNlSykv3G0dmedOFxQsVpVgoUpA== + /@rushstack/ts-command-line/4.4.2: + dependencies: + '@types/argparse': 1.0.38 + argparse: 1.0.10 + colors: 1.2.5 + dev: false + resolution: + integrity: sha512-iJ6wV+ICaE252J2snVPDiX4pz1r25CY1Ua/3QE4nd+lD+80hv6i6JLCDdmkculgYRXkAxvYXRtriD4JfqvgdKA== /@sinonjs/commons/1.8.0: dependencies: type-detect: 4.0.8 @@ -963,17 +1058,17 @@ packages: dev: false resolution: integrity: sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== - /@types/eslint/6.1.3: + /@types/eslint/7.2.0: dependencies: - '@types/estree': 0.0.39 + '@types/estree': 0.0.44 '@types/json-schema': 7.0.4 dev: false resolution: - integrity: sha512-llYf1QNZaDweXtA7uY6JczcwHmFwJL9TpK3E6sY0B18l6ulDT6VWNMAdEjYccFHiDfxLPxffd8QmSDV4QUUspA== - /@types/estree/0.0.39: + integrity: sha512-LpUXkr7fnmPXWGxB0ZuLEzNeTURuHPavkC5zuU4sg62/TgL5ZEjamr5Y8b6AftwHtx2bPJasI+CL0TT2JwQ7aA== + /@types/estree/0.0.44: dev: false resolution: - integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== + integrity: sha512-iaIVzr+w2ZJ5HkidlZ3EJM8VTZb2MJLCjw3V+505yVts0gRC4UMvjw0d1HPtGqI/HQC/KdsYtayfzl+AXY2R8g== /@types/events/3.0.0: dev: false resolution: @@ -1327,6 +1422,10 @@ packages: dev: false resolution: integrity: sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ== + /@types/tapable/1.0.5: + dev: false + resolution: + integrity: sha512-/gG2M/Imw7cQFp8PGvz/SwocNrmKFjFsm5Pb8HdbHkZ1K8pmuPzOX4VeVoiEecFCVf4CsN1r3/BRvx+6sNqwtQ== /@types/tar/4.0.3: dependencies: '@types/minipass': 2.2.0 @@ -1449,7 +1548,6 @@ packages: functional-red-black-tree: 1.0.1 regexpp: 2.0.1 tsutils: 3.17.1_typescript@3.5.3 - typescript: 3.5.3 dev: false engines: node: ^8.10.0 || ^10.13.0 || >=11.10.1 @@ -1459,6 +1557,47 @@ packages: typescript: '*' resolution: integrity: sha512-12cCbwu5PbQudkq2xCIS/QhB7hCMrsNPXK+vJtqy/zFqtzVkPRGy12O5Yy0gUK086f3VHV/P4a4R4CjMW853pA== + /@typescript-eslint/eslint-plugin/2.3.3_bb9a6dbd05774a8f63383c04291d931e: + dependencies: + '@typescript-eslint/experimental-utils': 2.3.3_eslint@6.5.1 + '@typescript-eslint/parser': 2.3.3_eslint@6.5.1 + eslint: 6.5.1 + eslint-utils: 1.4.3 + functional-red-black-tree: 1.0.1 + regexpp: 2.0.1 + tsutils: 3.17.1_typescript@3.9.5 + typescript: 3.9.5 + dev: false + engines: + node: ^8.10.0 || ^10.13.0 || >=11.10.1 + peerDependencies: + '@typescript-eslint/parser': ^2.0.0 + eslint: ^5.0.0 || ^6.0.0 + typescript: '*' + resolution: + integrity: sha512-12cCbwu5PbQudkq2xCIS/QhB7hCMrsNPXK+vJtqy/zFqtzVkPRGy12O5Yy0gUK086f3VHV/P4a4R4CjMW853pA== + /@typescript-eslint/eslint-plugin/3.3.0_5230966e5e0a36b5cf15b6a6401aaf8c: + dependencies: + '@typescript-eslint/experimental-utils': 3.3.0_eslint@7.2.0+typescript@3.5.3 + '@typescript-eslint/parser': 3.3.0_eslint@7.2.0+typescript@3.5.3 + eslint: 7.2.0 + functional-red-black-tree: 1.0.1 + regexpp: 3.1.0 + semver: 7.3.2 + tsutils: 3.17.1_typescript@3.5.3 + typescript: 3.5.3 + dev: false + engines: + node: ^10.12.0 || >=12.0.0 + peerDependencies: + '@typescript-eslint/parser': ^3.0.0 + eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + resolution: + integrity: sha512-Ybx/wU75Tazz6nU2d7nN6ll0B98odoiYLXwcuwS5WSttGzK46t0n7TPRQ4ozwcTv82UY6TQoIvI+sJfTzqK9dQ== /@typescript-eslint/experimental-utils/2.3.3_eslint@6.5.1: dependencies: '@types/json-schema': 7.0.4 @@ -1472,6 +1611,38 @@ packages: eslint: '*' resolution: integrity: sha512-MQ4jKPMTU1ty4TigJCRKFPye2qyQdH8jzIIkceaHgecKFmkNS1hXPqKiZ+mOehkz6+HcN5Nuvwm+frmWZR9tdg== + /@typescript-eslint/experimental-utils/3.3.0_eslint@7.2.0+typescript@3.5.3: + dependencies: + '@types/json-schema': 7.0.4 + '@typescript-eslint/typescript-estree': 3.3.0_typescript@3.5.3 + eslint: 7.2.0 + eslint-scope: 5.1.0 + eslint-utils: 2.1.0 + typescript: 3.5.3 + dev: false + engines: + node: ^10.12.0 || >=12.0.0 + peerDependencies: + eslint: '*' + typescript: '*' + resolution: + integrity: sha512-d4pGIAbu/tYsrPrdHCQ5xfadJGvlkUxbeBB56nO/VGmEDi/sKmfa5fGty5t5veL1OyJBrUmSiRn1R1qfVDydrg== + /@typescript-eslint/experimental-utils/3.3.0_eslint@7.2.0+typescript@3.9.5: + dependencies: + '@types/json-schema': 7.0.4 + '@typescript-eslint/typescript-estree': 3.3.0_typescript@3.9.5 + eslint: 7.2.0 + eslint-scope: 5.1.0 + eslint-utils: 2.1.0 + typescript: 3.9.5 + dev: false + engines: + node: ^10.12.0 || >=12.0.0 + peerDependencies: + eslint: '*' + typescript: '*' + resolution: + integrity: sha512-d4pGIAbu/tYsrPrdHCQ5xfadJGvlkUxbeBB56nO/VGmEDi/sKmfa5fGty5t5veL1OyJBrUmSiRn1R1qfVDydrg== /@typescript-eslint/parser/2.3.3_eslint@6.5.1: dependencies: '@types/eslint-visitor-keys': 1.0.0 @@ -1486,6 +1657,44 @@ packages: eslint: ^5.0.0 || ^6.0.0 resolution: integrity: sha512-+cV53HuYFeeyrNW8x/rgPmbVrzzp/rpRmwbJnNtwn4K8mroL1BdjxwQh7X9cUHp9rm4BBiEWmD3cSBjKG7d5mw== + /@typescript-eslint/parser/3.3.0_eslint@7.2.0+typescript@3.5.3: + dependencies: + '@types/eslint-visitor-keys': 1.0.0 + '@typescript-eslint/experimental-utils': 3.3.0_eslint@7.2.0+typescript@3.5.3 + '@typescript-eslint/typescript-estree': 3.3.0_typescript@3.5.3 + eslint: 7.2.0 + eslint-visitor-keys: 1.3.0 + typescript: 3.5.3 + dev: false + engines: + node: ^10.12.0 || >=12.0.0 + peerDependencies: + eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + resolution: + integrity: sha512-a7S0Sqn/+RpOOWTcaLw6RD4obsharzxmgMfdK24l364VxuBODXjuJM7ImCkSXEN7oz52aiZbXSbc76+2EsE91w== + /@typescript-eslint/parser/3.3.0_eslint@7.2.0+typescript@3.9.5: + dependencies: + '@types/eslint-visitor-keys': 1.0.0 + '@typescript-eslint/experimental-utils': 3.3.0_eslint@7.2.0+typescript@3.9.5 + '@typescript-eslint/typescript-estree': 3.3.0_typescript@3.9.5 + eslint: 7.2.0 + eslint-visitor-keys: 1.3.0 + typescript: 3.9.5 + dev: false + engines: + node: ^10.12.0 || >=12.0.0 + peerDependencies: + eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + resolution: + integrity: sha512-a7S0Sqn/+RpOOWTcaLw6RD4obsharzxmgMfdK24l364VxuBODXjuJM7ImCkSXEN7oz52aiZbXSbc76+2EsE91w== /@typescript-eslint/typescript-estree/2.3.3: dependencies: glob: 7.1.6 @@ -1497,6 +1706,46 @@ packages: node: ^8.10.0 || ^10.13.0 || >=11.10.1 resolution: integrity: sha512-GkACs12Xp8d/STunNv/iSMYJFQrkrax9vuPZySlgSzoJJtw1cp6tbEw4qsLskQv6vloLrkFJHcTJ0a/yCB5cIA== + /@typescript-eslint/typescript-estree/3.3.0_typescript@3.5.3: + dependencies: + debug: 4.1.1 + eslint-visitor-keys: 1.3.0 + glob: 7.1.6 + is-glob: 4.0.1 + lodash: 4.17.15 + semver: 7.3.2 + tsutils: 3.17.1_typescript@3.5.3 + typescript: 3.5.3 + dev: false + engines: + node: ^10.12.0 || >=12.0.0 + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + resolution: + integrity: sha512-3SqxylENltEvJsjjMSDCUx/edZNSC7wAqifUU1Ywp//0OWEZwMZJfecJud9XxJ/40rAKEbJMKBOQzeOjrLJFzQ== + /@typescript-eslint/typescript-estree/3.3.0_typescript@3.9.5: + dependencies: + debug: 4.1.1 + eslint-visitor-keys: 1.3.0 + glob: 7.1.6 + is-glob: 4.0.1 + lodash: 4.17.15 + semver: 7.3.2 + tsutils: 3.17.1_typescript@3.9.5 + typescript: 3.9.5 + dev: false + engines: + node: ^10.12.0 || >=12.0.0 + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + resolution: + integrity: sha512-3SqxylENltEvJsjjMSDCUx/edZNSC7wAqifUU1Ywp//0OWEZwMZJfecJud9XxJ/40rAKEbJMKBOQzeOjrLJFzQ== /@webassemblyjs/ast/1.8.5: dependencies: '@webassemblyjs/helper-module-context': 1.8.5 @@ -2912,6 +3161,15 @@ packages: node: '>=8' resolution: integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + /chalk/4.1.0: + dependencies: + ansi-styles: 4.2.1 + supports-color: 7.1.0 + dev: false + engines: + node: '>=10' + resolution: + integrity: sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== /chardet/0.7.0: dev: false resolution: @@ -3026,6 +3284,14 @@ packages: node: '>=4' resolution: integrity: sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= + /cli-cursor/3.1.0: + dependencies: + restore-cursor: 3.1.0 + dev: false + engines: + node: '>=8' + resolution: + integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== /cli-table/0.3.1: dependencies: colors: 1.0.3 @@ -3357,6 +3623,11 @@ packages: dev: false resolution: integrity: sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A== + /core-js-pure/3.6.5: + dev: false + requiresBuild: true + resolution: + integrity: sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA== /core-js/2.6.11: deprecated: 'core-js@<3 is no longer maintained and not recommended for usage due to the number of issues. Please, upgrade your dependencies to the actual version of core-js@3.' dev: false @@ -4215,6 +4486,27 @@ packages: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 resolution: integrity: sha512-GacBAATewhhptbK3/vTP09CbFrgUJmBSaaRcWdbQLFvUZy9yVcQxigBNHGPU/KE2AyHpzj3AWXpxoMTsIDiHug== + /eslint-plugin-react/7.20.0_eslint@7.2.0: + dependencies: + array-includes: 3.1.1 + doctrine: 2.1.0 + eslint: 7.2.0 + has: 1.0.3 + jsx-ast-utils: 2.3.0 + object.entries: 1.1.2 + object.fromentries: 2.0.2 + object.values: 1.1.1 + prop-types: 15.7.2 + resolve: 1.17.0 + string.prototype.matchall: 4.0.2 + xregexp: 4.3.0 + dev: false + engines: + node: '>=4' + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 + resolution: + integrity: sha512-rqe1abd0vxMjmbPngo4NaYxTcR3Y4Hrmc/jg4T+sYz63yqlmJRknpEQfmWY+eDWPuMmix6iUIK+mv0zExjeLgA== /eslint-plugin-security/1.4.0: dependencies: safe-regex: 1.1.0 @@ -4246,6 +4538,15 @@ packages: node: '>=8.0.0' resolution: integrity: sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== + /eslint-scope/5.1.0: + dependencies: + esrecurse: 4.2.1 + estraverse: 4.3.0 + dev: false + engines: + node: '>=8.0.0' + resolution: + integrity: sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== /eslint-utils/1.4.3: dependencies: eslint-visitor-keys: 1.1.0 @@ -4254,12 +4555,26 @@ packages: node: '>=6' resolution: integrity: sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== + /eslint-utils/2.1.0: + dependencies: + eslint-visitor-keys: 1.3.0 + dev: false + engines: + node: '>=6' + resolution: + integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== /eslint-visitor-keys/1.1.0: dev: false engines: node: '>=4' resolution: integrity: sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== + /eslint-visitor-keys/1.3.0: + dev: false + engines: + node: '>=4' + resolution: + integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== /eslint/6.5.1: dependencies: '@babel/code-frame': 7.10.1 @@ -4305,6 +4620,50 @@ packages: hasBin: true resolution: integrity: sha512-32h99BoLYStT1iq1v2P9uwpyznQ4M2jRiFB6acitKz52Gqn+vPaMDUTB1bYi1WN4Nquj2w+t+bimYUG83DC55A== + /eslint/7.2.0: + dependencies: + '@babel/code-frame': 7.10.1 + ajv: 6.12.2 + chalk: 4.1.0 + cross-spawn: 7.0.3 + debug: 4.1.1 + doctrine: 3.0.0 + eslint-scope: 5.1.0 + eslint-utils: 2.1.0 + eslint-visitor-keys: 1.3.0 + espree: 7.1.0 + esquery: 1.3.1 + esutils: 2.0.3 + file-entry-cache: 5.0.1 + functional-red-black-tree: 1.0.1 + glob-parent: 5.1.1 + globals: 12.4.0 + ignore: 4.0.6 + import-fresh: 3.2.1 + imurmurhash: 0.1.4 + inquirer: 7.2.0 + is-glob: 4.0.1 + js-yaml: 3.13.1 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash: 4.17.15 + minimatch: 3.0.4 + natural-compare: 1.4.0 + optionator: 0.9.1 + progress: 2.0.3 + regexpp: 3.1.0 + semver: 7.3.2 + strip-ansi: 6.0.0 + strip-json-comments: 3.1.0 + table: 5.4.6 + text-table: 0.2.0 + v8-compile-cache: 2.1.1 + dev: false + engines: + node: ^10.12.0 || >=12.0.0 + hasBin: true + resolution: + integrity: sha512-B3BtEyaDKC5MlfDa2Ha8/D6DsS4fju95zs0hjS3HdGazw+LNayai38A25qMppK37wWGWNYSPOR6oYzlz5MHsRQ== /espree/6.2.1: dependencies: acorn: 7.2.0 @@ -4315,6 +4674,16 @@ packages: node: '>=6.0.0' resolution: integrity: sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== + /espree/7.1.0: + dependencies: + acorn: 7.2.0 + acorn-jsx: 5.2.0_acorn@7.2.0 + eslint-visitor-keys: 1.3.0 + dev: false + engines: + node: ^10.12.0 || >=12.0.0 + resolution: + integrity: sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw== /esprima/1.2.5: dev: false engines: @@ -4789,6 +5158,14 @@ packages: node: '>=4' resolution: integrity: sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + /figures/3.2.0: + dependencies: + escape-string-regexp: 1.0.5 + dev: false + engines: + node: '>=8' + resolution: + integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== /file-entry-cache/5.0.1: dependencies: flat-cache: 2.0.1 @@ -5419,6 +5796,14 @@ packages: node: '>=4' resolution: integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + /globals/12.4.0: + dependencies: + type-fest: 0.8.1 + dev: false + engines: + node: '>=8' + resolution: + integrity: sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== /globals/9.18.0: dev: false engines: @@ -6195,6 +6580,26 @@ packages: node: '>=6.0.0' resolution: integrity: sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== + /inquirer/7.2.0: + dependencies: + ansi-escapes: 4.3.1 + chalk: 3.0.0 + cli-cursor: 3.1.0 + cli-width: 2.2.1 + external-editor: 3.1.0 + figures: 3.2.0 + lodash: 4.17.15 + mute-stream: 0.0.8 + run-async: 2.4.1 + rxjs: 6.5.5 + string-width: 4.2.0 + strip-ansi: 6.0.0 + through: 2.3.8 + dev: false + engines: + node: '>=8.0.0' + resolution: + integrity: sha512-E0c4rPwr9ByePfNlTIB8z51kK1s2n6jrHuJeEHENl/sbq2G/S1auvibgEwNR4uSyiU+PiYHqSwsgGiXjG8p5ZQ== /internal-ip/4.3.0: dependencies: default-gateway: 4.2.0 @@ -6204,6 +6609,16 @@ packages: node: '>=6' resolution: integrity: sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg== + /internal-slot/1.0.2: + dependencies: + es-abstract: 1.17.5 + has: 1.0.3 + side-channel: 1.0.2 + dev: false + engines: + node: '>= 0.4' + resolution: + integrity: sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g== /interpret/1.2.0: dev: false engines: @@ -8201,6 +8616,15 @@ packages: node: '>= 0.8.0' resolution: integrity: sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + /levn/0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: false + engines: + node: '>= 0.8.0' + resolution: + integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== /liftoff/3.1.0: dependencies: extend: 3.0.2 @@ -9505,6 +9929,19 @@ packages: node: '>= 0.8.0' resolution: integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + /optionator/0.9.1: + dependencies: + deep-is: 0.1.3 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.3 + dev: false + engines: + node: '>= 0.8.0' + resolution: + integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== /orchestrator/0.3.8: dependencies: end-of-stream: 0.1.5 @@ -10135,6 +10572,12 @@ packages: node: '>= 0.8.0' resolution: integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + /prelude-ls/1.2.1: + dev: false + engines: + node: '>= 0.8.0' + resolution: + integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== /preserve/0.2.0: dev: false engines: @@ -10620,6 +11063,10 @@ packages: dev: false resolution: integrity: sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + /regenerator-runtime/0.13.5: + dev: false + resolution: + integrity: sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== /regex-cache/0.4.4: dependencies: is-equal-shallow: 0.1.3 @@ -10652,6 +11099,12 @@ packages: node: '>=6.5.0' resolution: integrity: sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + /regexpp/3.1.0: + dev: false + engines: + node: '>=8' + resolution: + integrity: sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== /regexpu-core/4.7.0: dependencies: regenerate: 1.4.0 @@ -10922,6 +11375,15 @@ packages: node: '>=4' resolution: integrity: sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + /restore-cursor/3.1.0: + dependencies: + onetime: 5.1.0 + signal-exit: 3.0.3 + dev: false + engines: + node: '>=8' + resolution: + integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== /ret/0.1.15: dev: false engines: @@ -11303,6 +11765,13 @@ packages: dev: false resolution: integrity: sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== + /side-channel/1.0.2: + dependencies: + es-abstract: 1.17.5 + object-inspect: 1.7.0 + dev: false + resolution: + integrity: sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA== /signal-exit/3.0.3: dev: false resolution: @@ -11730,6 +12199,17 @@ packages: node: '>=8' resolution: integrity: sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== + /string.prototype.matchall/4.0.2: + dependencies: + define-properties: 1.1.3 + es-abstract: 1.17.5 + has-symbols: 1.0.1 + internal-slot: 1.0.2 + regexp.prototype.flags: 1.3.0 + side-channel: 1.0.2 + dev: false + resolution: + integrity: sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg== /string.prototype.trimend/1.0.1: dependencies: define-properties: 1.1.3 @@ -12401,6 +12881,17 @@ packages: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' resolution: integrity: sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== + /tsutils/3.17.1_typescript@3.9.5: + dependencies: + tslib: 1.13.0 + typescript: 3.9.5 + dev: false + engines: + node: '>= 6' + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + resolution: + integrity: sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== /tty-browserify/0.0.0: dev: false resolution: @@ -12423,6 +12914,14 @@ packages: node: '>= 0.8.0' resolution: integrity: sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + /type-check/0.4.0: + dependencies: + prelude-ls: 1.2.1 + dev: false + engines: + node: '>= 0.8.0' + resolution: + integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== /type-detect/0.1.1: dev: false resolution: @@ -13411,6 +13910,12 @@ packages: dev: false resolution: integrity: sha512-ruPC/fyPNck2BD1dpz0AZZyrEwMOrWTO5lDdIXS91rs3wtm4j+T8Rp2o+zoOYkkAxJTZRPOSnOGei1egoRmKMQ== + /xregexp/4.3.0: + dependencies: + '@babel/runtime-corejs3': 7.10.3 + dev: false + resolution: + integrity: sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g== /xtend/4.0.2: dev: false engines: @@ -13647,7 +14152,7 @@ packages: dev: false name: '@rush-temp/api-documenter-test' resolution: - integrity: sha512-TXX2XGFWXT9L/c0EBNCSf4t4nRNVKWtMfOqiXPXhiuDYqIc1ics4bdDN+hYkY8IRaN5e7iLbjmcXle1hnhiFsg== + integrity: sha512-xPShjp3CMqTNozpd0NQ7gszqAyFosMF30f7CXeVhG8uchtKyCTRxCWCSTybLNT7FZyYFgQ6IgzJYk8ZDPCPP2Q== tarball: 'file:projects/api-documenter-test.tgz' version: 0.0.0 'file:projects/api-documenter.tgz': @@ -13665,7 +14170,7 @@ packages: dev: false name: '@rush-temp/api-documenter' resolution: - integrity: sha512-Jwy59tLl94t+w9ux4spjg+fD5oM35QHCgH5shwmW/0uWj3QgPBhYR2XkkSn7UbsIShHjYUYaHx7qcfGxCpM18Q== + integrity: sha512-zZAUZWVAnR5l55npmqTmaJGdxA5c2mANCAjX/0063z3BYwjRAoeyFE4zWMzIal0QoGDwnV6l35P0NR448U4jBQ== tarball: 'file:projects/api-documenter.tgz' version: 0.0.0 'file:projects/api-extractor-lib1-test.tgz': @@ -13676,7 +14181,7 @@ packages: dev: false name: '@rush-temp/api-extractor-lib1-test' resolution: - integrity: sha512-OXk5XZCTQOPnO2fV/SPxjtcqEg6x3x9wtzzAUFqV9TR7i4+xot1txuh4hly1iSQ/Fk1zwD/wtQ3RScsZwsJ+LQ== + integrity: sha512-gi8v35mfZ1UjiRMMVrfqEvqWTlzwFk0+ShIsuznGPFXHQho0k7WLJXK1/PL9dG6Lud+pfwFtT18LKESMi+gvHw== tarball: 'file:projects/api-extractor-lib1-test.tgz' version: 0.0.0 'file:projects/api-extractor-lib2-test.tgz': @@ -13688,7 +14193,7 @@ packages: dev: false name: '@rush-temp/api-extractor-lib2-test' resolution: - integrity: sha512-9JMVBlxvcnFoYcghe7tgx7PbEyoNOSK5yrJv2DjmvYwKipIWkTlmYe5G3TfuCzWZgC27x9zOXKw9P3KaVluBoA== + integrity: sha512-IyG00gC1rU0u25g9CcxtzoxGAZOd271AXBjfyyBU6iXb4a1GTBafsDhmC6CyjeIe4IMi0jzmwjkevBGV4SYVAw== tarball: 'file:projects/api-extractor-lib2-test.tgz' version: 0.0.0 'file:projects/api-extractor-lib3-test.tgz': @@ -13700,7 +14205,7 @@ packages: dev: false name: '@rush-temp/api-extractor-lib3-test' resolution: - integrity: sha512-Xaq+4t3d/tRnbJuMVT5CsQSeVHMcgZ7Q6fLIUNF7By2wbtmuCzwFK/yVTIf4NlMBr8vM4FshtACBd3H+tU6Z2A== + integrity: sha512-qWYKmJAZMWzI5Lya19W4LflIxStoHG7gHZHWTIscAL8TSqy+d/PTZh2Ecea4PnB8vgPiRzGryae1m6cRv714tQ== tarball: 'file:projects/api-extractor-lib3-test.tgz' version: 0.0.0 'file:projects/api-extractor-model.tgz': @@ -13714,7 +14219,7 @@ packages: dev: false name: '@rush-temp/api-extractor-model' resolution: - integrity: sha512-pn9wP3/peGZ42JnBGtVUL4GaTRkYMXnrG9xAJXieof1RHwRbLjo2IwSs9kkB1MgXdP8752grmv/LGy9ElBzGIA== + integrity: sha512-uFOBdEdczwM8LEOJ1KOKL4KePdBiK/ttx19crBxcCW4nEQb1/Or8/CXj1mkcZvrepI/d/PHUSS2Kx+6YSwggTA== tarball: 'file:projects/api-extractor-model.tgz' version: 0.0.0 'file:projects/api-extractor-scenarios.tgz': @@ -13728,7 +14233,7 @@ packages: dev: false name: '@rush-temp/api-extractor-scenarios' resolution: - integrity: sha512-ISTb01zEOBAFoVnxIQcjLa+axmu6q8+/AwDj9qHszO3ycXmtpPer9EPxvbQedCNpD3Tp3MbIMghloXFn2njnCA== + integrity: sha512-z6z6d06x4oGbWUh/k/eK90f7NcfbF4VmejAUZtekcCRg0QZdRTPmAkLmyHWzsz8vgl550XdojFPPXNWz8MR7oA== tarball: 'file:projects/api-extractor-scenarios.tgz' version: 0.0.0 'file:projects/api-extractor-test-01.tgz': @@ -13742,7 +14247,7 @@ packages: dev: false name: '@rush-temp/api-extractor-test-01' resolution: - integrity: sha512-vLsN73xcEaa7VWtft1ijyOFIU/z0RYHMRaaO7eIWMcKggEJy9gq1226GbPz6sBKDoURfGThanjTnxyA5P46dHw== + integrity: sha512-gOjcaQLOaF/QOdFTRwAHSBCF3ybI7+oIqk6Rd0JtEtGO4BcPSqwnLHD9LX+zD3uGEWJziRs0BgeafQzWiZZOwQ== tarball: 'file:projects/api-extractor-test-01.tgz' version: 0.0.0 'file:projects/api-extractor-test-02.tgz': @@ -13755,7 +14260,7 @@ packages: dev: false name: '@rush-temp/api-extractor-test-02' resolution: - integrity: sha512-UWLrF7+wwRKN4hj/jnAih0LgsK+d+AcmYdmOt+ZHkENca4c3iKxi6NxMazohUvWx1gbU/3fqjJrtfClFkIjEzQ== + integrity: sha512-c71KlFtuAIrZNTr3xpuGeSKiKZ4Hhr79zGIglstYRp0psjrK4RD1ZF5kT43gQ3GoNBKBIj2TBkExudN+rDlbjw== tarball: 'file:projects/api-extractor-test-02.tgz' version: 0.0.0 'file:projects/api-extractor-test-03.tgz': @@ -13777,7 +14282,7 @@ packages: dev: false name: '@rush-temp/api-extractor-test-04' resolution: - integrity: sha512-s45r5nn8wd/ecEtyShun4nvzyPU2mXboK9/frShX7Y0JdAj18E+IsZhebTFw3Yh06BQEHQ0c8Emeuo1ddF8mug== + integrity: sha512-xEYRuLo3KBPCTEvhyyALCtUfUTezX1HrxOdft9O3DACXsBawFHPVqZUbnN6IwISU9wuPl0p4jB0e9mzYvWpcxw== tarball: 'file:projects/api-extractor-test-04.tgz' version: 0.0.0 'file:projects/api-extractor.tgz': @@ -13798,7 +14303,7 @@ packages: dev: false name: '@rush-temp/api-extractor' resolution: - integrity: sha512-zAIJZu4aoegbuP1jhaZpuooIXr5RVTVGmBhCJweCvMGN/hcOGQDayvuCKIiNraVY3s2bLm923kHyGvsQ7dRGqQ== + integrity: sha512-dWZrORWaZuwFZRqm0DsNRMgwU/oWDr+L/G7Rq/uhpZkk3z8t1BhpfRhL2Z51IpCOapi15rm4fseal7gSGyOktA== tarball: 'file:projects/api-extractor.tgz' version: 0.0.0 'file:projects/debug-certificate-manager.tgz': @@ -13813,7 +14318,7 @@ packages: dev: false name: '@rush-temp/debug-certificate-manager' resolution: - integrity: sha512-wcf4B1/hCvvDpxBWob0a4IZiCup9VhTxXtx0LmzD5VT7kZysgbQtKl+ZMr98emwRsOlKH7Y+f7WWWumu8+wDNA== + integrity: sha512-IvSBa1p0MZmX/znNDbEXovD0pXQDLvUpjDg13z0b9zNzOph2gGir0RY2qP3HoePFbhO0mCPkB2BfKmElFV+LlA== tarball: 'file:projects/debug-certificate-manager.tgz' version: 0.0.0 'file:projects/doc-plugin-rush-stack.tgz': @@ -13826,51 +14331,64 @@ packages: dev: false name: '@rush-temp/doc-plugin-rush-stack' resolution: - integrity: sha512-J8hwYfq7UkBY8LzBW68c+g5WL9iz7aaTpOiB945ODU5WXa2kqZp4Ed+KUPqP8+gfJDmUt1cmsVb7MgOkNd+KIQ== + integrity: sha512-67rl8eDnQoRJyBiS5rVmOILtlE9uwD4KhAzE9hegqlvvescIkZdnbDk/WpjvtwPpt5MV7AbFr3Qd0YXuB5XHPA== tarball: 'file:projects/doc-plugin-rush-stack.tgz' version: 0.0.0 'file:projects/eslint-config.tgz': dependencies: - '@typescript-eslint/eslint-plugin': 2.3.3_5b3b7d3a75edb27abc53579646941536 - '@typescript-eslint/experimental-utils': 2.3.3_eslint@6.5.1 - '@typescript-eslint/parser': 2.3.3_eslint@6.5.1 - '@typescript-eslint/typescript-estree': 2.3.3 - eslint: 6.5.1 + '@typescript-eslint/eslint-plugin': 3.3.0_5230966e5e0a36b5cf15b6a6401aaf8c + '@typescript-eslint/experimental-utils': 3.3.0_eslint@7.2.0+typescript@3.5.3 + '@typescript-eslint/parser': 3.3.0_eslint@7.2.0+typescript@3.5.3 + '@typescript-eslint/typescript-estree': 3.3.0_typescript@3.5.3 + eslint: 7.2.0 eslint-plugin-promise: 4.2.1 - eslint-plugin-react: 7.16.0_eslint@6.5.1 + eslint-plugin-react: 7.20.0_eslint@7.2.0 eslint-plugin-security: 1.4.0 eslint-plugin-tsdoc: 0.2.5 typescript: 3.5.3 dev: false name: '@rush-temp/eslint-config' resolution: - integrity: sha512-nf6kyKroqvfYn9e2eBHBsKDVwJHSA43JWHRGM1qZQO5ux1ZENDUOpEVXQADMHOUvNz1p6NOVzHPrjrWKjyigDg== + integrity: sha512-YiSMlB1XCVv2QmC3jJB+vHjgxKe13BH7hFQiS/SSS9eyZG8Q40lhiipmdcEUW+WxH3X/G+6dJ6Oi66TfvZWLkg== tarball: 'file:projects/eslint-config.tgz' version: 0.0.0 + 'file:projects/eslint-patch.tgz': + dependencies: + '@microsoft/node-library-build': 6.4.10 + '@microsoft/rush-stack-compiler-3.5': 0.4.4 + '@types/node': 10.17.13 + gulp: 4.0.2 + dev: false + name: '@rush-temp/eslint-patch' + resolution: + integrity: sha512-9Tk8VDdnvofysUc0iWkZPOmDZiHBvTwPsG1u1QREkFFcU9PIDM0w4DKw/+G1Xz14tyNl4QSFHYyWvpfLeXJG2Q== + tarball: 'file:projects/eslint-patch.tgz' + version: 0.0.0 'file:projects/eslint-plugin.tgz': dependencies: '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/eslint': 6.1.3 - '@types/estree': 0.0.39 + '@microsoft/rush-stack-compiler-3.9': 0.2.1 + '@types/eslint': 7.2.0 + '@types/estree': 0.0.44 '@types/node': 10.17.13 - '@typescript-eslint/experimental-utils': 2.3.3_eslint@6.5.1 - '@typescript-eslint/parser': 2.3.3_eslint@6.5.1 - '@typescript-eslint/typescript-estree': 2.3.3 - eslint: 6.5.1 + '@typescript-eslint/experimental-utils': 3.3.0_eslint@7.2.0+typescript@3.9.5 + '@typescript-eslint/parser': 3.3.0_eslint@7.2.0+typescript@3.9.5 + '@typescript-eslint/typescript-estree': 3.3.0_typescript@3.9.5 + eslint: 7.2.0 gulp: 4.0.2 - typescript: 3.5.3 + typescript: 3.9.5 dev: false name: '@rush-temp/eslint-plugin' resolution: - integrity: sha512-8J4XtiI3vFv11k4IwnvyZddLYNpxxQOrPq9zGP4nFi4J1+JVA2ZZyss6mHZqeEOyL2go/p8/yhy/e1SyII+5Kg== + integrity: sha512-iGDW1jWZJeDSXGm0XKxUPtHqGL4wpcZHeNHf9TIcBSqj61dwvWiLJmHMpGQjSbBCLC2HEnuR/NJM2MLuyn5sxg== tarball: 'file:projects/eslint-plugin.tgz' version: 0.0.0 'file:projects/generate-api-docs.tgz': dev: false name: '@rush-temp/generate-api-docs' resolution: - integrity: sha512-q9r1RYGZpWLK/9ajxkG0iQFnA2MzMCfdssBuQZbvRZukBVdAoZZO+yoLPghcNz6hn2Ej2pH/PGH3jVf3JtiYHw== + integrity: sha512-EdMtO2cbdAOc2YMasycDyYvdhF3hVXEITM0q4W300CzRuoo18ygd4Fd6jFq+gv4r4WUuHABR/v1uhNZFDYMeig== tarball: 'file:projects/generate-api-docs.tgz' version: 0.0.0 'file:projects/gulp-core-build-mocha.tgz': @@ -13891,7 +14409,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-mocha' resolution: - integrity: sha512-5XFZ4zKZ+jSbHg1PTJhjkQitggcKTxTfU5LbqnFCVlwj/Ee1QKIbVY30dTPeY4MBxh+oYuTSluB6r3CYk6nsnQ== + integrity: sha512-r5zagOwKFMJIT08EmGOkouD3RBbzBjoMQaj+DH0BuhrwtnF8S0O0LVmvCbZtSnss1x/QsibTt0xILNBZJU9BUQ== tarball: 'file:projects/gulp-core-build-mocha.tgz' version: 0.0.0 'file:projects/gulp-core-build-sass.tgz': @@ -13914,7 +14432,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-sass' resolution: - integrity: sha512-tV37KXx2KBrZENRA591k0mDm9jNmDdvidrDNqokQ/jThNGeez+jxW+dXGdXuZxJDHIKux/pt1Cy+ID9mkPI6oQ== + integrity: sha512-LP8ALd6fp6blk8Fva7axAFB9M8T5YPjcnbYfjnNFfZPh3C8tQZKvSEFeKVR5oEv5t37zLZ5NUgIyEsdD90DJyw== tarball: 'file:projects/gulp-core-build-sass.tgz' version: 0.0.0 'file:projects/gulp-core-build-serve.tgz': @@ -13937,7 +14455,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-serve' resolution: - integrity: sha512-8dE7gW6ZRhwy5gshaobZMXlz7fEshUr3Czt9oynRMsW+4kH5zksNkDYz2T6cDFf7vERBuAx1Yl9hnVtSoV1sRg== + integrity: sha512-JX6RAbeJmH0AJ6VF2m1ieATu38qlK70vznNv2YkvDrMlmxhuz5PxdqAxTYLeComn9OitBe8H1b2i7RWSOlBGiA== tarball: 'file:projects/gulp-core-build-serve.tgz' version: 0.0.0 'file:projects/gulp-core-build-typescript.tgz': @@ -13956,7 +14474,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-typescript' resolution: - integrity: sha512-4ezZkd375+anny07SVyoennfj1OonWtucAmP2wyKgcaWjqV+Toy+1rr10fqT+PbS+NF+n4alg9vOPzghKZYYkA== + integrity: sha512-oO9VkOSKzCx3QaO7/qMzJN4mIpaSPWzkfPCnHoJ62xTFGN90zKcKVS8Wzwmg1i2mqfnJW4jrDj4c739dRn+GOQ== tarball: 'file:projects/gulp-core-build-typescript.tgz' version: 0.0.0 'file:projects/gulp-core-build-webpack.tgz': @@ -13974,7 +14492,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-webpack' resolution: - integrity: sha512-EehzSsLEKMUGg6xr7ecVwQvfjIlEUZZ5Z6dX2rwaEfcDJHzuHjHdEHVXcF7u1qlcGd1WghX+fatdUamU2drnqQ== + integrity: sha512-7DHcxPmoDQGDoYgf9PPuclHNPLb53GUC0aa+Dz64CxGizUkn0KU9Mqi8hf+U5ugMqZgcMzvVY0ol705k8x1fBA== tarball: 'file:projects/gulp-core-build-webpack.tgz' version: 0.0.0 'file:projects/gulp-core-build.tgz': @@ -14027,9 +14545,24 @@ packages: dev: false name: '@rush-temp/gulp-core-build' resolution: - integrity: sha512-AtxLC2CPpx+TqjehqEiqreFh6W4OpmWqXP0w8z64IeNhHmHmTRxuwYmJlzXWDz6/FmNHJHjSlObvDXogMBAC7A== + integrity: sha512-5o0TF4Ez7ENV/IUGiohZvOsOVIRvx85zyaPMvjZy7uulFvy8ufKUgoZhAI48kXFQjXPE9mOV+U5mRYuxa9QQ1A== tarball: 'file:projects/gulp-core-build.tgz' version: 0.0.0 + 'file:projects/heft.tgz': + dependencies: + '@types/glob': 7.1.1 + '@types/node': 10.17.13 + '@types/resolve': 1.17.1 + '@types/tapable': 1.0.5 + glob: 7.0.6 + resolve: 1.17.0 + tapable: 1.1.3 + dev: false + name: '@rush-temp/heft' + resolution: + integrity: sha512-vJ9opGwFd5jjMaf0dRPg1RDUMK2LuRVOzth+eOem1aG4uFw/9bbDcIkr1KUyP14z1Sq9hc/MQFKtVmND8a0Y6Q== + tarball: 'file:projects/heft.tgz' + version: 0.0.0 'file:projects/load-themed-styles.tgz': dependencies: '@types/chai': 3.4.34 @@ -14041,7 +14574,7 @@ packages: dev: false name: '@rush-temp/load-themed-styles' resolution: - integrity: sha512-clKNvHSGnf6JdfGGk9xMPMNI1F3l2i82EJa8lY0JLsLaAuQ210pzOfbuRwf33xR9/A2LhKrCZtMdcoUMFv66Ug== + integrity: sha512-Yf0DHJF1N+ymVmX/r3NJDpZNKsCOPvtOvPdzASM4xo1tFepqGeuzD0BoK0KpsXz5REiZ2haSicwUYfyfGqA7hg== tarball: 'file:projects/load-themed-styles.tgz' version: 0.0.0 'file:projects/loader-load-themed-styles.tgz': @@ -14057,7 +14590,7 @@ packages: dev: false name: '@rush-temp/loader-load-themed-styles' resolution: - integrity: sha512-u9gJyiFoEmZ5y4OjvBp+kdDirFC5n3MudWbayhnPVv5UNs9oSNg12aayItj4X/Qm2wpCQUVtvcOJFJqNqVBqkA== + integrity: sha512-p4TOB+3wfySAQeAZknsW7mX2I8sZAKcxtq1MVOulih9t41GA991OGiOCZfGF2nQrGvCFFK9i8H26mR2hB8Y8pA== tarball: 'file:projects/loader-load-themed-styles.tgz' version: 0.0.0 'file:projects/loader-raw-script.tgz': @@ -14072,7 +14605,7 @@ packages: dev: false name: '@rush-temp/loader-raw-script' resolution: - integrity: sha512-lJRwBGhEq3QoT2Xjv+Ayt41tzPCLR7rWhxbooBphE0qZn4MXFfrMEZbX2oJa9Sb/B14MZkqx8j0CVvV5WotyQA== + integrity: sha512-yJrch7k+buHOl6UFsDY+DjgV92AJmEr5E4J2SlC5yPNcV8pBQHrBDdimavO82XRdkOVmIPtWRPgL6zLum/J24w== tarball: 'file:projects/loader-raw-script.tgz' version: 0.0.0 'file:projects/localization-plugin-test-01.tgz': @@ -14087,7 +14620,7 @@ packages: dev: false name: '@rush-temp/localization-plugin-test-01' resolution: - integrity: sha512-XPFx/W6mKgQuSDsEk0maae4ZCH2VCvmDGYBXMwdp5urK4nmw5B3tqYKs5sRJopbsUGzFAzriW1WASNC3SvKQPw== + integrity: sha512-Gz89FBD3tp2YeGik3bbt/r96RSW3RxlN58sAsrIRZZov4RMfeq/McfWT6kC6JMDAbJlSYCmkuKeoN5ySOwcymQ== tarball: 'file:projects/localization-plugin-test-01.tgz' version: 0.0.0 'file:projects/localization-plugin-test-02.tgz': @@ -14104,7 +14637,7 @@ packages: dev: false name: '@rush-temp/localization-plugin-test-02' resolution: - integrity: sha512-w+8luyyxPHtKa2oMSZw+P7yLpM9hXD4yhwy+HgGcuqGnhfMx1uG1PvPM1VDjS8x95/vcj6pGHqW+mP0Zp+i/VA== + integrity: sha512-dGZN+v0pir0xAJfDWD8RrNzaLUf7Q+ap52M8kX/3WSc8o4A/IM+1VGhC2mDCOoTWGFqnV+l85hyFJYsV4WnkpA== tarball: 'file:projects/localization-plugin-test-02.tgz' version: 0.0.0 'file:projects/localization-plugin-test-03.tgz': @@ -14119,7 +14652,7 @@ packages: dev: false name: '@rush-temp/localization-plugin-test-03' resolution: - integrity: sha512-sTyftdYindCyrrOnCnGYU01Em30MaxamMmJnQ1utCggKqOtwuDo7yh0DBlsAjbrD+QD0tjDbVLKzk99ta3UbFA== + integrity: sha512-fddgjDB89amP+XGWvRjSYn+pvw37w66YPNXEf5qm3veACqO6mAxtksJrm+/SG/XjCsCwIsSMdFonYr1SLqm+mg== tarball: 'file:projects/localization-plugin-test-03.tgz' version: 0.0.0 'file:projects/localization-plugin.tgz': @@ -14127,7 +14660,7 @@ packages: '@types/loader-utils': 1.1.3 '@types/lodash': 4.14.116 '@types/node': 10.17.13 - '@types/tapable': 1.0.4 + '@types/tapable': 1.0.5 '@types/webpack': 4.39.8 '@types/xmldoc': 1.1.4 decache: 4.5.1 @@ -14140,7 +14673,7 @@ packages: dev: false name: '@rush-temp/localization-plugin' resolution: - integrity: sha512-VGY+u0C5ywUsbUmQH5y0LDjwj+lsvbU7JY1ueQ2FmQAIuSmkAcUa3sCLGC6VwvRuOwBJOuS9GwZ0TnG1OLgyzg== + integrity: sha512-Li3TTe8AaM1T9XSURG9Jy0LrSAQ5US5lywbNogPs2Ds8Zpt+KxBikEkv9gzXkjGYAWCtwmokbIMS5NbqvL0FdQ== tarball: 'file:projects/localization-plugin.tgz' version: 0.0.0 'file:projects/node-core-library.tgz': @@ -14164,7 +14697,7 @@ packages: dev: false name: '@rush-temp/node-core-library' resolution: - integrity: sha512-fv6ABTvDWODQPGdweV5+tOv48waDjIutpFk7MotmaytCVH1URqoEACu1Kp1B2fGTYGLQO72H7uoXTWM3WoqTgg== + integrity: sha512-MGje/6vNJ5aSHtLTE/d9S8VTRLewrMbhrMWrRR9XeoQxgpBnRUmdSL0z2mt7OA/5SF6qKt/C/5g2m022Ou6ijg== tarball: 'file:projects/node-core-library.tgz' version: 0.0.0 'file:projects/node-library-build-eslint-test.tgz': @@ -14177,7 +14710,7 @@ packages: dev: false name: '@rush-temp/node-library-build-eslint-test' resolution: - integrity: sha512-wIE10iNotS0fEVHHC06Ii8rYUwmMNrsWSpYmPEUfBSn88xxeWjX3shXdMq9FcE2zdHvnvjkLqYai6DBBNMcEZA== + integrity: sha512-H5dimoozdurJLKJAlmR/QgvE4Oac8+DqxRoOKIyLn/lUy6VViV5w+M/Rf2J8oYh898RUS0BIKa8zswnXsO+kKg== tarball: 'file:projects/node-library-build-eslint-test.tgz' version: 0.0.0 'file:projects/node-library-build-tslint-test.tgz': @@ -14190,7 +14723,7 @@ packages: dev: false name: '@rush-temp/node-library-build-tslint-test' resolution: - integrity: sha512-OIXHyd75mDt9Epal63vQVMIS/CSC2d/wDqoSKA04j5Qx9aU+UWHChXt4Ox7WNEzeUiyun6jXNc8IX56ZCmkN7A== + integrity: sha512-QbDVKOK6Wk1xXCFs3TC25g+R8fJqVWw1kv6mPfmKpdJ3ohzjBBV+FV+XQ61Zes2ReWP7xLUFNZVpnQ0loeTUWQ== tarball: 'file:projects/node-library-build-tslint-test.tgz' version: 0.0.0 'file:projects/node-library-build.tgz': @@ -14201,7 +14734,7 @@ packages: dev: false name: '@rush-temp/node-library-build' resolution: - integrity: sha512-3y7+vQ7ZhYy5DHVmXyRfQob4hIAWJ0JWRBpn7kmoUWuMXuuMUbSKP1Rq4FNRmE5+lIXlOmsibzwJu5cD8zI80w== + integrity: sha512-bfyal8ttTMbaHL8CDzfisVkILcsdKXWMcgWsis+x/TkL9le1XVygP/6iIVGmRu5/In7aeyDfRrPFcH+Zbmv6Yw== tarball: 'file:projects/node-library-build.tgz' version: 0.0.0 'file:projects/package-deps-hash.tgz': @@ -14215,7 +14748,7 @@ packages: dev: false name: '@rush-temp/package-deps-hash' resolution: - integrity: sha512-0RrXA1YHv5w/0+7Usobjto78GUox8WGLX6KQu8jxabePYrqeCW1tFSKGjCJcv73acpSTgWKZ9dZuwWgz5Sx6OQ== + integrity: sha512-Lj0sEKoxaNfD3wyhE0Gg55i/0b9aXvkKBHPNirPiDn3AeB0mtlDH/vCAQ1mSzJVGuAwD7UUjw0qysQTz49bNsw== tarball: 'file:projects/package-deps-hash.tgz' version: 0.0.0 'file:projects/repo-toolbox.tgz': @@ -14225,7 +14758,7 @@ packages: dev: false name: '@rush-temp/repo-toolbox' resolution: - integrity: sha512-TrIQ3Y132JyWgkDS1++9pv/uj0RAiKTSTF7lb0iGbWoIgHWdL/axJjhttF42AEcgEtcTOG6WUkgEVlswdvD7tA== + integrity: sha512-He9VmESCwDZ85Mxyfl1BSjh+ZGhTHXbhp8l7u6nZ8WgLrYSkkEfy0abzPAohWGTrtftHijK191QgCEwQ03aStQ== tarball: 'file:projects/repo-toolbox.tgz' version: 0.0.0 'file:projects/rush-buildxl.tgz': @@ -14236,7 +14769,7 @@ packages: dev: false name: '@rush-temp/rush-buildxl' resolution: - integrity: sha512-FG1gZPrX4lwo+SulIcjAiKo/4VCokZP/bI95czvyjOh3qLuK7PePWq9eSBLtBGczOj6V29Cc0pDL50OSS0VnhQ== + integrity: sha512-H2yEXGCk732wAS2draTBfqWKaSZOS9CAQVHarzWLd3yceZ4NSvsEJLn+/oxtFrFmdIYnOj+dphihUtvpTErxNQ== tarball: 'file:projects/rush-buildxl.tgz' version: 0.0.0 'file:projects/rush-lib.tgz': @@ -14288,7 +14821,7 @@ packages: dev: false name: '@rush-temp/rush-lib' resolution: - integrity: sha512-rw9dkkbqx7iVFsr/KYOkJd/Rs7GS8XM4CjfB9tjARtrGKHjzjvuWHWdRQbjoGJyLyXPfuyweux1Y7Ac3uTpGtQ== + integrity: sha512-MY1rroOMxQHuJTExNFwTiz7V5U+YtcvmdRKZycUd+Y793Ew0DsOCvHL2EZA5rrraitzuivuFZZKmbDX158g7WA== tarball: 'file:projects/rush-lib.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.4-library-test.tgz': @@ -14298,7 +14831,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.4-library-test' resolution: - integrity: sha512-2v78Iif8yBORoAjZLV1IYwU1o27RyITRo4ZP6/jEFNea65pHIFHPgw/v9XvcYOnzQadpEiuyDx6+zcjy1Ck6gw== + integrity: sha512-vEtfkpGJDydXvzQeQgxigFVSnsnTaGtWzbgeoCzuVooYf2Np1d0YEopxGjdc6lEk+/W1UTOr0axeyARxq7CLaQ== tarball: 'file:projects/rush-stack-compiler-2.4-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.4.tgz': @@ -14306,7 +14839,7 @@ packages: '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 '@types/node': 10.17.13 - eslint: 6.5.1 + eslint: 7.2.0 gulp: 4.0.2 import-lazy: 4.0.0 tslint: 5.20.1 @@ -14315,7 +14848,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.4' resolution: - integrity: sha512-57P6ZVFgRpKnp/3ZrL0EYiDlzkTEqRhlZeUE6lZYdwp9Mzr0Xzlrx+5p7MjT8t9k9b2pvx2IFwbcEzyllaoZMw== + integrity: sha512-2u4kMMgfm6QZ+bhQJHnrt4TsHnrkqza20u5uA5t5tGFRVRndhYSVG+nNGFEw6EpsMmQTbhyuH/s7godEIhBC4w== tarball: 'file:projects/rush-stack-compiler-2.4.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.7-library-test.tgz': @@ -14325,7 +14858,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.7-library-test' resolution: - integrity: sha512-hMkhP7E+CWZEmP9IUPqcjkxaRBztoMG0V2rvXwE3pPqabMgyRKmqlxARCwFbVBTECgfoeF3rSh5MXqlqfMvv9Q== + integrity: sha512-ei2oKEmYe2F9vQ6eri8gshc7Gv9APqJGkzCHRwWN1cVfD90lYMu1QcjlmYPs8VHGhLtWKaTsFrC6xjh4cZWupA== tarball: 'file:projects/rush-stack-compiler-2.7-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.7.tgz': @@ -14333,7 +14866,7 @@ packages: '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 '@types/node': 10.17.13 - eslint: 6.5.1 + eslint: 7.2.0 gulp: 4.0.2 import-lazy: 4.0.0 tslint: 5.20.1 @@ -14342,7 +14875,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.7' resolution: - integrity: sha512-UC9Hv2u9wjj+uZ1CkWpcEsWC3Ke5kqkIZJTAY7TzYYTxRapqZwJOvp0zE23bqaLisToMqxnNfnNuvC/9CdGNEw== + integrity: sha512-DgIclv7qN6x0/JtVq8wUIxdWCC229x7WrEOubw05fyWemmcfWSKtts2WXlZrRsLqu8xXZhI7o7eMxlbKXAEztA== tarball: 'file:projects/rush-stack-compiler-2.7.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.8-library-test.tgz': @@ -14352,7 +14885,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.8-library-test' resolution: - integrity: sha512-ylHQuTGU6bSmSJpDxTbU2OWz5aU1n/OadUTaSXBpRgJmwo6i3nMri3kPY2jZ/nIPpdBCm7pAUsjpM20zXp98/A== + integrity: sha512-XkTLBTH5WYLV+KxS1fn4Z7cWzu0lWu4PnGk6d8hp9+sd1NwAf45YVo+TwJ8H422PIZCm4h1TkhD12pcqFLYONw== tarball: 'file:projects/rush-stack-compiler-2.8-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.8.tgz': @@ -14360,7 +14893,7 @@ packages: '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 '@types/node': 10.17.13 - eslint: 6.5.1 + eslint: 7.2.0 gulp: 4.0.2 import-lazy: 4.0.0 tslint: 5.20.1 @@ -14369,7 +14902,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.8' resolution: - integrity: sha512-Xyli6uxNrVQRV0ZNdm8El2zKhmpnB0zmA/xhUj8T4fO6oT+N5xuFzV2PwNKVg6plbD4962xE0H8eICKmg/6VTA== + integrity: sha512-abjnIbLrSv00emrPGaycjyEjBZDBuMhNn0d7NsxnZ675tLZtR3s+SfMZk5Po2h+Lv1eXgyUgU4c07ZZcGI4sow== tarball: 'file:projects/rush-stack-compiler-2.8.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.9-library-test.tgz': @@ -14379,7 +14912,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.9-library-test' resolution: - integrity: sha512-4M9DvDPj55BdSjhXaURSX3ecYXtyFQjWgzjyR3UsFn5xYFWLvbuwEMAOUScVXw6rZtbT07mp35ZRFoi4JWaSPw== + integrity: sha512-Zyl1Uyhk5+eTGnf6QPid80qRCcPqrEW+ZqWRVn+E+YRHuk/wvKyJe+AmK4c3toIRm5ufkdBb/OQIosBOIwINeg== tarball: 'file:projects/rush-stack-compiler-2.9-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.9.tgz': @@ -14387,7 +14920,7 @@ packages: '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 '@types/node': 10.17.13 - eslint: 6.5.1 + eslint: 7.2.0 gulp: 4.0.2 import-lazy: 4.0.0 tslint: 5.20.1 @@ -14396,7 +14929,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.9' resolution: - integrity: sha512-UQFb882awER9Y2RBIh3aEvlrsku1TJ8W65iULFkUAjSIwNdg6L6ff6kqkNjKg58w8DHQ8LP9JTABf1/z3RfvTA== + integrity: sha512-OUEqzQUeXV9w0+I3eFdTkjt4jaUp4S7bDE7Rtp4Hq7mjjd6Cw+sMzVVAwnQmViuYyr1iH2P/+FoCVb1FeNee7w== tarball: 'file:projects/rush-stack-compiler-2.9.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.0-library-test.tgz': @@ -14406,7 +14939,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.0-library-test' resolution: - integrity: sha512-oY3sGqtHbDeVODrDnMVxqe22w3RbMahHFY7+2w83GMIUgtBIRIlfoYTvnSfQ2iIUGl1pjqPYbN0jW9jdePG/4Q== + integrity: sha512-862U2HfyQ8n+j0YWrwY96DfbBH1IUfPoJrw+Tr4sYws2OftDUtFkADqv+pWLbkkY9B7YBsrNjLviKJ+jB21VtA== tarball: 'file:projects/rush-stack-compiler-3.0-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.0.tgz': @@ -14414,7 +14947,7 @@ packages: '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 '@types/node': 10.17.13 - eslint: 6.5.1 + eslint: 7.2.0 gulp: 4.0.2 import-lazy: 4.0.0 tslint: 5.20.1 @@ -14423,7 +14956,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.0' resolution: - integrity: sha512-LieTrQ5hGWMaYZY1Rd654W1Sr95/WHv+RyRxPwrjd82VrFcdfWw8DpCG0weIt9b7ejBmHOjL2dphAJEoEDp9Aw== + integrity: sha512-02CucPcTZ1sVaBDLP0IXaA7Mn8wq1Mrrgtdqp0lncIpWIcawjFn9sTDp0X75qJfhioxmW0z+1BYG8mrytZ81jg== tarball: 'file:projects/rush-stack-compiler-3.0.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.1-library-test.tgz': @@ -14433,7 +14966,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.1-library-test' resolution: - integrity: sha512-fBo+TTntb9Y0ljrlwaojekjry5AloO0xyOUqAMS8aS4ua0yt8xnUggWYxRU/9I3rHgiChUYwcDlRj0j/TkCzEw== + integrity: sha512-+miwHsekIONtsPn9ZwXUIOmreG9i24ERtOmqtf+iZQ8CyxQRMtMOs2IunirwrppHUbQAQ5TMWtztBHCALGQkBg== tarball: 'file:projects/rush-stack-compiler-3.1-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.1.tgz': @@ -14441,7 +14974,7 @@ packages: '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 '@types/node': 10.17.13 - eslint: 6.5.1 + eslint: 7.2.0 gulp: 4.0.2 import-lazy: 4.0.0 tslint: 5.20.1 @@ -14450,7 +14983,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.1' resolution: - integrity: sha512-KarOZC0BcXyg2ZWFZw5jTpDE9MCulfq/W1P8ZOUIA7/iS7keRqUb5UtJQxq+dWtjPusgYPoxhGXEQUVBPEvclg== + integrity: sha512-YmW5vnSMzKeuq5iP9golciP0liwNUAF+A0cWQHugIfmTKUyj7qBFXUHCi1tJnh08MGz96jFFx59XXH8x0n3K5A== tarball: 'file:projects/rush-stack-compiler-3.1.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.2-library-test.tgz': @@ -14460,7 +14993,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.2-library-test' resolution: - integrity: sha512-nhxrLyS3GRHnFOxTpGLLlZVCyxE5RtWhO0tmGnQiZ/NJC7JcgIn7vEKNUIjpIgiOrSc87aXBYOzN80UiSAMxlg== + integrity: sha512-Mdrm5KwuT5jEY8Tgrka+upc2kfIK3LEH8inc8XSaoDLGW0DvgQdcyaogBBnjTR4SzFtDnG/xzF1akXLeWjFkEg== tarball: 'file:projects/rush-stack-compiler-3.2-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.2.tgz': @@ -14468,7 +15001,7 @@ packages: '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 '@types/node': 10.17.13 - eslint: 6.5.1 + eslint: 7.2.0 gulp: 4.0.2 import-lazy: 4.0.0 tslint: 5.20.1 @@ -14477,7 +15010,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.2' resolution: - integrity: sha512-9BmcH3cHS5YgNEXJbspDEJ+KhyJadTerPBtupqKUsukdXgnfWRsw+wUinr9rpD8fz+Fs7I/GB9/zFIwk8mcokA== + integrity: sha512-uxteVLfkazD+6nEcqUlHcwLJEgXQ/qAyniTmPBpO4FOrJW+akphLyB+ot2yEZVNFfIlZpDlBoV7IdZWU3E2o/w== tarball: 'file:projects/rush-stack-compiler-3.2.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.3-library-test.tgz': @@ -14487,7 +15020,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.3-library-test' resolution: - integrity: sha512-X/2xMB7l6ADEkmqtSxDphN0oqNEsSJB4IalCd/Cw66GZP3mRWGKBg3aq+Hx1JEn9t0FUa5JcLxpx4frzbRNQGw== + integrity: sha512-phW34yARVqS3nP3QhY8QkdaUl7v1HuYVRhFOxS7LUZDnI37eCyM8Zotqvs6mLWMU5ykWnfd4OzSed6Ubots02A== tarball: 'file:projects/rush-stack-compiler-3.3-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.3.tgz': @@ -14495,7 +15028,7 @@ packages: '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 '@types/node': 10.17.13 - eslint: 6.5.1 + eslint: 7.2.0 gulp: 4.0.2 import-lazy: 4.0.0 tslint: 5.20.1 @@ -14504,7 +15037,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.3' resolution: - integrity: sha512-zNkp3TWnAcK0zPiOGxpT9VfPei5ip4x31ZDwZs0aX9o2XPzCxCvG4P7ck4U9MnylnN03VGtZHJ3HRVdhjnkcUg== + integrity: sha512-7e2S7uwrVKaCJOqD8cONo+EtEzjhytnX7nxoZoTzQJxP+S3MrgYuN/DABNf/ffNIo9OMock6CPf9BuwFlFcEvw== tarball: 'file:projects/rush-stack-compiler-3.3.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.4-library-test.tgz': @@ -14514,7 +15047,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.4-library-test' resolution: - integrity: sha512-hqKwsfxgJJNQU4YgC8DwEaOJYUElDMaLnfw2Asra2zE4IOJQDczqyIR0wP/7yI7bfPNwaUigN+sLl4c2BKEjEQ== + integrity: sha512-tILR2VCYYTTVc8srHOxz+3vLpyjWCeQNwZnGkJXFtwrgMbje9cq1cJVRp0rQY9yQwJ2v4U4HFrzdVrIf6hPIfw== tarball: 'file:projects/rush-stack-compiler-3.4-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.4.tgz': @@ -14522,7 +15055,7 @@ packages: '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 '@types/node': 10.17.13 - eslint: 6.5.1 + eslint: 7.2.0 gulp: 4.0.2 import-lazy: 4.0.0 tslint: 5.20.1 @@ -14531,7 +15064,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.4' resolution: - integrity: sha512-prGtvvhsIEDPrtgR7nAV/qLX9kgpQYFz19BnkMtjRfRCBf3pwL+W1X7lwLbUgj7qosjLt8Jh1UIvbX63ldVOqw== + integrity: sha512-BKmp2cuXiWypxYZ/u2OOi5JmH7wpmW0C1rFNlcON/qupOZqQJVHk68OY1dE3GcvbieYN7db3oAvl/Dp9Wakvug== tarball: 'file:projects/rush-stack-compiler-3.4.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.5-library-test.tgz': @@ -14541,7 +15074,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.5-library-test' resolution: - integrity: sha512-8pqwhi6Rq8ntcpvx6G0OSWk4HSOw3ICCtxqNr9EwKi2CPWBhjhiXEkkhs2bp0GXgLjfavDVZosR3Ta0UbPpw0Q== + integrity: sha512-V9ZgxNxuccf0p8JZxpPkU/ht//HbTFXhvSBfirfDSN37FiqvPJkc+AEbdbjzDbeK/hqnsm1OEZP82luE7cdWwA== tarball: 'file:projects/rush-stack-compiler-3.5-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.5.tgz': @@ -14549,7 +15082,7 @@ packages: '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 '@types/node': 10.17.13 - eslint: 6.5.1 + eslint: 7.2.0 gulp: 4.0.2 import-lazy: 4.0.0 tslint: 5.20.1 @@ -14558,7 +15091,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.5' resolution: - integrity: sha512-pg+nSIUt9aGFRkoGPFVnVfK6Sbh//gQRrX8hWxEXSLtB0wwrw/TaLMxuJSE6qPLN1xuc90XKHP5LjGr9ZXCNew== + integrity: sha512-Jl3P0UMFqTAA9Gy+z8eNvQ4SthMzlKEf4FCaCpVy72cwHJDaZbj13WWpobmf3WYKFEvy49veC9f2ucmwBM4dfA== tarball: 'file:projects/rush-stack-compiler-3.5.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.6-library-test.tgz': @@ -14568,7 +15101,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.6-library-test' resolution: - integrity: sha512-+y+e5tTG6/MgmKykS1AFhqQWKDvDa+y0EtJJnQJ0R90S9sQdEyyRsHI2V6sUVy6HWb34xTnlWUnXuBvkEk0f/Q== + integrity: sha512-lDRf3c807YzaPWjpIGvxqZnA1NVQzhqiBkP2Rq6kTS7Bx4shpMyILjransKJsT5nNGtyTA/Y+ARTOSbI6sTK1Q== tarball: 'file:projects/rush-stack-compiler-3.6-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.6.tgz': @@ -14576,7 +15109,7 @@ packages: '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 '@types/node': 10.17.13 - eslint: 6.5.1 + eslint: 7.2.0 gulp: 4.0.2 import-lazy: 4.0.0 tslint: 5.20.1 @@ -14585,7 +15118,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.6' resolution: - integrity: sha512-eYCoOrDyiJDR8yEkiIikL/m46rZGwmYdOUyutBUcl8LtXVuHfBdL2t4YB2u9p16fOtbMA59Ji00bHzmueGVDdA== + integrity: sha512-bHtrtA9lrfoLBJy72sx8arVUYNSeUlh+FOwISQ5aS/OAQGuIMu6RlXxxzfOoK1EoGfrjvkRPdl4Wz65T1imnUw== tarball: 'file:projects/rush-stack-compiler-3.6.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.7-library-test.tgz': @@ -14595,7 +15128,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.7-library-test' resolution: - integrity: sha512-3Y4p/vdIkwhVX2O699pDU4pKQ5DPW5M8jBGn9d8cmJPkQxdXuyD4+2Muf/PUIJSgIkaHh3nER0MCL3gVtKqE5w== + integrity: sha512-HqWRokq5BdOC3xzofbfw/vtHqZJm1vl1tuZe3vJGlD7q82gkn/L5PYYQng9tJOWujlgVMm0BG9fAJmLlcUWyVA== tarball: 'file:projects/rush-stack-compiler-3.7-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.7.tgz': @@ -14603,7 +15136,7 @@ packages: '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 '@types/node': 10.17.13 - eslint: 6.5.1 + eslint: 7.2.0 gulp: 4.0.2 import-lazy: 4.0.0 tslint: 5.20.1 @@ -14612,7 +15145,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.7' resolution: - integrity: sha512-fu+y4D9ubcWWcxfLm9KwXH4cRHLXz07RUxNQUpDVvJZt3CP22mTgz8oqE/sRjvAeNbVuTzD5zUmh7g0YuXc0fw== + integrity: sha512-5nQB/tO5Ek7pljMcFu128hIQHK2c6EzzeAKBSumUW4UdMMzYa/3ZQs1y39ekvfIJ0YKvya7MmMjTvtiEvSa8rw== tarball: 'file:projects/rush-stack-compiler-3.7.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.8-library-test.tgz': @@ -14622,7 +15155,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.8-library-test' resolution: - integrity: sha512-WEPjJLl/NCyk1+pNzegflvuq5oEVIjJfe9JaPMkd4DgDa8McNRJdeYVBNrl2hFH16n1MxUiFJH7QMgHRArLSfA== + integrity: sha512-uvh/8A31sF4IR1VNoL5/8DeUFTJxZLOIF5AAxiPnZeu/57zuZFRnJSYHU6fj1PaF43lbOwEj4UY+QWJpNHWLuQ== tarball: 'file:projects/rush-stack-compiler-3.8-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.8.tgz': @@ -14630,7 +15163,7 @@ packages: '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 '@types/node': 10.17.13 - eslint: 6.5.1 + eslint: 7.2.0 gulp: 4.0.2 import-lazy: 4.0.0 tslint: 5.20.1 @@ -14639,7 +15172,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.8' resolution: - integrity: sha512-0sRxabQ8klB4RtahkVubv7gmpzhNOGMau6PMH8w522W/9QVLHwxgZivMNUAIR/AesKCBDyC0h4UqQAI65MJg5Q== + integrity: sha512-aSs99GPY2h+h/AnEXwLfuUjBSl7oZwamaaPO3YHgfQm9IV2H1Bon1djRikmA8UQY5s8atjYwZj1XGdpkg3dFlw== tarball: 'file:projects/rush-stack-compiler-3.8.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.9-library-test.tgz': @@ -14649,7 +15182,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.9-library-test' resolution: - integrity: sha512-RYQBHxw8QLidr3+xWFXLTZ/bRq55yb0sg95IMgY4ZG4IqcuqazmR7cfr8k0h26lpCRJUIwSTrjXULHtN0Qau/A== + integrity: sha512-iFdnUuhu0Yz46cU0VObpRWcN7jksPu+n9jK50jPhaeUXBmrnuR4FGYCjFGp/CA1SA3VYPQsXZaoDetxLmhx5Og== tarball: 'file:projects/rush-stack-compiler-3.9-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.9.tgz': @@ -14657,7 +15190,7 @@ packages: '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 '@types/node': 10.17.13 - eslint: 6.5.1 + eslint: 7.2.0 gulp: 4.0.2 import-lazy: 4.0.0 tslint: 5.20.1 @@ -14666,7 +15199,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.9' resolution: - integrity: sha512-DohfyyEzS9DVMho2kA29fZzE8TxdCKJyymcQ5/SHYMbFF1/tcdD5lL5kMNPLTJz/IdsjoLQ7MEvkUIQmn0i+eQ== + integrity: sha512-/DQtIGWOa1k1XZRPap03pxX6+Kz9ZBgCMwFqsJLUuNu8J9xuAjX/d0/WH1A4t22TtnbkB6h7Lm88WduqQKHkEA== tarball: 'file:projects/rush-stack-compiler-3.9.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-shared.tgz': @@ -14692,7 +15225,7 @@ packages: dev: false name: '@rush-temp/rush' resolution: - integrity: sha512-ZvLxIYiPjbmHAsDHIIE9hPwidL6PCH3SWwEU50fKRxRR6awT8c9NXIB6FKkjlJ8cVLpCTCxAtqp4XfoVLR46kg== + integrity: sha512-SUsz/SPJPCXaOMM3OVFxjHvFe0kuinaP5RYaVwOYdnMwIBfhSOR9h9TcdIZxx/u1izJB6zEWbFLWoQ5lRmxq7g== tarball: 'file:projects/rush.tgz' version: 0.0.0 'file:projects/rushell.tgz': @@ -14705,7 +15238,7 @@ packages: dev: false name: '@rush-temp/rushell' resolution: - integrity: sha512-dipxANGemIA9EpAjTGKfmIEF8gjGBK26fbWcK0VkFtmtpXy92FeGF/VsGIb3YOFzU1ldkl1yaDClTQjtglun2w== + integrity: sha512-5sXiTl7Usc1/FKUfE/P4VNEgLPFJlxYyLeWHZtjr5/lqe23umbq8gjUZLlVNHloNUbjmdgjrZQhEp5sqiENfdA== tarball: 'file:projects/rushell.tgz' version: 0.0.0 'file:projects/set-webpack-public-path-plugin.tgz': @@ -14714,7 +15247,7 @@ packages: '@types/lodash': 4.14.116 '@types/mocha': 5.2.5 '@types/node': 10.17.13 - '@types/tapable': 1.0.4 + '@types/tapable': 1.0.5 '@types/uglify-js': 2.6.29 '@types/webpack': 4.39.8 chai: 3.5.0 @@ -14725,7 +15258,7 @@ packages: dev: false name: '@rush-temp/set-webpack-public-path-plugin' resolution: - integrity: sha512-qusGxbGhGj78SgupkBiW6FnrT0P9di5UfVruaLS21hbG8d8dlBOXyxi8fZW74o7ruDuDz2aIKnkJnn3fWuOF/g== + integrity: sha512-hWFUISDs0hR53pbCC+h5M9i8ftfYzHEUrHvax/Ir7BLwijPJarr5kOeSdhM+KqcaSPoUzA/ek5Ttc0WVPLBmBQ== tarball: 'file:projects/set-webpack-public-path-plugin.tgz' version: 0.0.0 'file:projects/stream-collator.tgz': @@ -14741,7 +15274,7 @@ packages: dev: false name: '@rush-temp/stream-collator' resolution: - integrity: sha512-iEwUuzQEhf6ZUEPKd1LiFS9QKfKuPMOJUhCBao87juV/2uJF3WIcG6V9WjscjClI0GKXFesvykpddCcKPE6b7w== + integrity: sha512-t4VFdRKP6sb75hacRiamRhr7vTxiLn6m1bqr0yef8oL1gU5+m3X0qZN95XwX3LnExWMCbP7fR4BQ9pk2ZNQ24Q== tarball: 'file:projects/stream-collator.tgz' version: 0.0.0 'file:projects/ts-command-line-test.tgz': @@ -14752,7 +15285,7 @@ packages: dev: false name: '@rush-temp/ts-command-line-test' resolution: - integrity: sha512-vFZJ1Qfi9GFAtOMkAoGvGPmmtXEGK53RSneMS6Spdpt1HtYi/0iNcl202dqsGoxBwc8SDJcI2tjc2tDT+Vz0BA== + integrity: sha512-3Q9mruEsrLmdAzMoUJ4jjLPQ3WZk7AzblOoS+uDfGb+STekssyRyVb6oqY4Oofic0s6sseltAm0iCDQMygpttw== tarball: 'file:projects/ts-command-line-test.tgz' version: 0.0.0 'file:projects/ts-command-line.tgz': @@ -14768,7 +15301,7 @@ packages: dev: false name: '@rush-temp/ts-command-line' resolution: - integrity: sha512-nX8i0DpfELk1LGXQqcy9CKGPRwLmOGzHVVF/CXCCZmyheXJQAc5g22VXYdQW0xRkHU7HKyKa8DbcpOAZSjoWUw== + integrity: sha512-pQ48un6TgpznXL/QpbQ/93V6t04qgL39FRBdIyT92rH0+pIrjxWX3DENe7l6jpOOfEdDLvoR+eq7YYacsJPghQ== tarball: 'file:projects/ts-command-line.tgz' version: 0.0.0 'file:projects/typings-generator.tgz': @@ -14781,7 +15314,7 @@ packages: dev: false name: '@rush-temp/typings-generator' resolution: - integrity: sha512-PSvE7VbftzMXJeP3dLJEN1IOlLBrfXud4FAtgZRIgGZvy/sx0TqkL3VYScNrndVEBaCvgGUMsGRAC5eeThXcvg== + integrity: sha512-pE10zoM8almJqk2DYl1GslAMQRgDM6GV8Hpv0J1FYPuIRcVgTTUoVor51BuQCS7yJ3k9bJ5nC2a8jy/My1/i0w== tarball: 'file:projects/typings-generator.tgz' version: 0.0.0 'file:projects/web-library-build-test.tgz': @@ -14793,7 +15326,7 @@ packages: dev: false name: '@rush-temp/web-library-build-test' resolution: - integrity: sha512-3+hYz6E6JAUPZHqeriKpF1MKUfnuY9nUbJXnHUAPdQhebI1ldgKOQ4zyn+LBg1jcw4YEb0DCfvnDEb5VI7V9ig== + integrity: sha512-p0F5e4DX1O8WhT62D7YCoHLe5E9HTFS31CZYhR28tTosH5/oQ8D7dzBxC6oeCCP39u82OGqlmMCckt/hOr+AQw== tarball: 'file:projects/web-library-build-test.tgz' version: 0.0.0 'file:projects/web-library-build.tgz': @@ -14805,7 +15338,7 @@ packages: dev: false name: '@rush-temp/web-library-build' resolution: - integrity: sha512-nD1tSW0ehEoMAghr3KS+p192wGTl/MKEcPRRwhRV/mMtiB5n9OQSJGJHZisEbymgo8kFrF6pLFMgD8t5fLuGeQ== + integrity: sha512-ZSVMR6xUJS8F5U+D7H6Ir0aBqXklwhAMYB5JHvwBkJUv9qo/T+BIPTfnFab09HHKKdSKlA/B8wtU/jNwYuYRlg== tarball: 'file:projects/web-library-build.tgz' version: 0.0.0 registry: '' @@ -14814,6 +15347,7 @@ specifiers: '@jest/reporters': 25.4.0 '@microsoft/node-library-build': 6.4.10 '@microsoft/rush-stack-compiler-3.5': 0.4.4 + '@microsoft/rush-stack-compiler-3.9': 0.2.1 '@microsoft/teams-js': 1.3.0-beta.4 '@microsoft/tsdoc': 0.12.19 '@pnpm/link-bins': ~5.1.0 @@ -14832,6 +15366,7 @@ specifiers: '@rush-temp/debug-certificate-manager': 'file:./projects/debug-certificate-manager.tgz' '@rush-temp/doc-plugin-rush-stack': 'file:./projects/doc-plugin-rush-stack.tgz' '@rush-temp/eslint-config': 'file:./projects/eslint-config.tgz' + '@rush-temp/eslint-patch': 'file:./projects/eslint-patch.tgz' '@rush-temp/eslint-plugin': 'file:./projects/eslint-plugin.tgz' '@rush-temp/generate-api-docs': 'file:./projects/generate-api-docs.tgz' '@rush-temp/gulp-core-build': 'file:./projects/gulp-core-build.tgz' @@ -14840,6 +15375,7 @@ specifiers: '@rush-temp/gulp-core-build-serve': 'file:./projects/gulp-core-build-serve.tgz' '@rush-temp/gulp-core-build-typescript': 'file:./projects/gulp-core-build-typescript.tgz' '@rush-temp/gulp-core-build-webpack': 'file:./projects/gulp-core-build-webpack.tgz' + '@rush-temp/heft': 'file:./projects/heft.tgz' '@rush-temp/load-themed-styles': 'file:./projects/load-themed-styles.tgz' '@rush-temp/loader-load-themed-styles': 'file:./projects/loader-load-themed-styles.tgz' '@rush-temp/loader-raw-script': 'file:./projects/loader-raw-script.tgz' @@ -14897,8 +15433,8 @@ specifiers: '@types/autoprefixer': 9.7.2 '@types/chalk': 0.4.31 '@types/clean-css': 4.2.1 - '@types/eslint': 6.1.3 - '@types/estree': 0.0.39 + '@types/eslint': 7.2.0 + '@types/estree': 0.0.44 '@types/express': 4.11.0 '@types/express-serve-static-core': 4.11.0 '@types/fs-extra': 7.0.0 @@ -14931,7 +15467,7 @@ specifiers: '@types/sinon': 1.16.34 '@types/source-map': 0.5.0 '@types/strict-uri-encode': 2.0.0 - '@types/tapable': 1.0.4 + '@types/tapable': 1.0.5 '@types/tar': 4.0.3 '@types/through2': 2.0.32 '@types/timsort': 0.3.0 @@ -14944,10 +15480,10 @@ specifiers: '@types/xmldoc': 1.1.4 '@types/yargs': 0.0.34 '@types/z-schema': 3.16.31 - '@typescript-eslint/eslint-plugin': 2.3.3 - '@typescript-eslint/experimental-utils': 2.3.3 - '@typescript-eslint/parser': 2.3.3 - '@typescript-eslint/typescript-estree': 2.3.3 + '@typescript-eslint/eslint-plugin': 3.3.0 + '@typescript-eslint/experimental-utils': 3.3.0 + '@typescript-eslint/parser': 3.3.0 + '@typescript-eslint/typescript-estree': 3.3.0 '@yarnpkg/lockfile': ~1.0.2 argparse: ~1.0.9 autoprefixer: ~9.8.0 @@ -14962,11 +15498,11 @@ specifiers: decomment: ~0.9.1 del: ^2.2.2 end-of-stream: ~1.1.0 - eslint: ~6.5.1 + eslint: ~7.2.0 eslint-plugin-promise: ~4.2.1 - eslint-plugin-react: ~7.16.0 + eslint-plugin-react: ~7.20.0 eslint-plugin-security: ~1.4.0 - eslint-plugin-tsdoc: ~0.2.4 + eslint-plugin-tsdoc: ~0.2.5 express: ~4.16.2 fs-extra: ~7.0.1 git-repo-info: ~2.1.0 @@ -15018,6 +15554,7 @@ specifiers: source-map: ~0.6.1 strict-uri-encode: ~2.0.0 sudo: ~1.0.3 + tapable: 1.1.3 tar: ~5.0.5 through2: ~2.0.1 timsort: ~0.3.0 @@ -15038,4 +15575,4 @@ specifiers: xmldoc: ~1.1.2 yargs: ~4.6.0 z-schema: ~3.18.3 -# shrinkwrap hash: 8bc86b40cebd75f1d7bdf06001439e8ebfed61be +# shrinkwrap hash: a591d3bb867cb057f2092670d6d3edea517ea502 From e84113622e3f55af6308360aa0a693aeb975e49c Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Wed, 24 Jun 2020 16:35:30 -0700 Subject: [PATCH 13/33] Small modification to avoid work when using DeployManager --- apps/rush-lib/src/logic/deploy/PnpmfileConfiguration.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/rush-lib/src/logic/deploy/PnpmfileConfiguration.ts b/apps/rush-lib/src/logic/deploy/PnpmfileConfiguration.ts index 825bdee9b48..bb57a2d330f 100644 --- a/apps/rush-lib/src/logic/deploy/PnpmfileConfiguration.ts +++ b/apps/rush-lib/src/logic/deploy/PnpmfileConfiguration.ts @@ -39,7 +39,12 @@ export class PnpmfileConfiguration { log: (message: string) => {} }; - if (rushConfiguration.packageManager === 'pnpm') { + // Avoid setting the hook when not using pnpm or when using pnpm workspaces, since workspaces mode + // already transforms the package.json + if ( + rushConfiguration.packageManager === 'pnpm' && + (!rushConfiguration.pnpmOptions || !rushConfiguration.pnpmOptions.useWorkspaces) + ) { const pnpmFilePath: string = rushConfiguration.getPnpmfilePath(); if (FileSystem.exists(pnpmFilePath)) { console.log('Loading ' + path.relative(rushConfiguration.rushJsonFolder, pnpmFilePath)); From 48bcca5486d5738fc760213071ef31e8961301e9 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Thu, 25 Jun 2020 15:39:59 -0700 Subject: [PATCH 14/33] Fix changes when workspace dependencies should be tracked --- apps/rush-lib/src/logic/VersionManager.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/rush-lib/src/logic/VersionManager.ts b/apps/rush-lib/src/logic/VersionManager.ts index 95ad420ff10..80b32cb5b30 100644 --- a/apps/rush-lib/src/logic/VersionManager.ts +++ b/apps/rush-lib/src/logic/VersionManager.ts @@ -14,6 +14,7 @@ import { RushConfigurationProject } from '../api/RushConfigurationProject'; import { VersionPolicyConfiguration } from '../api/VersionPolicyConfiguration'; import { PublishUtilities } from './PublishUtilities'; import { ChangeManager } from './ChangeManager'; +import { DependencySpecifier } from './DependencySpecifier'; export class VersionManager { private _rushConfiguration: RushConfiguration; @@ -313,7 +314,14 @@ export class VersionManager { oldDependencyVersion: string, newDependencyVersion: string ): void { - if (!semver.satisfies(updatedDependentProject.version, oldDependencyVersion) && !projectVersionChanged) { + const oldSpecifier: DependencySpecifier = new DependencySpecifier( + updatedDependentProject.name, + oldDependencyVersion + ); + if ( + !semver.satisfies(updatedDependentProject.version, oldSpecifier.versionSpecifier) && + !projectVersionChanged + ) { this._addChange(changes, { changeType: ChangeType.patch, packageName: clonedProject.name From 6ce1e866e270483e68f3470356434dbf4e3f254f Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Fri, 26 Jun 2020 18:04:50 -0700 Subject: [PATCH 15/33] Rush update --- common/config/rush/pnpm-lock.yaml | 354 ++++++++++++++++++------------ 1 file changed, 210 insertions(+), 144 deletions(-) diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 16df155e6d0..d4f06fd32af 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -136,16 +136,16 @@ dependencies: '@types/xmldoc': 1.1.4 '@types/yargs': 0.0.34 '@types/z-schema': 3.16.31 - '@typescript-eslint/eslint-plugin': 3.3.0_5230966e5e0a36b5cf15b6a6401aaf8c - '@typescript-eslint/experimental-utils': 3.3.0_eslint@7.2.0+typescript@3.5.3 - '@typescript-eslint/parser': 3.3.0_eslint@7.2.0+typescript@3.5.3 - '@typescript-eslint/typescript-estree': 3.3.0_typescript@3.5.3 + '@typescript-eslint/eslint-plugin': 3.4.0_cda7146ea5fa41161805b85f9284f6bd + '@typescript-eslint/experimental-utils': 3.4.0_eslint@7.2.0+typescript@3.5.3 + '@typescript-eslint/parser': 3.4.0_eslint@7.2.0+typescript@3.5.3 + '@typescript-eslint/typescript-estree': 3.4.0_typescript@3.5.3 '@yarnpkg/lockfile': 1.0.2 argparse: 1.0.10 autoprefixer: 9.8.0 builtin-modules: 3.1.0 chai: 3.5.0 - chokidar: 3.3.1 + chokidar: 3.4.0 clean-css: 4.2.1 cli-table: 0.3.1 colors: 1.2.5 @@ -1576,10 +1576,34 @@ packages: typescript: '*' resolution: integrity: sha512-12cCbwu5PbQudkq2xCIS/QhB7hCMrsNPXK+vJtqy/zFqtzVkPRGy12O5Yy0gUK086f3VHV/P4a4R4CjMW853pA== - /@typescript-eslint/eslint-plugin/3.3.0_5230966e5e0a36b5cf15b6a6401aaf8c: + /@typescript-eslint/eslint-plugin/3.4.0_43170e314695d1b0876b4d3c3574f4a4: dependencies: - '@typescript-eslint/experimental-utils': 3.3.0_eslint@7.2.0+typescript@3.5.3 - '@typescript-eslint/parser': 3.3.0_eslint@7.2.0+typescript@3.5.3 + '@typescript-eslint/experimental-utils': 3.4.0_eslint@7.2.0+typescript@3.7.5 + '@typescript-eslint/parser': 3.4.0_eslint@7.2.0+typescript@3.7.5 + debug: 4.1.1 + eslint: 7.2.0 + functional-red-black-tree: 1.0.1 + regexpp: 3.1.0 + semver: 7.3.2 + tsutils: 3.17.1_typescript@3.7.5 + typescript: 3.7.5 + dev: false + engines: + node: ^10.12.0 || >=12.0.0 + peerDependencies: + '@typescript-eslint/parser': ^3.0.0 + eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + resolution: + integrity: sha512-wfkpiqaEVhZIuQRmudDszc01jC/YR7gMSxa6ulhggAe/Hs0KVIuo9wzvFiDbG3JD5pRFQoqnf4m7REDsUvBnMQ== + /@typescript-eslint/eslint-plugin/3.4.0_cda7146ea5fa41161805b85f9284f6bd: + dependencies: + '@typescript-eslint/experimental-utils': 3.4.0_eslint@7.2.0+typescript@3.5.3 + '@typescript-eslint/parser': 3.4.0_eslint@7.2.0+typescript@3.5.3 + debug: 4.1.1 eslint: 7.2.0 functional-red-black-tree: 1.0.1 regexpp: 3.1.0 @@ -1597,7 +1621,7 @@ packages: typescript: optional: true resolution: - integrity: sha512-Ybx/wU75Tazz6nU2d7nN6ll0B98odoiYLXwcuwS5WSttGzK46t0n7TPRQ4ozwcTv82UY6TQoIvI+sJfTzqK9dQ== + integrity: sha512-wfkpiqaEVhZIuQRmudDszc01jC/YR7gMSxa6ulhggAe/Hs0KVIuo9wzvFiDbG3JD5pRFQoqnf4m7REDsUvBnMQ== /@typescript-eslint/experimental-utils/2.3.3_eslint@6.5.1: dependencies: '@types/json-schema': 7.0.4 @@ -1611,10 +1635,10 @@ packages: eslint: '*' resolution: integrity: sha512-MQ4jKPMTU1ty4TigJCRKFPye2qyQdH8jzIIkceaHgecKFmkNS1hXPqKiZ+mOehkz6+HcN5Nuvwm+frmWZR9tdg== - /@typescript-eslint/experimental-utils/3.3.0_eslint@7.2.0+typescript@3.5.3: + /@typescript-eslint/experimental-utils/3.4.0_eslint@7.2.0+typescript@3.5.3: dependencies: '@types/json-schema': 7.0.4 - '@typescript-eslint/typescript-estree': 3.3.0_typescript@3.5.3 + '@typescript-eslint/typescript-estree': 3.4.0_typescript@3.5.3 eslint: 7.2.0 eslint-scope: 5.1.0 eslint-utils: 2.1.0 @@ -1626,11 +1650,27 @@ packages: eslint: '*' typescript: '*' resolution: - integrity: sha512-d4pGIAbu/tYsrPrdHCQ5xfadJGvlkUxbeBB56nO/VGmEDi/sKmfa5fGty5t5veL1OyJBrUmSiRn1R1qfVDydrg== - /@typescript-eslint/experimental-utils/3.3.0_eslint@7.2.0+typescript@3.9.5: + integrity: sha512-rHPOjL43lOH1Opte4+dhC0a/+ks+8gOBwxXnyrZ/K4OTAChpSjP76fbI8Cglj7V5GouwVAGaK+xVwzqTyE/TPw== + /@typescript-eslint/experimental-utils/3.4.0_eslint@7.2.0+typescript@3.7.5: + dependencies: + '@types/json-schema': 7.0.4 + '@typescript-eslint/typescript-estree': 3.4.0_typescript@3.7.5 + eslint: 7.2.0 + eslint-scope: 5.1.0 + eslint-utils: 2.1.0 + typescript: 3.7.5 + dev: false + engines: + node: ^10.12.0 || >=12.0.0 + peerDependencies: + eslint: '*' + typescript: '*' + resolution: + integrity: sha512-rHPOjL43lOH1Opte4+dhC0a/+ks+8gOBwxXnyrZ/K4OTAChpSjP76fbI8Cglj7V5GouwVAGaK+xVwzqTyE/TPw== + /@typescript-eslint/experimental-utils/3.4.0_eslint@7.2.0+typescript@3.9.5: dependencies: '@types/json-schema': 7.0.4 - '@typescript-eslint/typescript-estree': 3.3.0_typescript@3.9.5 + '@typescript-eslint/typescript-estree': 3.4.0_typescript@3.9.5 eslint: 7.2.0 eslint-scope: 5.1.0 eslint-utils: 2.1.0 @@ -1642,7 +1682,7 @@ packages: eslint: '*' typescript: '*' resolution: - integrity: sha512-d4pGIAbu/tYsrPrdHCQ5xfadJGvlkUxbeBB56nO/VGmEDi/sKmfa5fGty5t5veL1OyJBrUmSiRn1R1qfVDydrg== + integrity: sha512-rHPOjL43lOH1Opte4+dhC0a/+ks+8gOBwxXnyrZ/K4OTAChpSjP76fbI8Cglj7V5GouwVAGaK+xVwzqTyE/TPw== /@typescript-eslint/parser/2.3.3_eslint@6.5.1: dependencies: '@types/eslint-visitor-keys': 1.0.0 @@ -1657,11 +1697,11 @@ packages: eslint: ^5.0.0 || ^6.0.0 resolution: integrity: sha512-+cV53HuYFeeyrNW8x/rgPmbVrzzp/rpRmwbJnNtwn4K8mroL1BdjxwQh7X9cUHp9rm4BBiEWmD3cSBjKG7d5mw== - /@typescript-eslint/parser/3.3.0_eslint@7.2.0+typescript@3.5.3: + /@typescript-eslint/parser/3.4.0_eslint@7.2.0+typescript@3.5.3: dependencies: '@types/eslint-visitor-keys': 1.0.0 - '@typescript-eslint/experimental-utils': 3.3.0_eslint@7.2.0+typescript@3.5.3 - '@typescript-eslint/typescript-estree': 3.3.0_typescript@3.5.3 + '@typescript-eslint/experimental-utils': 3.4.0_eslint@7.2.0+typescript@3.5.3 + '@typescript-eslint/typescript-estree': 3.4.0_typescript@3.5.3 eslint: 7.2.0 eslint-visitor-keys: 1.3.0 typescript: 3.5.3 @@ -1675,12 +1715,31 @@ packages: typescript: optional: true resolution: - integrity: sha512-a7S0Sqn/+RpOOWTcaLw6RD4obsharzxmgMfdK24l364VxuBODXjuJM7ImCkSXEN7oz52aiZbXSbc76+2EsE91w== - /@typescript-eslint/parser/3.3.0_eslint@7.2.0+typescript@3.9.5: + integrity: sha512-ZUGI/de44L5x87uX5zM14UYcbn79HSXUR+kzcqU42gH0AgpdB/TjuJy3m4ezI7Q/jk3wTQd755mxSDLhQP79KA== + /@typescript-eslint/parser/3.4.0_eslint@7.2.0+typescript@3.7.5: dependencies: '@types/eslint-visitor-keys': 1.0.0 - '@typescript-eslint/experimental-utils': 3.3.0_eslint@7.2.0+typescript@3.9.5 - '@typescript-eslint/typescript-estree': 3.3.0_typescript@3.9.5 + '@typescript-eslint/experimental-utils': 3.4.0_eslint@7.2.0+typescript@3.7.5 + '@typescript-eslint/typescript-estree': 3.4.0_typescript@3.7.5 + eslint: 7.2.0 + eslint-visitor-keys: 1.3.0 + typescript: 3.7.5 + dev: false + engines: + node: ^10.12.0 || >=12.0.0 + peerDependencies: + eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + resolution: + integrity: sha512-ZUGI/de44L5x87uX5zM14UYcbn79HSXUR+kzcqU42gH0AgpdB/TjuJy3m4ezI7Q/jk3wTQd755mxSDLhQP79KA== + /@typescript-eslint/parser/3.4.0_eslint@7.2.0+typescript@3.9.5: + dependencies: + '@types/eslint-visitor-keys': 1.0.0 + '@typescript-eslint/experimental-utils': 3.4.0_eslint@7.2.0+typescript@3.9.5 + '@typescript-eslint/typescript-estree': 3.4.0_typescript@3.9.5 eslint: 7.2.0 eslint-visitor-keys: 1.3.0 typescript: 3.9.5 @@ -1694,7 +1753,7 @@ packages: typescript: optional: true resolution: - integrity: sha512-a7S0Sqn/+RpOOWTcaLw6RD4obsharzxmgMfdK24l364VxuBODXjuJM7ImCkSXEN7oz52aiZbXSbc76+2EsE91w== + integrity: sha512-ZUGI/de44L5x87uX5zM14UYcbn79HSXUR+kzcqU42gH0AgpdB/TjuJy3m4ezI7Q/jk3wTQd755mxSDLhQP79KA== /@typescript-eslint/typescript-estree/2.3.3: dependencies: glob: 7.1.6 @@ -1706,7 +1765,7 @@ packages: node: ^8.10.0 || ^10.13.0 || >=11.10.1 resolution: integrity: sha512-GkACs12Xp8d/STunNv/iSMYJFQrkrax9vuPZySlgSzoJJtw1cp6tbEw4qsLskQv6vloLrkFJHcTJ0a/yCB5cIA== - /@typescript-eslint/typescript-estree/3.3.0_typescript@3.5.3: + /@typescript-eslint/typescript-estree/3.4.0_typescript@3.5.3: dependencies: debug: 4.1.1 eslint-visitor-keys: 1.3.0 @@ -1725,8 +1784,28 @@ packages: typescript: optional: true resolution: - integrity: sha512-3SqxylENltEvJsjjMSDCUx/edZNSC7wAqifUU1Ywp//0OWEZwMZJfecJud9XxJ/40rAKEbJMKBOQzeOjrLJFzQ== - /@typescript-eslint/typescript-estree/3.3.0_typescript@3.9.5: + integrity: sha512-zKwLiybtt4uJb4mkG5q2t6+W7BuYx2IISiDNV+IY68VfoGwErDx/RfVI7SWL4gnZ2t1A1ytQQwZ+YOJbHHJ2rw== + /@typescript-eslint/typescript-estree/3.4.0_typescript@3.7.5: + dependencies: + debug: 4.1.1 + eslint-visitor-keys: 1.3.0 + glob: 7.1.6 + is-glob: 4.0.1 + lodash: 4.17.15 + semver: 7.3.2 + tsutils: 3.17.1_typescript@3.7.5 + typescript: 3.7.5 + dev: false + engines: + node: ^10.12.0 || >=12.0.0 + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + resolution: + integrity: sha512-zKwLiybtt4uJb4mkG5q2t6+W7BuYx2IISiDNV+IY68VfoGwErDx/RfVI7SWL4gnZ2t1A1ytQQwZ+YOJbHHJ2rw== + /@typescript-eslint/typescript-estree/3.4.0_typescript@3.9.5: dependencies: debug: 4.1.1 eslint-visitor-keys: 1.3.0 @@ -1745,7 +1824,7 @@ packages: typescript: optional: true resolution: - integrity: sha512-3SqxylENltEvJsjjMSDCUx/edZNSC7wAqifUU1Ywp//0OWEZwMZJfecJud9XxJ/40rAKEbJMKBOQzeOjrLJFzQ== + integrity: sha512-zKwLiybtt4uJb4mkG5q2t6+W7BuYx2IISiDNV+IY68VfoGwErDx/RfVI7SWL4gnZ2t1A1ytQQwZ+YOJbHHJ2rw== /@webassemblyjs/ast/1.8.5: dependencies: '@webassemblyjs/helper-module-context': 1.8.5 @@ -3197,22 +3276,6 @@ packages: fsevents: 1.2.13 resolution: integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== - /chokidar/3.3.1: - dependencies: - anymatch: 3.1.1 - braces: 3.0.2 - glob-parent: 5.1.1 - is-binary-path: 2.1.0 - is-glob: 4.0.1 - normalize-path: 3.0.0 - readdirp: 3.3.0 - dev: false - engines: - node: '>= 8.10.0' - optionalDependencies: - fsevents: 2.1.3 - resolution: - integrity: sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg== /chokidar/3.4.0: dependencies: anymatch: 3.1.1 @@ -3225,7 +3288,6 @@ packages: dev: false engines: node: '>= 8.10.0' - optional: true optionalDependencies: fsevents: 2.1.3 resolution: @@ -10999,21 +11061,12 @@ packages: node: '>=0.10' resolution: integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== - /readdirp/3.3.0: - dependencies: - picomatch: 2.2.2 - dev: false - engines: - node: '>=8.10.0' - resolution: - integrity: sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ== /readdirp/3.4.0: dependencies: picomatch: 2.2.2 dev: false engines: node: '>=8.10.0' - optional: true resolution: integrity: sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ== /realpath-native/1.1.0: @@ -12881,6 +12934,17 @@ packages: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' resolution: integrity: sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== + /tsutils/3.17.1_typescript@3.7.5: + dependencies: + tslib: 1.13.0 + typescript: 3.7.5 + dev: false + engines: + node: '>= 6' + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + resolution: + integrity: sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== /tsutils/3.17.1_typescript@3.9.5: dependencies: tslib: 1.13.0 @@ -14152,7 +14216,7 @@ packages: dev: false name: '@rush-temp/api-documenter-test' resolution: - integrity: sha512-xPShjp3CMqTNozpd0NQ7gszqAyFosMF30f7CXeVhG8uchtKyCTRxCWCSTybLNT7FZyYFgQ6IgzJYk8ZDPCPP2Q== + integrity: sha512-oSQHe/WAGn2pGDzHNxy/ebbHwgV5EkUiaHoDC5mFveZi/YbZt8DfhcFzCAIzP/7M19h4bhhD9dkmDencC/4Q/A== tarball: 'file:projects/api-documenter-test.tgz' version: 0.0.0 'file:projects/api-documenter.tgz': @@ -14170,7 +14234,7 @@ packages: dev: false name: '@rush-temp/api-documenter' resolution: - integrity: sha512-zZAUZWVAnR5l55npmqTmaJGdxA5c2mANCAjX/0063z3BYwjRAoeyFE4zWMzIal0QoGDwnV6l35P0NR448U4jBQ== + integrity: sha512-NP2auGxTmo90sgiJQaYfXT7rAr6LM//a9D2cwZOC8ll0AZrI1Zj7mkLiqGQzEkZ0E0qVqoM2RHbl4AeJqq4XOg== tarball: 'file:projects/api-documenter.tgz' version: 0.0.0 'file:projects/api-extractor-lib1-test.tgz': @@ -14181,7 +14245,7 @@ packages: dev: false name: '@rush-temp/api-extractor-lib1-test' resolution: - integrity: sha512-gi8v35mfZ1UjiRMMVrfqEvqWTlzwFk0+ShIsuznGPFXHQho0k7WLJXK1/PL9dG6Lud+pfwFtT18LKESMi+gvHw== + integrity: sha512-j4cGvRknTDXwBbM7rx7X+V62UfeTK9kAGkSpT3GpaZrRTwbtZhzPWyqY9lzw6tN43xlX/Iuc1g4FmnVDe1lqWA== tarball: 'file:projects/api-extractor-lib1-test.tgz' version: 0.0.0 'file:projects/api-extractor-lib2-test.tgz': @@ -14193,7 +14257,7 @@ packages: dev: false name: '@rush-temp/api-extractor-lib2-test' resolution: - integrity: sha512-IyG00gC1rU0u25g9CcxtzoxGAZOd271AXBjfyyBU6iXb4a1GTBafsDhmC6CyjeIe4IMi0jzmwjkevBGV4SYVAw== + integrity: sha512-d/guVZZpVbV7X0N8WYQfltz0frTUO/Al4vq73fb9AF22TcWTmA+lFxlc7bMuXi/UZNtmpkH/kJ27YCSbeCuMkg== tarball: 'file:projects/api-extractor-lib2-test.tgz' version: 0.0.0 'file:projects/api-extractor-lib3-test.tgz': @@ -14205,7 +14269,7 @@ packages: dev: false name: '@rush-temp/api-extractor-lib3-test' resolution: - integrity: sha512-qWYKmJAZMWzI5Lya19W4LflIxStoHG7gHZHWTIscAL8TSqy+d/PTZh2Ecea4PnB8vgPiRzGryae1m6cRv714tQ== + integrity: sha512-B3J22QVJJC5kWnBLgDh6XjcwyEwwFRKvdA43oi1wPCvlqLW6RTrH8YA2SJVAMNf3rVSYWJHnFpwekfeGuqJ0Kg== tarball: 'file:projects/api-extractor-lib3-test.tgz' version: 0.0.0 'file:projects/api-extractor-model.tgz': @@ -14219,7 +14283,7 @@ packages: dev: false name: '@rush-temp/api-extractor-model' resolution: - integrity: sha512-uFOBdEdczwM8LEOJ1KOKL4KePdBiK/ttx19crBxcCW4nEQb1/Or8/CXj1mkcZvrepI/d/PHUSS2Kx+6YSwggTA== + integrity: sha512-95livdaJE9QL2skP3yC8c+7rU6JIWBK+satYaGNMs9wSe6ls3thHy8l9w07Y2fyNdyoO2/ETvmFU8r/Dgm1aMQ== tarball: 'file:projects/api-extractor-model.tgz' version: 0.0.0 'file:projects/api-extractor-scenarios.tgz': @@ -14233,7 +14297,7 @@ packages: dev: false name: '@rush-temp/api-extractor-scenarios' resolution: - integrity: sha512-z6z6d06x4oGbWUh/k/eK90f7NcfbF4VmejAUZtekcCRg0QZdRTPmAkLmyHWzsz8vgl550XdojFPPXNWz8MR7oA== + integrity: sha512-dioxOVTQZgT+tuCvtcottdkiVTOvej/eLPIiz+W+vp71jbjzComxaKwxXokzw3XmvqIiW/HJajG55q+B0O+WDw== tarball: 'file:projects/api-extractor-scenarios.tgz' version: 0.0.0 'file:projects/api-extractor-test-01.tgz': @@ -14247,7 +14311,7 @@ packages: dev: false name: '@rush-temp/api-extractor-test-01' resolution: - integrity: sha512-gOjcaQLOaF/QOdFTRwAHSBCF3ybI7+oIqk6Rd0JtEtGO4BcPSqwnLHD9LX+zD3uGEWJziRs0BgeafQzWiZZOwQ== + integrity: sha512-gRBxDF1RjKcabsNcInRgWQ0cll2J0+XInXCpvuemXNl/oIRBPDbB6R8Hhfm5q7mw5mVOympHX9fRSnTeIw9fJg== tarball: 'file:projects/api-extractor-test-01.tgz' version: 0.0.0 'file:projects/api-extractor-test-02.tgz': @@ -14260,7 +14324,7 @@ packages: dev: false name: '@rush-temp/api-extractor-test-02' resolution: - integrity: sha512-c71KlFtuAIrZNTr3xpuGeSKiKZ4Hhr79zGIglstYRp0psjrK4RD1ZF5kT43gQ3GoNBKBIj2TBkExudN+rDlbjw== + integrity: sha512-0APEr7rC+gvyoY3jlfwSCSeIDAAQ5KQ3sq1xZR1/7+hs1ikzbjAVN+kebcnlCkANm28rXePFOKceUPQ51tFW2Q== tarball: 'file:projects/api-extractor-test-02.tgz' version: 0.0.0 'file:projects/api-extractor-test-03.tgz': @@ -14282,7 +14346,7 @@ packages: dev: false name: '@rush-temp/api-extractor-test-04' resolution: - integrity: sha512-xEYRuLo3KBPCTEvhyyALCtUfUTezX1HrxOdft9O3DACXsBawFHPVqZUbnN6IwISU9wuPl0p4jB0e9mzYvWpcxw== + integrity: sha512-JwMGU3lYK4vjLm/0SnnM632y3lJNxBALjTcjnNQGVaT1DbLUS7wNWit9PM+cG7Wf4RUxxsRnLYLgEYVv12/SnQ== tarball: 'file:projects/api-extractor-test-04.tgz' version: 0.0.0 'file:projects/api-extractor.tgz': @@ -14303,7 +14367,7 @@ packages: dev: false name: '@rush-temp/api-extractor' resolution: - integrity: sha512-dWZrORWaZuwFZRqm0DsNRMgwU/oWDr+L/G7Rq/uhpZkk3z8t1BhpfRhL2Z51IpCOapi15rm4fseal7gSGyOktA== + integrity: sha512-0Hc/hnyjcrx2L8a6Ff0ovcb+MogtCyyzeE4q8LgN6hjzAP1Yn3DKh9k3LVSJNOuHNR5j8Ru9OSnFgR+lI8FITg== tarball: 'file:projects/api-extractor.tgz' version: 0.0.0 'file:projects/debug-certificate-manager.tgz': @@ -14318,7 +14382,7 @@ packages: dev: false name: '@rush-temp/debug-certificate-manager' resolution: - integrity: sha512-IvSBa1p0MZmX/znNDbEXovD0pXQDLvUpjDg13z0b9zNzOph2gGir0RY2qP3HoePFbhO0mCPkB2BfKmElFV+LlA== + integrity: sha512-RCmD4L/QRni3fAbW7QQIZWxgQ2BxCoaMBHhJNl+MN7Bt4mBZ7jZf1770fNzTba8TTXpq5RasjUU7ihGEL7qsOQ== tarball: 'file:projects/debug-certificate-manager.tgz' version: 0.0.0 'file:projects/doc-plugin-rush-stack.tgz': @@ -14331,25 +14395,25 @@ packages: dev: false name: '@rush-temp/doc-plugin-rush-stack' resolution: - integrity: sha512-67rl8eDnQoRJyBiS5rVmOILtlE9uwD4KhAzE9hegqlvvescIkZdnbDk/WpjvtwPpt5MV7AbFr3Qd0YXuB5XHPA== + integrity: sha512-N6qFz5WIhWV7dvh2FWM8knYWOx7AHQHg8LYJWTTXnfWHeJx74XlKiK+EzVYmOEMNXKCFj8ihIvNmUMBNZpUlzw== tarball: 'file:projects/doc-plugin-rush-stack.tgz' version: 0.0.0 'file:projects/eslint-config.tgz': dependencies: - '@typescript-eslint/eslint-plugin': 3.3.0_5230966e5e0a36b5cf15b6a6401aaf8c - '@typescript-eslint/experimental-utils': 3.3.0_eslint@7.2.0+typescript@3.5.3 - '@typescript-eslint/parser': 3.3.0_eslint@7.2.0+typescript@3.5.3 - '@typescript-eslint/typescript-estree': 3.3.0_typescript@3.5.3 + '@typescript-eslint/eslint-plugin': 3.4.0_43170e314695d1b0876b4d3c3574f4a4 + '@typescript-eslint/experimental-utils': 3.4.0_eslint@7.2.0+typescript@3.7.5 + '@typescript-eslint/parser': 3.4.0_eslint@7.2.0+typescript@3.7.5 + '@typescript-eslint/typescript-estree': 3.4.0_typescript@3.7.5 eslint: 7.2.0 eslint-plugin-promise: 4.2.1 eslint-plugin-react: 7.20.0_eslint@7.2.0 eslint-plugin-security: 1.4.0 eslint-plugin-tsdoc: 0.2.5 - typescript: 3.5.3 + typescript: 3.7.5 dev: false name: '@rush-temp/eslint-config' resolution: - integrity: sha512-YiSMlB1XCVv2QmC3jJB+vHjgxKe13BH7hFQiS/SSS9eyZG8Q40lhiipmdcEUW+WxH3X/G+6dJ6Oi66TfvZWLkg== + integrity: sha512-H+s2zdOcBIg3B1N8O0Q3TmFw8NupN1WXzV0utr+RPxb5fkiXxLydV7Pkhyl7qohEnN2hyvauS7A3LEahTcQzVQ== tarball: 'file:projects/eslint-config.tgz' version: 0.0.0 'file:projects/eslint-patch.tgz': @@ -14372,23 +14436,23 @@ packages: '@types/eslint': 7.2.0 '@types/estree': 0.0.44 '@types/node': 10.17.13 - '@typescript-eslint/experimental-utils': 3.3.0_eslint@7.2.0+typescript@3.9.5 - '@typescript-eslint/parser': 3.3.0_eslint@7.2.0+typescript@3.9.5 - '@typescript-eslint/typescript-estree': 3.3.0_typescript@3.9.5 + '@typescript-eslint/experimental-utils': 3.4.0_eslint@7.2.0+typescript@3.9.5 + '@typescript-eslint/parser': 3.4.0_eslint@7.2.0+typescript@3.9.5 + '@typescript-eslint/typescript-estree': 3.4.0_typescript@3.9.5 eslint: 7.2.0 gulp: 4.0.2 typescript: 3.9.5 dev: false name: '@rush-temp/eslint-plugin' resolution: - integrity: sha512-iGDW1jWZJeDSXGm0XKxUPtHqGL4wpcZHeNHf9TIcBSqj61dwvWiLJmHMpGQjSbBCLC2HEnuR/NJM2MLuyn5sxg== + integrity: sha512-bcprX3VHw98dLdej4H/pTccDUJ5R0C5F9+n+FyeO8J6DPY9aixf9YOR3rAQrYdeQuBkXUDp/nDp9CQwNp0Cl7Q== tarball: 'file:projects/eslint-plugin.tgz' version: 0.0.0 'file:projects/generate-api-docs.tgz': dev: false name: '@rush-temp/generate-api-docs' resolution: - integrity: sha512-EdMtO2cbdAOc2YMasycDyYvdhF3hVXEITM0q4W300CzRuoo18ygd4Fd6jFq+gv4r4WUuHABR/v1uhNZFDYMeig== + integrity: sha512-kYuy0KhmbVlRgzysnD3WPVUVnWCIELSGDkiyY9ggRdvrTAbBacjYEPbYp7qep6BXAzdqd7eDPuWv6e3mzwvVvg== tarball: 'file:projects/generate-api-docs.tgz' version: 0.0.0 'file:projects/gulp-core-build-mocha.tgz': @@ -14409,7 +14473,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-mocha' resolution: - integrity: sha512-r5zagOwKFMJIT08EmGOkouD3RBbzBjoMQaj+DH0BuhrwtnF8S0O0LVmvCbZtSnss1x/QsibTt0xILNBZJU9BUQ== + integrity: sha512-Xqz8CqQ8rJ5Xw1N2Ip4kOg0upYTuCVl0MbXWBfPWoEyTQtM7mDjoRwD+x20X+7Cq/CkXxkm2TxLBKDN8GSO/uA== tarball: 'file:projects/gulp-core-build-mocha.tgz' version: 0.0.0 'file:projects/gulp-core-build-sass.tgz': @@ -14432,7 +14496,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-sass' resolution: - integrity: sha512-LP8ALd6fp6blk8Fva7axAFB9M8T5YPjcnbYfjnNFfZPh3C8tQZKvSEFeKVR5oEv5t37zLZ5NUgIyEsdD90DJyw== + integrity: sha512-Mlna3VhrcK35LdQBockrHzexTwQj1LnjHrL+vlhi70m9UcCgrXSucynGMPNvGDHCv9O0mUC2O/XIFoUXdf8eeQ== tarball: 'file:projects/gulp-core-build-sass.tgz' version: 0.0.0 'file:projects/gulp-core-build-serve.tgz': @@ -14455,7 +14519,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-serve' resolution: - integrity: sha512-JX6RAbeJmH0AJ6VF2m1ieATu38qlK70vznNv2YkvDrMlmxhuz5PxdqAxTYLeComn9OitBe8H1b2i7RWSOlBGiA== + integrity: sha512-EcDZupb0dv3v+0Yve3aVwNEK0amNhR8o7nwaVOx+gOxhxXdUW1D2gv0ekKomJhO+m2xnWngGiCIY4qBGQlnwPA== tarball: 'file:projects/gulp-core-build-serve.tgz' version: 0.0.0 'file:projects/gulp-core-build-typescript.tgz': @@ -14474,7 +14538,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-typescript' resolution: - integrity: sha512-oO9VkOSKzCx3QaO7/qMzJN4mIpaSPWzkfPCnHoJ62xTFGN90zKcKVS8Wzwmg1i2mqfnJW4jrDj4c739dRn+GOQ== + integrity: sha512-6wSeAy3PrwsXxBCmWnAtqK/xVuu40Nb42vQ/ym0fQ50mTTRDB6qhTgY+Yl3wseHBtf4UvVX8JaZExsaQdLhqqg== tarball: 'file:projects/gulp-core-build-typescript.tgz' version: 0.0.0 'file:projects/gulp-core-build-webpack.tgz': @@ -14492,7 +14556,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-webpack' resolution: - integrity: sha512-7DHcxPmoDQGDoYgf9PPuclHNPLb53GUC0aa+Dz64CxGizUkn0KU9Mqi8hf+U5ugMqZgcMzvVY0ol705k8x1fBA== + integrity: sha512-QC5XgdjN+DvNrs3GkM/txMlLSL+cWXdSrVyr4x4VKCaZtTUrdePomtnC0EptxRLIiDHdkP7L8kPxcJi5uGE69A== tarball: 'file:projects/gulp-core-build-webpack.tgz' version: 0.0.0 'file:projects/gulp-core-build.tgz': @@ -14545,7 +14609,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build' resolution: - integrity: sha512-5o0TF4Ez7ENV/IUGiohZvOsOVIRvx85zyaPMvjZy7uulFvy8ufKUgoZhAI48kXFQjXPE9mOV+U5mRYuxa9QQ1A== + integrity: sha512-shYhDXfrdXxFzB3H50wpPM4iY/a1ZU98Xa4g0CKrgwjbwyG+r+trVasnkN7taRNxLF2uFs5b/AHrIh48AzYwoQ== tarball: 'file:projects/gulp-core-build.tgz' version: 0.0.0 'file:projects/heft.tgz': @@ -14554,13 +14618,15 @@ packages: '@types/node': 10.17.13 '@types/resolve': 1.17.1 '@types/tapable': 1.0.5 + chokidar: 3.4.0 glob: 7.0.6 + glob-escape: 0.0.2 resolve: 1.17.0 tapable: 1.1.3 dev: false name: '@rush-temp/heft' resolution: - integrity: sha512-vJ9opGwFd5jjMaf0dRPg1RDUMK2LuRVOzth+eOem1aG4uFw/9bbDcIkr1KUyP14z1Sq9hc/MQFKtVmND8a0Y6Q== + integrity: sha512-oqxC8xYIHFYvP9Z4oGlnsIgaQYrG+0s3Vr/B4wP/pj7GJtl6h8+lhh2PwI0OzcpsOr3IebO5P1TMnXsM1iqZaA== tarball: 'file:projects/heft.tgz' version: 0.0.0 'file:projects/load-themed-styles.tgz': @@ -14574,7 +14640,7 @@ packages: dev: false name: '@rush-temp/load-themed-styles' resolution: - integrity: sha512-Yf0DHJF1N+ymVmX/r3NJDpZNKsCOPvtOvPdzASM4xo1tFepqGeuzD0BoK0KpsXz5REiZ2haSicwUYfyfGqA7hg== + integrity: sha512-01vIZKCCPY6M/uPP94vTdUGrFllQ7PFfmmdy/mY8oGDwETMqhahB08al3DizNfnf4mGCuWbvogPd3QvpLHQqlA== tarball: 'file:projects/load-themed-styles.tgz' version: 0.0.0 'file:projects/loader-load-themed-styles.tgz': @@ -14590,7 +14656,7 @@ packages: dev: false name: '@rush-temp/loader-load-themed-styles' resolution: - integrity: sha512-p4TOB+3wfySAQeAZknsW7mX2I8sZAKcxtq1MVOulih9t41GA991OGiOCZfGF2nQrGvCFFK9i8H26mR2hB8Y8pA== + integrity: sha512-p7Iw5IsjI2eu+A2NgaOiqndBPJ46DHdd/cpykA7DoS8nF8geTM6/74DuTnAWRzrVSbbEHT44+04zCeMZeu9Mrg== tarball: 'file:projects/loader-load-themed-styles.tgz' version: 0.0.0 'file:projects/loader-raw-script.tgz': @@ -14605,7 +14671,7 @@ packages: dev: false name: '@rush-temp/loader-raw-script' resolution: - integrity: sha512-yJrch7k+buHOl6UFsDY+DjgV92AJmEr5E4J2SlC5yPNcV8pBQHrBDdimavO82XRdkOVmIPtWRPgL6zLum/J24w== + integrity: sha512-g0YMLdY/Df2nQnUg3tP4osBSxrXDliwTFR8sD3qw5wrh7xtuF2JhsUXjMMeheAe31igxYUI2mYhPIsTUnDi1YQ== tarball: 'file:projects/loader-raw-script.tgz' version: 0.0.0 'file:projects/localization-plugin-test-01.tgz': @@ -14620,7 +14686,7 @@ packages: dev: false name: '@rush-temp/localization-plugin-test-01' resolution: - integrity: sha512-Gz89FBD3tp2YeGik3bbt/r96RSW3RxlN58sAsrIRZZov4RMfeq/McfWT6kC6JMDAbJlSYCmkuKeoN5ySOwcymQ== + integrity: sha512-T1h640rfmZr9IjXFfJU79OBnKR24s3d/T63izdP7l5QQSx0+ypQ3nZJX8cNK1LbuFPto31C7A0vcf/RjbM5j6w== tarball: 'file:projects/localization-plugin-test-01.tgz' version: 0.0.0 'file:projects/localization-plugin-test-02.tgz': @@ -14637,7 +14703,7 @@ packages: dev: false name: '@rush-temp/localization-plugin-test-02' resolution: - integrity: sha512-dGZN+v0pir0xAJfDWD8RrNzaLUf7Q+ap52M8kX/3WSc8o4A/IM+1VGhC2mDCOoTWGFqnV+l85hyFJYsV4WnkpA== + integrity: sha512-oI6y8e286Uk1W1/153DjcpIWF+0hSST/JhOxzG83DI7SVNN49k/VWaM4YAXXmGe2WdhUsQDqh8sopm0HAhNq0w== tarball: 'file:projects/localization-plugin-test-02.tgz' version: 0.0.0 'file:projects/localization-plugin-test-03.tgz': @@ -14652,7 +14718,7 @@ packages: dev: false name: '@rush-temp/localization-plugin-test-03' resolution: - integrity: sha512-fddgjDB89amP+XGWvRjSYn+pvw37w66YPNXEf5qm3veACqO6mAxtksJrm+/SG/XjCsCwIsSMdFonYr1SLqm+mg== + integrity: sha512-1FZYUFCd91HyzzVV656MKZS/Pce9++sM5L6NhXZmKzFfKsDwFWhD3TbruN3L7qfDJ4fEAH9m64hVgYLcjA6Biw== tarball: 'file:projects/localization-plugin-test-03.tgz' version: 0.0.0 'file:projects/localization-plugin.tgz': @@ -14673,7 +14739,7 @@ packages: dev: false name: '@rush-temp/localization-plugin' resolution: - integrity: sha512-Li3TTe8AaM1T9XSURG9Jy0LrSAQ5US5lywbNogPs2Ds8Zpt+KxBikEkv9gzXkjGYAWCtwmokbIMS5NbqvL0FdQ== + integrity: sha512-NGBE5WLIbTDgzylanE3T46NtyiIzG1HhUKNIDwpmVQy8ZxD+IIqeWNHOM9utBEz/KzBVBMuKlfPg3vl+gOxMIw== tarball: 'file:projects/localization-plugin.tgz' version: 0.0.0 'file:projects/node-core-library.tgz': @@ -14697,7 +14763,7 @@ packages: dev: false name: '@rush-temp/node-core-library' resolution: - integrity: sha512-MGje/6vNJ5aSHtLTE/d9S8VTRLewrMbhrMWrRR9XeoQxgpBnRUmdSL0z2mt7OA/5SF6qKt/C/5g2m022Ou6ijg== + integrity: sha512-RDJ2BrVdYldUKa5lXoSlyBooJzJJkNDEwRBBV4q4XxFzKyHKvctWBt0UQasKrxywPvMq0FcfJtf8Wp88iYKXyw== tarball: 'file:projects/node-core-library.tgz' version: 0.0.0 'file:projects/node-library-build-eslint-test.tgz': @@ -14710,7 +14776,7 @@ packages: dev: false name: '@rush-temp/node-library-build-eslint-test' resolution: - integrity: sha512-H5dimoozdurJLKJAlmR/QgvE4Oac8+DqxRoOKIyLn/lUy6VViV5w+M/Rf2J8oYh898RUS0BIKa8zswnXsO+kKg== + integrity: sha512-hOP/rEc21giPwlkAXL9oMWM1kWDOwQfFbucvUvwFtnIvwRW5BU5hwfLUpLsjgiC5tQ1XBCLFojZqoGY8G9vRPQ== tarball: 'file:projects/node-library-build-eslint-test.tgz' version: 0.0.0 'file:projects/node-library-build-tslint-test.tgz': @@ -14723,7 +14789,7 @@ packages: dev: false name: '@rush-temp/node-library-build-tslint-test' resolution: - integrity: sha512-QbDVKOK6Wk1xXCFs3TC25g+R8fJqVWw1kv6mPfmKpdJ3ohzjBBV+FV+XQ61Zes2ReWP7xLUFNZVpnQ0loeTUWQ== + integrity: sha512-OSj8uA034CdrDT/08Nlptckd168hDytKHXXXUPAXQ6QiMBfKm8Z2g577vZyH1lfE9WWK9yRpVljs7+7DtFIMWg== tarball: 'file:projects/node-library-build-tslint-test.tgz' version: 0.0.0 'file:projects/node-library-build.tgz': @@ -14734,7 +14800,7 @@ packages: dev: false name: '@rush-temp/node-library-build' resolution: - integrity: sha512-bfyal8ttTMbaHL8CDzfisVkILcsdKXWMcgWsis+x/TkL9le1XVygP/6iIVGmRu5/In7aeyDfRrPFcH+Zbmv6Yw== + integrity: sha512-3x3En+KDCO8RFVxwvrzP614SP8nUTc9R/5eAfUC5Gm0mzmLZaNHBFOXHANDWvbM6nCH09p7hK2QXmu93wHcw1A== tarball: 'file:projects/node-library-build.tgz' version: 0.0.0 'file:projects/package-deps-hash.tgz': @@ -14748,7 +14814,7 @@ packages: dev: false name: '@rush-temp/package-deps-hash' resolution: - integrity: sha512-Lj0sEKoxaNfD3wyhE0Gg55i/0b9aXvkKBHPNirPiDn3AeB0mtlDH/vCAQ1mSzJVGuAwD7UUjw0qysQTz49bNsw== + integrity: sha512-HvlJgTBK1wsoSq697epvJWYsuF0tu85yD+IXlBqkc77oub2YgpjP9An3CNxo7Kvm+FUnYCq3AoJFn62MVjgTSA== tarball: 'file:projects/package-deps-hash.tgz' version: 0.0.0 'file:projects/repo-toolbox.tgz': @@ -14758,7 +14824,7 @@ packages: dev: false name: '@rush-temp/repo-toolbox' resolution: - integrity: sha512-He9VmESCwDZ85Mxyfl1BSjh+ZGhTHXbhp8l7u6nZ8WgLrYSkkEfy0abzPAohWGTrtftHijK191QgCEwQ03aStQ== + integrity: sha512-F7usln44ENLWV3PAM/qS8efUFWy1nvu2TiU/S3SvEiptO4xG1cobMQ0jXCc4SrFRVBdRVPjzC3HmtCsZIzQKWw== tarball: 'file:projects/repo-toolbox.tgz' version: 0.0.0 'file:projects/rush-buildxl.tgz': @@ -14769,7 +14835,7 @@ packages: dev: false name: '@rush-temp/rush-buildxl' resolution: - integrity: sha512-H2yEXGCk732wAS2draTBfqWKaSZOS9CAQVHarzWLd3yceZ4NSvsEJLn+/oxtFrFmdIYnOj+dphihUtvpTErxNQ== + integrity: sha512-VpkPux6A6n/Gzljtfsrd9Z7YGvUVTYiBkRvC6a7SKcLkiggLNFOX6R+6OSI7jhCHmLKi+I0+4jJNQ+uxuL0Ckg== tarball: 'file:projects/rush-buildxl.tgz' version: 0.0.0 'file:projects/rush-lib.tgz': @@ -14821,7 +14887,7 @@ packages: dev: false name: '@rush-temp/rush-lib' resolution: - integrity: sha512-MY1rroOMxQHuJTExNFwTiz7V5U+YtcvmdRKZycUd+Y793Ew0DsOCvHL2EZA5rrraitzuivuFZZKmbDX158g7WA== + integrity: sha512-PHze32ux9+k3o8RQKhepW4OrPQXOVOvhjC9tG0JrJdTuzIcqpycFG0xQQJaJDm6wzbn/H3iuLhUxA3AXQGRfLA== tarball: 'file:projects/rush-lib.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.4-library-test.tgz': @@ -14831,7 +14897,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.4-library-test' resolution: - integrity: sha512-vEtfkpGJDydXvzQeQgxigFVSnsnTaGtWzbgeoCzuVooYf2Np1d0YEopxGjdc6lEk+/W1UTOr0axeyARxq7CLaQ== + integrity: sha512-4VhQoGUInk8shJLdM6lCb9GsOll3oWH4OcJVQ6cAwgK6YKdFb1eH23Tw/ZooOeb6MxnUu7fLZV2vYLZeBGWieg== tarball: 'file:projects/rush-stack-compiler-2.4-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.4.tgz': @@ -14848,7 +14914,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.4' resolution: - integrity: sha512-2u4kMMgfm6QZ+bhQJHnrt4TsHnrkqza20u5uA5t5tGFRVRndhYSVG+nNGFEw6EpsMmQTbhyuH/s7godEIhBC4w== + integrity: sha512-hG1r5yVDkBfx71HPn3Mev3yLwwOW95hi5Lr252mIkJnm+ahdIWalooVao0FD7iobjbBSDiLOHTytiJU4B32Igg== tarball: 'file:projects/rush-stack-compiler-2.4.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.7-library-test.tgz': @@ -14858,7 +14924,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.7-library-test' resolution: - integrity: sha512-ei2oKEmYe2F9vQ6eri8gshc7Gv9APqJGkzCHRwWN1cVfD90lYMu1QcjlmYPs8VHGhLtWKaTsFrC6xjh4cZWupA== + integrity: sha512-srXLgtPwX+/ohQ8xpWKCPF8QbMBuNpSyG35DhKK3KhrMOhcgjT391Hgk1x1WIeZQtV5PlPphoc3VNqO6ouZb6w== tarball: 'file:projects/rush-stack-compiler-2.7-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.7.tgz': @@ -14875,7 +14941,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.7' resolution: - integrity: sha512-DgIclv7qN6x0/JtVq8wUIxdWCC229x7WrEOubw05fyWemmcfWSKtts2WXlZrRsLqu8xXZhI7o7eMxlbKXAEztA== + integrity: sha512-rMrR8wum1C9L+d3rTjiWk6XCec7lVJvYiaHhjIXtTd0ES4dLdosgCia3uq9ajD0+NToY4QAAwoq+Y+gsTaT+3A== tarball: 'file:projects/rush-stack-compiler-2.7.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.8-library-test.tgz': @@ -14885,7 +14951,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.8-library-test' resolution: - integrity: sha512-XkTLBTH5WYLV+KxS1fn4Z7cWzu0lWu4PnGk6d8hp9+sd1NwAf45YVo+TwJ8H422PIZCm4h1TkhD12pcqFLYONw== + integrity: sha512-AXRaABTMx4u38YP67laQmqB+9Q5nLVnxAzQgC3Tz2ukUtg7VOwW78aSbJS6tWi6r40koxf0kjza1xaJys/LbEg== tarball: 'file:projects/rush-stack-compiler-2.8-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.8.tgz': @@ -14902,7 +14968,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.8' resolution: - integrity: sha512-abjnIbLrSv00emrPGaycjyEjBZDBuMhNn0d7NsxnZ675tLZtR3s+SfMZk5Po2h+Lv1eXgyUgU4c07ZZcGI4sow== + integrity: sha512-BgpuKWwcQsUPz/CnVlSa5I0RCHt14HtoVDsxSgts+OftigNAqwbYDS+bLIIaPH13CVWJj4hXkY+8SVUGtBtHpw== tarball: 'file:projects/rush-stack-compiler-2.8.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.9-library-test.tgz': @@ -14912,7 +14978,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.9-library-test' resolution: - integrity: sha512-Zyl1Uyhk5+eTGnf6QPid80qRCcPqrEW+ZqWRVn+E+YRHuk/wvKyJe+AmK4c3toIRm5ufkdBb/OQIosBOIwINeg== + integrity: sha512-COU64dI/gxMf5Fde2Hpk+XCkcB64qzY47rIJ9qZWTp7b42rEPkqBZCCmOvdprCV1QRXezeY+E+SYSxirN/1f/w== tarball: 'file:projects/rush-stack-compiler-2.9-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.9.tgz': @@ -14929,7 +14995,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.9' resolution: - integrity: sha512-OUEqzQUeXV9w0+I3eFdTkjt4jaUp4S7bDE7Rtp4Hq7mjjd6Cw+sMzVVAwnQmViuYyr1iH2P/+FoCVb1FeNee7w== + integrity: sha512-Tq6IFsZBQvwJfaRARpw7a51TXHUlPeHJT2MX69eXN1vXQQWle9pIoSpq4iQS5CWy7J8f+j2honpUy6DpuCEzlQ== tarball: 'file:projects/rush-stack-compiler-2.9.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.0-library-test.tgz': @@ -14939,7 +15005,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.0-library-test' resolution: - integrity: sha512-862U2HfyQ8n+j0YWrwY96DfbBH1IUfPoJrw+Tr4sYws2OftDUtFkADqv+pWLbkkY9B7YBsrNjLviKJ+jB21VtA== + integrity: sha512-KbHGX9685/56jgLK+OXEphJa7PATxHNUrmNadMkKFTejTky68+PqpqZd/aV9HPC/XW+TuHwH5/vYq3Ih5tUXDQ== tarball: 'file:projects/rush-stack-compiler-3.0-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.0.tgz': @@ -14956,7 +15022,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.0' resolution: - integrity: sha512-02CucPcTZ1sVaBDLP0IXaA7Mn8wq1Mrrgtdqp0lncIpWIcawjFn9sTDp0X75qJfhioxmW0z+1BYG8mrytZ81jg== + integrity: sha512-vMLB2XFdd0LGxgFcllFuQSvzzwXn6TqFdmb4xeki/2mSbYZku1AQaV3a8IWybiX59Xh9XpPanNhMsuu0iqiNog== tarball: 'file:projects/rush-stack-compiler-3.0.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.1-library-test.tgz': @@ -14966,7 +15032,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.1-library-test' resolution: - integrity: sha512-+miwHsekIONtsPn9ZwXUIOmreG9i24ERtOmqtf+iZQ8CyxQRMtMOs2IunirwrppHUbQAQ5TMWtztBHCALGQkBg== + integrity: sha512-FdL2pswO0WrPpMYll+E3Wg2TA97tOm7wFPOklI+Z+Y4Zw8FuGO7eG0lRMC76skBwyeaM7K/ZRYcX8MFQWvNBJA== tarball: 'file:projects/rush-stack-compiler-3.1-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.1.tgz': @@ -14983,7 +15049,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.1' resolution: - integrity: sha512-YmW5vnSMzKeuq5iP9golciP0liwNUAF+A0cWQHugIfmTKUyj7qBFXUHCi1tJnh08MGz96jFFx59XXH8x0n3K5A== + integrity: sha512-/ti1UbntA4cFzQr0ZgG9rqUIQXqNGydcjmhMXpn/p9hEjZaQdJ/R+xTCQcwt14vLiaXZqkwziad+cDM2GAQyKQ== tarball: 'file:projects/rush-stack-compiler-3.1.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.2-library-test.tgz': @@ -14993,7 +15059,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.2-library-test' resolution: - integrity: sha512-Mdrm5KwuT5jEY8Tgrka+upc2kfIK3LEH8inc8XSaoDLGW0DvgQdcyaogBBnjTR4SzFtDnG/xzF1akXLeWjFkEg== + integrity: sha512-aniHkRDpldzVnHxvrXBtXjbAHxh3swMCIo9vEnB0hHw9FFFUdFWxKVowmAj4lj7os2cLgimq3URLfom1k2kWzQ== tarball: 'file:projects/rush-stack-compiler-3.2-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.2.tgz': @@ -15010,7 +15076,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.2' resolution: - integrity: sha512-uxteVLfkazD+6nEcqUlHcwLJEgXQ/qAyniTmPBpO4FOrJW+akphLyB+ot2yEZVNFfIlZpDlBoV7IdZWU3E2o/w== + integrity: sha512-cU/RSNyebjIUmJfbnWZQW96KoMAFKEFtyehPVguTA9vSalA+kTfFAQ9gkGwlmCQ3aTpM4f9z3VJgew/4QM2ifw== tarball: 'file:projects/rush-stack-compiler-3.2.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.3-library-test.tgz': @@ -15020,7 +15086,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.3-library-test' resolution: - integrity: sha512-phW34yARVqS3nP3QhY8QkdaUl7v1HuYVRhFOxS7LUZDnI37eCyM8Zotqvs6mLWMU5ykWnfd4OzSed6Ubots02A== + integrity: sha512-efsGPnFV/RsutIBBRgyLx2Zq0C15rNtxN9lY6VJXhS5CA8wPA0H9MrIxDrMZo4t4Slxu2y61XMYbU6J/opelXw== tarball: 'file:projects/rush-stack-compiler-3.3-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.3.tgz': @@ -15037,7 +15103,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.3' resolution: - integrity: sha512-7e2S7uwrVKaCJOqD8cONo+EtEzjhytnX7nxoZoTzQJxP+S3MrgYuN/DABNf/ffNIo9OMock6CPf9BuwFlFcEvw== + integrity: sha512-b7NF93lucZ3408ZIizqdda01HqEGoFbaDrGSf89B6gN1i88WrrXoQ2K+17v+vc4dLY32+HDM0mgw6xy8rYCMVQ== tarball: 'file:projects/rush-stack-compiler-3.3.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.4-library-test.tgz': @@ -15047,7 +15113,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.4-library-test' resolution: - integrity: sha512-tILR2VCYYTTVc8srHOxz+3vLpyjWCeQNwZnGkJXFtwrgMbje9cq1cJVRp0rQY9yQwJ2v4U4HFrzdVrIf6hPIfw== + integrity: sha512-R4TRjNCH5A+ER7bucWPT4+NlyD6MFumjSrMak2KLYDg33KXbJN051fzieqJQoltfNHGkQDIgXCh/6qZR8OFISg== tarball: 'file:projects/rush-stack-compiler-3.4-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.4.tgz': @@ -15064,7 +15130,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.4' resolution: - integrity: sha512-BKmp2cuXiWypxYZ/u2OOi5JmH7wpmW0C1rFNlcON/qupOZqQJVHk68OY1dE3GcvbieYN7db3oAvl/Dp9Wakvug== + integrity: sha512-LdDJIHD+jg+T2JsfdquoatKkxL8hHnH6Tt/1IcOxku7ZIqTWpFeQ+g3Et5eGQ99ki33u2jN5zCLijR3NPGQYxA== tarball: 'file:projects/rush-stack-compiler-3.4.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.5-library-test.tgz': @@ -15074,7 +15140,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.5-library-test' resolution: - integrity: sha512-V9ZgxNxuccf0p8JZxpPkU/ht//HbTFXhvSBfirfDSN37FiqvPJkc+AEbdbjzDbeK/hqnsm1OEZP82luE7cdWwA== + integrity: sha512-fyZKZsfcBG+y2FEzqfVyMgykQf6OceXQ9nGviE6WAwKBtz0Q0+PMPIYUuUmYDLXwSYaDSr5teXUk1rcva1vSag== tarball: 'file:projects/rush-stack-compiler-3.5-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.5.tgz': @@ -15091,7 +15157,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.5' resolution: - integrity: sha512-Jl3P0UMFqTAA9Gy+z8eNvQ4SthMzlKEf4FCaCpVy72cwHJDaZbj13WWpobmf3WYKFEvy49veC9f2ucmwBM4dfA== + integrity: sha512-JTxecGPqctAodYS7PndNd7oncQ5bk6WTx9wxIjLnm00BG0mvPcksngOEQ81GT7c9Gi65S3OF6/5tZpN3Yf/ADA== tarball: 'file:projects/rush-stack-compiler-3.5.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.6-library-test.tgz': @@ -15101,7 +15167,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.6-library-test' resolution: - integrity: sha512-lDRf3c807YzaPWjpIGvxqZnA1NVQzhqiBkP2Rq6kTS7Bx4shpMyILjransKJsT5nNGtyTA/Y+ARTOSbI6sTK1Q== + integrity: sha512-8JdP1KV8bF0cjH6CORh+D+dRzW6ekO0TTFpEdcysnR/eUcDcNlDYhyifOqymkp/xfsCB8zRZh2uwi51N5v4P1g== tarball: 'file:projects/rush-stack-compiler-3.6-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.6.tgz': @@ -15118,7 +15184,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.6' resolution: - integrity: sha512-bHtrtA9lrfoLBJy72sx8arVUYNSeUlh+FOwISQ5aS/OAQGuIMu6RlXxxzfOoK1EoGfrjvkRPdl4Wz65T1imnUw== + integrity: sha512-+2EQQ8/YMqzqc/bi2CiUwpQnKUpvGzTepNtVdtodO+zkUy5fLElf+5nzmet3dPEWCreR1pAc/ce16MHE6qVTnA== tarball: 'file:projects/rush-stack-compiler-3.6.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.7-library-test.tgz': @@ -15128,7 +15194,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.7-library-test' resolution: - integrity: sha512-HqWRokq5BdOC3xzofbfw/vtHqZJm1vl1tuZe3vJGlD7q82gkn/L5PYYQng9tJOWujlgVMm0BG9fAJmLlcUWyVA== + integrity: sha512-s4Sh6RDfa/jml/8XxxYA2XpGSHZubZGnFtiy+nYuzUyKeqlZITaZ21lmK3/SMKBrvFhLRHsopk1YdWFPARRVhw== tarball: 'file:projects/rush-stack-compiler-3.7-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.7.tgz': @@ -15145,7 +15211,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.7' resolution: - integrity: sha512-5nQB/tO5Ek7pljMcFu128hIQHK2c6EzzeAKBSumUW4UdMMzYa/3ZQs1y39ekvfIJ0YKvya7MmMjTvtiEvSa8rw== + integrity: sha512-rLsIDtuo9SRh3D64477T1JQWJ+xgK4M9PU1MDaK46iAWNyAjohUcKSaaiAcSROfgthWtWRMo/bKOIJ+nDwFAlQ== tarball: 'file:projects/rush-stack-compiler-3.7.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.8-library-test.tgz': @@ -15155,7 +15221,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.8-library-test' resolution: - integrity: sha512-uvh/8A31sF4IR1VNoL5/8DeUFTJxZLOIF5AAxiPnZeu/57zuZFRnJSYHU6fj1PaF43lbOwEj4UY+QWJpNHWLuQ== + integrity: sha512-2SuQ8Q166CtI6gUn4EDk4noGJvM1z3Lf+S9T2Qdeq9U/2phIXbdvlvDU3Uas6HmCIfOazBifOz+Kg2K/r1uN5Q== tarball: 'file:projects/rush-stack-compiler-3.8-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.8.tgz': @@ -15172,7 +15238,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.8' resolution: - integrity: sha512-aSs99GPY2h+h/AnEXwLfuUjBSl7oZwamaaPO3YHgfQm9IV2H1Bon1djRikmA8UQY5s8atjYwZj1XGdpkg3dFlw== + integrity: sha512-H/wZFsTyYIq7c0crHhDXDoct6T5+l3NvyrzkZBinRNv11EZgYLsbpYb/504HhFGGMSgXc8iwltLNlc/JA8TDmQ== tarball: 'file:projects/rush-stack-compiler-3.8.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.9-library-test.tgz': @@ -15182,7 +15248,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.9-library-test' resolution: - integrity: sha512-iFdnUuhu0Yz46cU0VObpRWcN7jksPu+n9jK50jPhaeUXBmrnuR4FGYCjFGp/CA1SA3VYPQsXZaoDetxLmhx5Og== + integrity: sha512-e4zCSyw0fH/N1UmJiHkIcSvfzH8P01fIrf9MeEuSW+xG+BGXp73GHcNvJTsMcj9xNO/MIPOqZhW5YDLz5KNQug== tarball: 'file:projects/rush-stack-compiler-3.9-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.9.tgz': @@ -15199,7 +15265,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.9' resolution: - integrity: sha512-/DQtIGWOa1k1XZRPap03pxX6+Kz9ZBgCMwFqsJLUuNu8J9xuAjX/d0/WH1A4t22TtnbkB6h7Lm88WduqQKHkEA== + integrity: sha512-xVJGjTvwoKsEaL4jZSCOazIX148/7CLF0IVh7kplkm2mGuHfoHRWMOXV5Y5I1DQRBw6d1CF/yOtRxgafd85EZw== tarball: 'file:projects/rush-stack-compiler-3.9.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-shared.tgz': @@ -15225,7 +15291,7 @@ packages: dev: false name: '@rush-temp/rush' resolution: - integrity: sha512-SUsz/SPJPCXaOMM3OVFxjHvFe0kuinaP5RYaVwOYdnMwIBfhSOR9h9TcdIZxx/u1izJB6zEWbFLWoQ5lRmxq7g== + integrity: sha512-U9KhjMT8Yool5GBDtLaBLBQVwVn4UK90Jh9rqhQsBvMQ7XIBjnrvVJjghDt9GY6fzyxb2nGh6Z8MAaPsrjOrNQ== tarball: 'file:projects/rush.tgz' version: 0.0.0 'file:projects/rushell.tgz': @@ -15238,7 +15304,7 @@ packages: dev: false name: '@rush-temp/rushell' resolution: - integrity: sha512-5sXiTl7Usc1/FKUfE/P4VNEgLPFJlxYyLeWHZtjr5/lqe23umbq8gjUZLlVNHloNUbjmdgjrZQhEp5sqiENfdA== + integrity: sha512-sj5UrwwDh615gbhQbi8VgtSHhI89Ze+12DPBixnsa7sXZwYTQ+YVJ0dOBSYqITUyed/ZpPR70ADeW5hf90MCKg== tarball: 'file:projects/rushell.tgz' version: 0.0.0 'file:projects/set-webpack-public-path-plugin.tgz': @@ -15258,7 +15324,7 @@ packages: dev: false name: '@rush-temp/set-webpack-public-path-plugin' resolution: - integrity: sha512-hWFUISDs0hR53pbCC+h5M9i8ftfYzHEUrHvax/Ir7BLwijPJarr5kOeSdhM+KqcaSPoUzA/ek5Ttc0WVPLBmBQ== + integrity: sha512-yOQKXWQq3wS4mYOeM5yhKJetDcASn5jaOpPfpI6OByacPGdSvT0bUBWM8pxuPGGp0cchdq2+yAYYsDWJ1rbJ1g== tarball: 'file:projects/set-webpack-public-path-plugin.tgz' version: 0.0.0 'file:projects/stream-collator.tgz': @@ -15274,7 +15340,7 @@ packages: dev: false name: '@rush-temp/stream-collator' resolution: - integrity: sha512-t4VFdRKP6sb75hacRiamRhr7vTxiLn6m1bqr0yef8oL1gU5+m3X0qZN95XwX3LnExWMCbP7fR4BQ9pk2ZNQ24Q== + integrity: sha512-Nm5Bfyl1i2EnfGG7ijwlP2TBmti/JSJmgS14pl0FtRMDWOP599DOh36N5jw/z0krrYfieaF2zYOJBRqiHl+pzw== tarball: 'file:projects/stream-collator.tgz' version: 0.0.0 'file:projects/ts-command-line-test.tgz': @@ -15285,7 +15351,7 @@ packages: dev: false name: '@rush-temp/ts-command-line-test' resolution: - integrity: sha512-3Q9mruEsrLmdAzMoUJ4jjLPQ3WZk7AzblOoS+uDfGb+STekssyRyVb6oqY4Oofic0s6sseltAm0iCDQMygpttw== + integrity: sha512-BXoCr1E3CZHjcqlnDYLLP1F18ExjaJ8/m2qUTxBHEnayfy0Xmt9L3ZmslWzt6hFWSkuUEt5NlxkdGBXlFFNZfQ== tarball: 'file:projects/ts-command-line-test.tgz' version: 0.0.0 'file:projects/ts-command-line.tgz': @@ -15301,20 +15367,20 @@ packages: dev: false name: '@rush-temp/ts-command-line' resolution: - integrity: sha512-pQ48un6TgpznXL/QpbQ/93V6t04qgL39FRBdIyT92rH0+pIrjxWX3DENe7l6jpOOfEdDLvoR+eq7YYacsJPghQ== + integrity: sha512-Cj1urGxlYlcJQHPcUscx1jfRreiKbGCT04pqdo0QDEopcmL74h14ptjNgt6Q/UOO+a0s2Ou4OtVVv3het2xR8A== tarball: 'file:projects/ts-command-line.tgz' version: 0.0.0 'file:projects/typings-generator.tgz': dependencies: '@types/glob': 7.1.1 '@types/node': 10.17.13 - chokidar: 3.3.1 + chokidar: 3.4.0 glob: 7.0.6 gulp: 4.0.2 dev: false name: '@rush-temp/typings-generator' resolution: - integrity: sha512-pE10zoM8almJqk2DYl1GslAMQRgDM6GV8Hpv0J1FYPuIRcVgTTUoVor51BuQCS7yJ3k9bJ5nC2a8jy/My1/i0w== + integrity: sha512-NAT3Xv0oy0P4+NDUceFMc9vlJ4O1C/JZkH5cEBmNS0iQQ3hAo+SO1SFkJ4ihTNMPBVd0DS5b7XGm5xgRODLxjA== tarball: 'file:projects/typings-generator.tgz' version: 0.0.0 'file:projects/web-library-build-test.tgz': @@ -15326,7 +15392,7 @@ packages: dev: false name: '@rush-temp/web-library-build-test' resolution: - integrity: sha512-p0F5e4DX1O8WhT62D7YCoHLe5E9HTFS31CZYhR28tTosH5/oQ8D7dzBxC6oeCCP39u82OGqlmMCckt/hOr+AQw== + integrity: sha512-zK8JowWRhZ4Lbwzec4wvWmLqSWg4xY0xalIitKd1WHz3VoxW50BY/kJM/iWtcvjKtxCoYIdNbGNuDkOKkgzEIw== tarball: 'file:projects/web-library-build-test.tgz' version: 0.0.0 'file:projects/web-library-build.tgz': @@ -15338,7 +15404,7 @@ packages: dev: false name: '@rush-temp/web-library-build' resolution: - integrity: sha512-ZSVMR6xUJS8F5U+D7H6Ir0aBqXklwhAMYB5JHvwBkJUv9qo/T+BIPTfnFab09HHKKdSKlA/B8wtU/jNwYuYRlg== + integrity: sha512-2I0Hk+AmU4AtPc0R1PUNdsIewWhTvMuK0XDQBLYIg9XMWm5W41ValoiQV6mhxmPKNsg4MJvfhsktN6VltyUJgA== tarball: 'file:projects/web-library-build.tgz' version: 0.0.0 registry: '' @@ -15480,16 +15546,16 @@ specifiers: '@types/xmldoc': 1.1.4 '@types/yargs': 0.0.34 '@types/z-schema': 3.16.31 - '@typescript-eslint/eslint-plugin': 3.3.0 - '@typescript-eslint/experimental-utils': 3.3.0 - '@typescript-eslint/parser': 3.3.0 - '@typescript-eslint/typescript-estree': 3.3.0 + '@typescript-eslint/eslint-plugin': 3.4.0 + '@typescript-eslint/experimental-utils': 3.4.0 + '@typescript-eslint/parser': 3.4.0 + '@typescript-eslint/typescript-estree': 3.4.0 '@yarnpkg/lockfile': ~1.0.2 argparse: ~1.0.9 autoprefixer: ~9.8.0 builtin-modules: ~3.1.0 chai: ~3.5.0 - chokidar: ~3.3.1 + chokidar: ~3.4.0 clean-css: 4.2.1 cli-table: ~0.3.1 colors: ~1.2.1 @@ -15507,7 +15573,7 @@ specifiers: fs-extra: ~7.0.1 git-repo-info: ~2.1.0 glob: ~7.0.5 - glob-escape: ~0.0.1 + glob-escape: ~0.0.2 globby: ~5.0.0 gulp: ~4.0.2 gulp-connect: ~5.5.0 @@ -15575,4 +15641,4 @@ specifiers: xmldoc: ~1.1.2 yargs: ~4.6.0 z-schema: ~3.18.3 -# shrinkwrap hash: a591d3bb867cb057f2092670d6d3edea517ea502 +# shrinkwrap hash: 7fd4f219613327fb0c3b58cc18af77a4183033bf From d8a7b2c12595579f039ebb4ea6fab0e911f250f9 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Fri, 26 Jun 2020 19:29:45 -0700 Subject: [PATCH 16/33] PR feedback --- apps/rush-lib/assets/rush-init/rush.json | 20 +++++++++++++++++-- apps/rush-lib/src/api/RushConfiguration.ts | 2 +- apps/rush-lib/src/cli/actions/AddAction.ts | 6 +++--- apps/rush-lib/src/logic/PackageJsonUpdater.ts | 2 +- .../src/{api => logic}/RepoStateFile.ts | 10 +++++++--- .../installManager/WorkspaceInstallManager.ts | 2 +- .../src/logic/pnpm/PnpmLinkManager.ts | 4 ++-- 7 files changed, 33 insertions(+), 13 deletions(-) rename apps/rush-lib/src/{api => logic}/RepoStateFile.ts (83%) diff --git a/apps/rush-lib/assets/rush-init/rush.json b/apps/rush-lib/assets/rush-init/rush.json index a8763548436..775fcc437a3 100644 --- a/apps/rush-lib/assets/rush-init/rush.json +++ b/apps/rush-lib/assets/rush-init/rush.json @@ -26,7 +26,7 @@ * Specify one of: "pnpmVersion", "npmVersion", or "yarnVersion". See the Rush documentation * for details about these alternatives. */ - "pnpmVersion": "4.12.5", + "pnpmVersion": "4.14.4", /*[LINE "HYPOTHETICAL"]*/ "npmVersion": "4.5.0", /*[LINE "HYPOTHETICAL"]*/ "yarnVersion": "1.9.4", @@ -94,7 +94,23 @@ * * The default value is false. */ - /*[LINE "HYPOTHETICAL"]*/ "preventManualShrinkwrapChanges": true + /*[LINE "HYPOTHETICAL"]*/ "preventManualShrinkwrapChanges": true, + + /** + * If true, then `rush install` will use the PNPM workspaces feature to perform the + * install. + * + * This feature uses PNPM to peform the entire monorepo install. When using workspaces, Rush will + * generate a "pnpm-workspace.yaml" file referencing all local projects to install. Rush will + * also generate a "pnpmfile.js" which is used to provide preferred versions support. When install + * is run, this pnpmfile will be used to replace dependency version ranges with a smaller subset + * of the original range. If the preferred version is not fully a subset of the original version + * range, it will be left as-is. After this, the pnpmfile.js provided in the repository (if one + * exists) will be called to further modify package dependencies. + * + * The default value is false. + */ + /*[LINE "HYPOTHETICAL"]*/ "useWorkspaces": true }, /** diff --git a/apps/rush-lib/src/api/RushConfiguration.ts b/apps/rush-lib/src/api/RushConfiguration.ts index 1188f922e39..51e282b95fb 100644 --- a/apps/rush-lib/src/api/RushConfiguration.ts +++ b/apps/rush-lib/src/api/RushConfiguration.ts @@ -24,7 +24,7 @@ import { YarnPackageManager } from './packageManager/YarnPackageManager'; import { PnpmPackageManager } from './packageManager/PnpmPackageManager'; import { ExperimentsConfiguration } from './ExperimentsConfiguration'; import { PackageNameParsers } from './PackageNameParsers'; -import { RepoStateFile } from './RepoStateFile'; +import { RepoStateFile } from '../logic/RepoStateFile'; const MINIMUM_SUPPORTED_RUSH_JSON_VERSION: string = '0.0.0'; const DEFAULT_BRANCH: string = 'master'; diff --git a/apps/rush-lib/src/cli/actions/AddAction.ts b/apps/rush-lib/src/cli/actions/AddAction.ts index 9955d986340..8ff51a78b54 100644 --- a/apps/rush-lib/src/cli/actions/AddAction.ts +++ b/apps/rush-lib/src/cli/actions/AddAction.ts @@ -26,9 +26,9 @@ export class AddAction extends BaseRushAction { 'Adds a specified package as a dependency of the current project (as determined by the current working directory)' + ' and then runs "rush update". If no version is specified, a version will be automatically detected (typically' + ' either the latest version or a version that won\'t break the "ensureConsistentVersions" policy). If a version' + - ' range is specified, the latest version in the range will be used. The version will be automatically prepended' + - ' with a tilde, unless the "--exact" or "--caret" flags are used. The "--make-consistent" flag can be used to' + - ' update all packages with the dependency.' + ' range (or a workspace range) is specified, the latest version in the range will be used. The version will be' + + ' automatically prepended with a tilde, unless the "--exact" or "--caret" flags are used. The "--make-consistent"' + + ' flag can be used to update all packages with the dependency.' ]; super({ actionName: 'add', diff --git a/apps/rush-lib/src/logic/PackageJsonUpdater.ts b/apps/rush-lib/src/logic/PackageJsonUpdater.ts index 31a58e09895..d5fe9122b5a 100644 --- a/apps/rush-lib/src/logic/PackageJsonUpdater.ts +++ b/apps/rush-lib/src/logic/PackageJsonUpdater.ts @@ -352,7 +352,7 @@ export class PackageJsonUpdater { // For workspaces, assume that specifying the exact version means you always want to consume // the local project. Otherwise, use the exact local package version if (useWorkspaces) { - selectedVersion = semver.clean(initialSpec) === semver.clean(version) ? '*' : initialSpec; + selectedVersion = initialSpec === version ? '*' : initialSpec; selectedVersionPrefix = workspacePrefix; } else { selectedVersion = version; diff --git a/apps/rush-lib/src/api/RepoStateFile.ts b/apps/rush-lib/src/logic/RepoStateFile.ts similarity index 83% rename from apps/rush-lib/src/api/RepoStateFile.ts rename to apps/rush-lib/src/logic/RepoStateFile.ts index 3982a2cd201..df8801c181e 100644 --- a/apps/rush-lib/src/api/RepoStateFile.ts +++ b/apps/rush-lib/src/logic/RepoStateFile.ts @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. import * as path from 'path'; -import { FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; +import { FileSystem, JsonFile, JsonSchema, NewlineKind } from '@rushstack/node-core-library'; /** * This interface represents the raw pnpm-workspace.YAML file @@ -17,7 +17,8 @@ interface IRepoStateJson { } /** - * Th + * This file is used to track the state of various Rush-related features. It is generated + * and updated by Rush. */ export class RepoStateFile { private static _jsonSchema: JsonSchema = JsonSchema.fromFile( @@ -74,7 +75,10 @@ export class RepoStateFile { */ public saveIfModified(): boolean { if (this._modified) { - JsonFile.save(this._serialize(), this._repoStateFilePath, { updateExistingFile: true }); + const content: string = + `// DO NOT MODIFY THIS FILE. It is generated and used by Rush.${NewlineKind.Lf}` + + `${JsonFile.stringify(this._serialize(), { newlineConversion: NewlineKind.Lf })}`; + FileSystem.writeFile(this._repoStateFilePath, content); this._modified = false; return true; } diff --git a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts index 1226bdc8e28..5dc4dc480f3 100644 --- a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -20,7 +20,7 @@ import { Stopwatch } from '../../utilities/Stopwatch'; import { Utilities } from '../../utilities/Utilities'; import { InstallHelpers } from './InstallHelpers'; import { CommonVersionsConfiguration } from '../../api/CommonVersionsConfiguration'; -import { RepoStateFile } from '../../api/RepoStateFile'; +import { RepoStateFile } from '../RepoStateFile'; /** * This class implements common logic between "rush install" and "rush update". diff --git a/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts b/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts index 5db6587ab25..dca5b5b819b 100644 --- a/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts +++ b/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts @@ -58,7 +58,6 @@ export class PnpmLinkManager extends BaseLinkManager { this._rushConfiguration.pnpmOptions.useWorkspaces; for (const rushProject of this._rushConfiguration.projects) { - console.log(os.EOL + 'LINKING: ' + rushProject.packageName); if (useWorkspaces) { await this._linkWorkspaceProject(rushProject, rushLinkJson, pnpmShrinkwrapFile); } else { @@ -88,8 +87,9 @@ export class PnpmLinkManager extends BaseLinkManager { rushLinkJson: IRushLinkJson, pnpmShrinkwrapFile: PnpmShrinkwrapFile ): Promise { - // first, read the temp package.json information + console.log(os.EOL + 'LINKING: ' + project.packageName); + // first, read the temp package.json information // Example: "project1" const unscopedTempProjectName: string = this._rushConfiguration.packageNameParser.getUnscopedName( project.tempProjectName From f7f7605d88f323e71eb4ac63dc7ed7bd1eb64547 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Mon, 29 Jun 2020 10:17:40 -0700 Subject: [PATCH 17/33] Updated snapshot --- .../test/__snapshots__/CommandLineHelp.test.ts.snap | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap b/apps/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap index eb03329eb02..ef240cd265f 100644 --- a/apps/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap +++ b/apps/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap @@ -64,11 +64,11 @@ Adds a specified package as a dependency of the current project (as determined by the current working directory) and then runs \\"rush update\\". If no version is specified, a version will be automatically detected (typically either the latest version or a version that won't break the -\\"ensureConsistentVersions\\" policy). If a version range is specified, the -latest version in the range will be used. The version will be automatically -prepended with a tilde, unless the \\"--exact\\" or \\"--caret\\" flags are used. The -\\"--make-consistent\\" flag can be used to update all packages with the -dependency. +\\"ensureConsistentVersions\\" policy). If a version range (or a workspace range) +is specified, the latest version in the range will be used. The version will +be automatically prepended with a tilde, unless the \\"--exact\\" or \\"--caret\\" +flags are used. The \\"--make-consistent\\" flag can be used to update all +packages with the dependency. Optional arguments: -h, --help Show this help message and exit. From 8b43f8e347056505550a6232618627f8e8dde2e0 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Mon, 29 Jun 2020 10:43:49 -0700 Subject: [PATCH 18/33] Fix local project references for RushInstallManager --- .../src/logic/installManager/RushInstallManager.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/rush-lib/src/logic/installManager/RushInstallManager.ts b/apps/rush-lib/src/logic/installManager/RushInstallManager.ts index 8d67b109079..fdf2d1def3b 100644 --- a/apps/rush-lib/src/logic/installManager/RushInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/RushInstallManager.ts @@ -121,9 +121,10 @@ export class RushInstallManager extends BaseInstallManager { const tarballFile: string = this._getTarballFilePath(rushProject); // Example: dependencies["@rush-temp/my-project-2"] = "file:./projects/my-project-2.tgz" - commonDependencies[ - rushProject.tempProjectName - ] = `file:./${RushConstants.rushTempProjectsFolderName}/${rushProject.unscopedTempProjectName}.tgz`; + commonDependencies.set( + rushProject.tempProjectName, + `file:./${RushConstants.rushTempProjectsFolderName}/${rushProject.unscopedTempProjectName}.tgz` + ); const tempPackageJson: IRushTempPackageJson = { name: rushProject.tempProjectName, From 495699aae62179bc6b07b547aecd146de712db1b Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Mon, 29 Jun 2020 12:35:55 -0700 Subject: [PATCH 19/33] Add support for reverting workspace notation when going back to legacy Rush install --- .../installManager/RushInstallManager.ts | 80 ++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/apps/rush-lib/src/logic/installManager/RushInstallManager.ts b/apps/rush-lib/src/logic/installManager/RushInstallManager.ts index fdf2d1def3b..f6bfbdbbf66 100644 --- a/apps/rush-lib/src/logic/installManager/RushInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/RushInstallManager.ts @@ -8,7 +8,15 @@ import * as path from 'path'; import * as semver from 'semver'; import * as tar from 'tar'; import * as globEscape from 'glob-escape'; -import { JsonFile, Text, FileSystem, FileConstants, Sort, PosixModeBits } from '@rushstack/node-core-library'; +import { + JsonFile, + Text, + FileSystem, + FileConstants, + Sort, + PosixModeBits, + InternalError +} from '@rushstack/node-core-library'; import { BaseInstallManager } from '../base/BaseInstallManager'; import { BaseShrinkwrapFile } from '../../logic/base/BaseShrinkwrapFile'; @@ -17,9 +25,10 @@ import { RushConfigurationProject } from '../../api/RushConfigurationProject'; import { RushConstants } from '../../logic/RushConstants'; import { Stopwatch } from '../../utilities/Stopwatch'; import { Utilities } from '../../utilities/Utilities'; -import { PackageJsonEditor, DependencyType } from '../../api/PackageJsonEditor'; +import { PackageJsonEditor, DependencyType, PackageJsonDependency } from '../../api/PackageJsonEditor'; import { DependencySpecifier } from '../DependencySpecifier'; import { InstallHelpers } from './InstallHelpers'; +import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; /** * The "noMtime" flag is new in tar@4.4.1 and not available yet for \@types/tar. @@ -71,6 +80,23 @@ export class RushInstallManager extends BaseInstallManager { if (!shrinkwrapFile) { shrinkwrapIsUpToDate = false; + } else { + let workspaceKeys: ReadonlyArray = []; + try { + workspaceKeys = shrinkwrapFile.getWorkspaceKeys(); + } catch { + // Swallow errors since not all shrinkwrap types support workspaces + } + if (workspaceKeys.length !== 0 && !this.options.fullUpgrade) { + console.log(); + console.log( + colors.red( + 'The shrinkwrap file had previously been updated to support workspaces. Run "rush update --full" ' + + 'to update the shrinkwrap file.' + ) + ); + throw new AlreadyReportedError(); + } } // dependency name --> version specifier @@ -139,6 +165,10 @@ export class RushInstallManager extends BaseInstallManager { // These can be regular, optional, or peer dependencies (but NOT dev dependencies). // (A given packageName will never appear more than once in this list.) for (const dependency of packageJson.dependencyList) { + if (this._revertWorkspaceNotation(dependency)) { + shrinkwrapIsUpToDate = false; + } + // If there are any optional dependencies, copy directly into the optionalDependencies field. if (dependency.dependencyType === DependencyType.Optional) { if (!tempPackageJson.optionalDependencies) { @@ -151,6 +181,10 @@ export class RushInstallManager extends BaseInstallManager { } for (const dependency of packageJson.devDependencyList) { + if (this._revertWorkspaceNotation(dependency)) { + shrinkwrapIsUpToDate = false; + } + // If there are devDependencies, we need to merge them with the regular dependencies. If the same // library appears in both places, then the dev dependency wins (because presumably it's saying what you // want right now for development, not the range that you support for consumers). @@ -261,6 +295,27 @@ export class RushInstallManager extends BaseInstallManager { FileSystem.deleteFile(tempPackageJsonFilename); } } + + // Remove the workspace file if it exists + if (this.rushConfiguration.packageManager === 'pnpm') { + const workspaceFilePath: string = path.join( + this.rushConfiguration.commonTempFolder, + 'pnpm-workspace.yaml' + ); + if (FileSystem.exists(workspaceFilePath)) { + FileSystem.deleteFile(workspaceFilePath); + } + } + + // Save the package.json if we modified the version references and warn that the package.json was modified + if (packageJson.saveIfModified()) { + console.log( + colors.yellow( + `"${rushProject.packageName}" depends on one or more local packages which used "workspace:" ` + + 'notation. The package.json has been modified and must be committed to source control.' + ) + ); + } } // Write the common package.json @@ -317,6 +372,27 @@ export class RushInstallManager extends BaseInstallManager { tar.create(tarOptions, [FileConstants.PackageJson]); } + private _revertWorkspaceNotation(dependency: PackageJsonDependency): boolean { + const specifier: DependencySpecifier = new DependencySpecifier(dependency.name, dependency.version); + if (specifier.specifierType !== 'workspace') { + return false; + } + // Replace workspace notation with the supplied version range + if (specifier.versionSpecifier === '*') { + // When converting to workspaces, exact package versions are replaced with a '*', so undo this + const localProject: RushConfigurationProject | undefined = this.rushConfiguration.getProjectByName( + specifier.packageName + ); + if (!localProject) { + throw new InternalError(`Could not find local project with package name ${specifier.packageName}`); + } + dependency.setVersion(localProject.packageJson.version); + } else { + dependency.setVersion(specifier.versionSpecifier); + } + return true; + } + /** * Check whether or not the install is already valid, and therefore can be skipped. * From 3ea3fbd0423bd9ec15898626013d5b24fe32a618 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Mon, 29 Jun 2020 12:46:06 -0700 Subject: [PATCH 20/33] Fix per-project shrinkwrap when encountering duplicate dev dependencies --- apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts b/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts index dca5b5b819b..2475037dda0 100644 --- a/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts +++ b/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts @@ -361,7 +361,7 @@ export class PnpmLinkManager extends BaseLinkManager { const useProjectDependencyManifest: boolean = !this._rushConfiguration.experimentsConfiguration .configuration.legacyIncrementalBuildDependencyDetection; - // Then, do non-local dependencies. Dev dependencies take priority over normal dependencies + // Then, do non-local dependencies const dependencies: PackageJsonDependency[] = [ ...project.packageJsonEditor.dependencyList, ...project.packageJsonEditor.devDependencyList @@ -375,7 +375,10 @@ export class PnpmLinkManager extends BaseLinkManager { version = (workspaceImporter.dependencies || {})[name]; break; case DependencyType.Dev: - version = (workspaceImporter.devDependencies || {})[name]; + // Dev dependencies are folded into dependencies if there is a duplicate + // definition, so we should also check there + version = + (workspaceImporter.devDependencies || {})[name] || (workspaceImporter.dependencies || {})[name]; break; case DependencyType.Optional: version = (workspaceImporter.optionalDependencies || {})[name]; From 3fad71ecbd7f779fce73f6a1aa2425c6c5498056 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Mon, 29 Jun 2020 17:39:52 -0700 Subject: [PATCH 21/33] Use repo-state.json for shrinkwrap hash validation --- .../src/api/CommonVersionsConfiguration.ts | 2 +- apps/rush-lib/src/api/RushConfiguration.ts | 4 +- apps/rush-lib/src/logic/RepoStateFile.ts | 100 ++++++++++++++---- .../src/logic/base/BaseInstallManager.ts | 30 +++--- .../src/logic/base/BaseShrinkwrapFile.ts | 13 +-- .../installManager/WorkspaceInstallManager.ts | 17 +-- .../src/logic/pnpm/PnpmShrinkwrapFile.ts | 61 +++-------- .../src/logic/policy/ShrinkwrapFilePolicy.ts | 11 +- .../src/schemas/repo-state.schema.json | 4 + common/reviews/api/rush-lib.api.md | 2 +- 10 files changed, 132 insertions(+), 112 deletions(-) diff --git a/apps/rush-lib/src/api/CommonVersionsConfiguration.ts b/apps/rush-lib/src/api/CommonVersionsConfiguration.ts index f0887e91fb9..fb074c08b76 100644 --- a/apps/rush-lib/src/api/CommonVersionsConfiguration.ts +++ b/apps/rush-lib/src/api/CommonVersionsConfiguration.ts @@ -153,7 +153,7 @@ export class CommonVersionsConfiguration { /** * Get a sha1 hash of the preferred versions. */ - public get preferredVersionsHash(): string { + public getPreferredVersionsHash(): string { // Sort so that the hash is stable const preferredVersionsToHash: Map = new Map( this._preferredVersions.protectedView diff --git a/apps/rush-lib/src/api/RushConfiguration.ts b/apps/rush-lib/src/api/RushConfiguration.ts index 51e282b95fb..c0902c4c6c9 100644 --- a/apps/rush-lib/src/api/RushConfiguration.ts +++ b/apps/rush-lib/src/api/RushConfiguration.ts @@ -340,7 +340,7 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration * @remarks * This feature protects against accidental inconsistencies that may be introduced * if the PNPM shrinkwrap file (`pnpm-lock.yaml`) is manually edited. When this - * feature is enabled, `rush update` will append a hash to the file as a YAML comment, + * feature is enabled, `rush update` will write a hash of the shrinkwrap contents to repo-state.json, * and then `rush update` and `rush install` will validate the hash. Note that this does not prohibit * manual modifications, but merely requires `rush update` be run * afterwards, ensuring that PNPM can report or repair any potential inconsistencies. @@ -1459,7 +1459,7 @@ export class RushConfiguration { */ public getRepoState(variant?: string | undefined): RepoStateFile { const repoStateFilename: string = this.getRepoStateFilePath(variant); - return RepoStateFile.loadFromFile(repoStateFilename); + return RepoStateFile.loadFromFile(repoStateFilename, variant); } /** diff --git a/apps/rush-lib/src/logic/RepoStateFile.ts b/apps/rush-lib/src/logic/RepoStateFile.ts index df8801c181e..3a5ebc71efd 100644 --- a/apps/rush-lib/src/logic/RepoStateFile.ts +++ b/apps/rush-lib/src/logic/RepoStateFile.ts @@ -4,6 +4,10 @@ import * as path from 'path'; import { FileSystem, JsonFile, JsonSchema, NewlineKind } from '@rushstack/node-core-library'; +import { RushConfiguration } from '../api/RushConfiguration'; +import { PnpmShrinkwrapFile } from './pnpm/PnpmShrinkwrapFile'; +import { CommonVersionsConfiguration } from '../api/CommonVersionsConfiguration'; + /** * This interface represents the raw pnpm-workspace.YAML file * Example: @@ -12,7 +16,13 @@ import { FileSystem, JsonFile, JsonSchema, NewlineKind } from '@rushstack/node-c * } */ interface IRepoStateJson { - /** A hash of the CommonVersionsConfiguration.preferredVersions field */ + /** + * A hash of the PNPM shrinkwrap file contents + */ + pnpmShrinkwrapHash?: string; + /** + * A hash of the CommonVersionsConfiguration.preferredVersions field + */ preferredVersionsHash?: string; } @@ -25,13 +35,21 @@ export class RepoStateFile { path.join(__dirname, '../schemas/repo-state.schema.json') ); private _repoStateFilePath: string; + private _variant: string | undefined; + private _pnpmShrinkwrapHash: string | undefined; private _preferredVersionsHash: string | undefined; private _modified: boolean = false; - private constructor(repoStateJson: IRepoStateJson | undefined, filePath: string) { + private constructor( + repoStateJson: IRepoStateJson | undefined, + filePath: string, + variant: string | undefined + ) { this._repoStateFilePath = filePath; + this._variant = variant; if (repoStateJson) { + this._pnpmShrinkwrapHash = repoStateJson.pnpmShrinkwrapHash; this._preferredVersionsHash = repoStateJson.preferredVersionsHash; } } @@ -43,6 +61,13 @@ export class RepoStateFile { return this._repoStateFilePath; } + /** + * The hash of the pnpm shrinkwrap file at the end of the last update. + */ + public get pnpmShrinkwrapHash(): string | undefined { + return this._pnpmShrinkwrapHash; + } + /** * The hash of all preferred versions at the end of the last update. */ @@ -50,34 +75,72 @@ export class RepoStateFile { return this._preferredVersionsHash; } - public set preferredVersionsHash(hash: string | undefined) { - if (this._preferredVersionsHash !== hash) { - this._preferredVersionsHash = hash; - this._modified = true; - } - } - /** * Loads the repo-state.json data from the specified file path. * If the file has not been created yet, then an empty object is returned. */ - public static loadFromFile(jsonFilename: string): RepoStateFile { + public static loadFromFile(jsonFilename: string, variant: string | undefined): RepoStateFile { let repoStateJson: IRepoStateJson | undefined = undefined; - - if (FileSystem.exists(jsonFilename)) { + try { repoStateJson = JsonFile.loadAndValidate(jsonFilename, RepoStateFile._jsonSchema); + } catch (error) { + if (!FileSystem.isNotExistError(error)) { + throw error; + } } - return new RepoStateFile(repoStateJson, jsonFilename); + + return new RepoStateFile(repoStateJson, jsonFilename, variant); + } + + public refreshState(rushConfiguration: RushConfiguration): boolean { + // Only support saving the pnpm shrinkwrap hash if it was enabled + const preventShrinkwrapChanges: boolean = + rushConfiguration.packageManager === 'pnpm' && + rushConfiguration.pnpmOptions && + rushConfiguration.pnpmOptions.preventManualShrinkwrapChanges; + if (preventShrinkwrapChanges) { + const pnpmShrinkwrapFile: PnpmShrinkwrapFile | undefined = PnpmShrinkwrapFile.loadFromFile( + rushConfiguration.getCommittedShrinkwrapFilename(this._variant), + rushConfiguration.pnpmOptions + ); + if (pnpmShrinkwrapFile) { + const shrinkwrapFileHash: string = pnpmShrinkwrapFile.getShrinkwrapHash(); + if (this._pnpmShrinkwrapHash !== shrinkwrapFileHash) { + this._pnpmShrinkwrapHash = shrinkwrapFileHash; + this._modified = true; + } + } + } else if (this._pnpmShrinkwrapHash !== undefined) { + this._pnpmShrinkwrapHash = undefined; + this._modified = true; + } + + // Currently, only support saving the preferred versions hash if using workspaces + const useWorkspaces: boolean = + rushConfiguration.pnpmOptions && rushConfiguration.pnpmOptions.useWorkspaces; + if (useWorkspaces) { + const commonVersions: CommonVersionsConfiguration = rushConfiguration.getCommonVersions(this._variant); + const preferredVersionsHash: string = commonVersions.getPreferredVersionsHash(); + if (this._preferredVersionsHash !== preferredVersionsHash) { + this._preferredVersionsHash = preferredVersionsHash; + this._modified = true; + } + } else if (this._preferredVersionsHash !== undefined) { + this._preferredVersionsHash = undefined; + this._modified = true; + } + + return this._saveIfModified(); } /** * Writes the "repo-state.json" file to disk, using the filename that was passed to loadFromFile(). */ - public saveIfModified(): boolean { + private _saveIfModified(): boolean { if (this._modified) { const content: string = - `// DO NOT MODIFY THIS FILE. It is generated and used by Rush.${NewlineKind.Lf}` + - `${JsonFile.stringify(this._serialize(), { newlineConversion: NewlineKind.Lf })}`; + '// DO NOT MODIFY THIS FILE. It is generated and used by Rush.' + + `${NewlineKind.Lf}${this._serialize()}`; FileSystem.writeFile(this._repoStateFilePath, content); this._modified = false; return true; @@ -86,10 +149,11 @@ export class RepoStateFile { return false; } - private _serialize(): IRepoStateJson { + private _serialize(): string { const repoStateJson: IRepoStateJson = { + pnpmShrinkwrapHash: this.pnpmShrinkwrapHash, preferredVersionsHash: this.preferredVersionsHash }; - return repoStateJson; + return JsonFile.stringify(repoStateJson, { newlineConversion: NewlineKind.Lf }); } } diff --git a/apps/rush-lib/src/logic/base/BaseInstallManager.ts b/apps/rush-lib/src/logic/base/BaseInstallManager.ts index 05181d54923..3b54e2c8858 100644 --- a/apps/rush-lib/src/logic/base/BaseInstallManager.ts +++ b/apps/rush-lib/src/logic/base/BaseInstallManager.ts @@ -36,24 +36,29 @@ export interface IInstallManagerOptions { * Whether the global "--debug" flag was specified. */ debug: boolean; + /** * Whether or not Rush will automatically update the shrinkwrap file. * True for "rush update", false for "rush install". */ allowShrinkwrapUpdates: boolean; + /** * Whether to skip policy checks. */ bypassPolicy: boolean; + /** * Whether to skip linking, i.e. require "rush link" to be done manually later. */ noLink: boolean; + /** * Whether to delete the shrinkwrap file before installation, i.e. so that all dependencies * will be upgraded to the latest SemVer-compatible version. */ fullUpgrade: boolean; + /** * Whether to force an update to the shrinkwrap file even if it appears to be unnecessary. * Normally Rush uses heuristics to determine when "pnpm install" can be skipped, @@ -187,16 +192,6 @@ export abstract class BaseInstallManager { true; if (this.options.allowShrinkwrapUpdates && (usePnpmFrozenLockfile || !shrinkwrapIsUpToDate)) { - // Shrinkwrap files may need to be post processed after install, so load and save it - const tempShrinkwrapFile: BaseShrinkwrapFile | undefined = ShrinkwrapFileFactory.getShrinkwrapFile( - this._rushConfiguration.packageManager, - this._rushConfiguration.packageManagerOptions, - this._rushConfiguration.tempShrinkwrapFilename - ); - if (tempShrinkwrapFile) { - tempShrinkwrapFile.save(this._rushConfiguration.tempShrinkwrapFilename); - } - // Copy (or delete) common\temp\pnpm-lock.yaml --> common\config\rush\pnpm-lock.yaml Utilities.syncFile( this._rushConfiguration.tempShrinkwrapFilename, @@ -206,6 +201,17 @@ export abstract class BaseInstallManager { // TODO: Validate whether the package manager updated it in a nontrivial way } + // Always update the state file if running "rush update" + if (this.options.allowShrinkwrapUpdates) { + if (this.rushConfiguration.getRepoState(this.options.variant).refreshState(this.rushConfiguration)) { + console.log( + colors.yellow( + `${RushConstants.repoStateFilename} has been modified and must be committed to source control.` + ) + ); + } + } + // Create the marker file to indicate a successful install this._commonTempInstallFlag.create(); @@ -361,9 +367,7 @@ export abstract class BaseInstallManager { // Allow for package managers to do their own preparation and check that the shrinkwrap is up to date // eslint-disable-next-line prefer-const let { shrinkwrapIsUpToDate, shrinkwrapWarnings } = await this.prepareAndCheckShrinkwrap(shrinkwrapFile); - shrinkwrapIsUpToDate = - shrinkwrapIsUpToDate && - !(this.options.recheckShrinkwrap || (shrinkwrapFile && shrinkwrapFile.shouldForceRecheck())); + shrinkwrapIsUpToDate = shrinkwrapIsUpToDate && !this.options.recheckShrinkwrap; // Write out the reported warnings if (shrinkwrapWarnings.length > 0) { diff --git a/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts b/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts index 7cf979c56f2..fe7ebc9b14e 100644 --- a/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts +++ b/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts @@ -7,7 +7,7 @@ import { FileSystem } from '@rushstack/node-core-library'; import { RushConstants } from '../../logic/RushConstants'; import { DependencySpecifier } from '../DependencySpecifier'; -import { IPolicyValidatorOptions } from '../policy/PolicyValidator'; +import { IShrinkwrapFilePolicyValidatorOptions } from '../policy/ShrinkwrapFilePolicy'; import { PackageManagerOptionsConfigurationBase } from '../../api/RushConfiguration'; import { PackageNameParsers } from '../../api/PackageNameParsers'; @@ -24,15 +24,6 @@ export abstract class BaseShrinkwrapFile { return undefined; } - /** - * Return whether or not the committed shrinkwrap file should be forcibly rechecked for changes. - * - * @virtual - */ - public shouldForceRecheck(): boolean { - return false; - } - /** * Serializes and saves the shrinkwrap file to specified location */ @@ -47,7 +38,7 @@ export abstract class BaseShrinkwrapFile { */ public validate( packageManagerOptionsConfig: PackageManagerOptionsConfigurationBase, - policyOptions: IPolicyValidatorOptions + policyOptions: IShrinkwrapFilePolicyValidatorOptions ): void {} /** diff --git a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts index 5dc4dc480f3..41d256f24a1 100644 --- a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -120,7 +120,7 @@ export class WorkspaceInstallManager extends BaseInstallManager { const commonVersions: CommonVersionsConfiguration = this.rushConfiguration.getCommonVersions( this.options.variant ); - if (repoState.preferredVersionsHash !== commonVersions.preferredVersionsHash) { + if (repoState.preferredVersionsHash !== commonVersions.getPreferredVersionsHash()) { shrinkwrapWarnings.push( `Preferred versions from ${RushConstants.commonVersionsFilename} have been modified.` ); @@ -417,21 +417,6 @@ export class WorkspaceInstallManager extends BaseInstallManager { } console.log(''); - - // We need to update the repo state with the information from the install - const repoState: RepoStateFile = this.rushConfiguration.getRepoState(this.options.variant); - const commonVersions: CommonVersionsConfiguration = this.rushConfiguration.getCommonVersions( - this.options.variant - ); - repoState.preferredVersionsHash = commonVersions.preferredVersionsHash; - if (repoState.saveIfModified()) { - console.log( - colors.yellow( - `${RushConstants.repoStateFilename} has been modified and must be committed to source control.` - ) - ); - console.log(''); - } } /** diff --git a/apps/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts b/apps/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts index b2008676e40..3a178591021 100644 --- a/apps/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts +++ b/apps/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts @@ -12,7 +12,7 @@ import { PackageManagerOptionsConfigurationBase, PnpmOptionsConfiguration } from '../../api/RushConfiguration'; -import { IPolicyValidatorOptions } from '../policy/PolicyValidator'; +import { IShrinkwrapFilePolicyValidatorOptions } from '../policy/ShrinkwrapFilePolicy'; import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; // This is based on PNPM's own configuration: @@ -187,22 +187,12 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { */ public readonly shrinkwrapFilename: string; - private static readonly _shrinkwrapHashPrefix: string = '# shrinkwrap hash:'; private _shrinkwrapJson: IPnpmShrinkwrapYaml; - private _shrinkwrapHash: string | undefined; - private _shrinkwrapHashEnabled: boolean | undefined; - - private constructor( - shrinkwrapJson: IPnpmShrinkwrapYaml, - shrinkwrapFilename: string, - shrinkwrapHash?: string, - shrinkwrapHashEnabled?: boolean - ) { + + private constructor(shrinkwrapJson: IPnpmShrinkwrapYaml, shrinkwrapFilename: string) { super(); this._shrinkwrapJson = shrinkwrapJson; this.shrinkwrapFilename = shrinkwrapFilename; - this._shrinkwrapHash = shrinkwrapHash; - this._shrinkwrapHashEnabled = shrinkwrapHashEnabled; // Normalize the data if (!this._shrinkwrapJson.registry) { @@ -233,38 +223,21 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { const shrinkwrapContent: string = FileSystem.readFile(shrinkwrapYamlFilename); const parsedData: IPnpmShrinkwrapYaml = yaml.safeLoad(shrinkwrapContent); - - let shrinkwrapHash: string | undefined; - if (pnpmOptions.preventManualShrinkwrapChanges) { - // Grab the shrinkwrap hash out of the comment where we store it. - const hashYamlCommentRegExp: RegExp = new RegExp( - `\\n\\s*${PnpmShrinkwrapFile._shrinkwrapHashPrefix}\\s*(\\S+)\\s*$` - ); - const match: RegExpMatchArray | null = shrinkwrapContent.match(hashYamlCommentRegExp); - shrinkwrapHash = match ? match[1] : undefined; - } - - return new PnpmShrinkwrapFile( - parsedData, - shrinkwrapYamlFilename, - shrinkwrapHash, - pnpmOptions.preventManualShrinkwrapChanges - ); + return new PnpmShrinkwrapFile(parsedData, shrinkwrapYamlFilename); } catch (error) { throw new Error(`Error reading "${shrinkwrapYamlFilename}":${os.EOL} ${error.message}`); } } - /** @override */ - public shouldForceRecheck(): boolean { - // Ensure the shrinkwrap is rechecked when the hash is enabled but no hash is populated. - return super.shouldForceRecheck() || (!!this._shrinkwrapHashEnabled && !this._shrinkwrapHash); + public getShrinkwrapHash(): string { + const shrinkwrapContent: string = this.serialize(); + return crypto.createHash('sha1').update(shrinkwrapContent).digest('hex'); } /** @override */ public validate( packageManagerOptionsConfig: PackageManagerOptionsConfigurationBase, - policyOptions: IPolicyValidatorOptions + policyOptions: IShrinkwrapFilePolicyValidatorOptions ): void { super.validate(packageManagerOptionsConfig, policyOptions); if (!(packageManagerOptionsConfig instanceof PnpmOptionsConfiguration)) { @@ -274,19 +247,17 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { // Only check the hash if allowShrinkwrapUpdates is false. If true, the shrinkwrap file // may have changed and the hash could be invalid. if (packageManagerOptionsConfig.preventManualShrinkwrapChanges && !policyOptions.allowShrinkwrapUpdates) { - if (!this._shrinkwrapHash) { + if (!policyOptions.repoState.pnpmShrinkwrapHash) { console.log( colors.red( - 'The shrinkwrap file does not contain the generated hash. You may need to run "rush update" to ' + + 'The existing shrinkwrap file hash could not be found. You may need to run "rush update" to ' + 'populate the hash. See the "preventManualShrinkwrapChanges" setting documentation for details.' ) + os.EOL ); throw new AlreadyReportedError(); } - const shrinkwrapContent: string = yaml.safeDump(this._shrinkwrapJson, SHRINKWRAP_YAML_FORMAT); - const calculatedHash: string = crypto.createHash('sha1').update(shrinkwrapContent).digest('hex'); - if (calculatedHash !== this._shrinkwrapHash) { + if (this.getShrinkwrapHash() !== policyOptions.repoState.pnpmShrinkwrapHash) { console.log( colors.red( 'The shrinkwrap file hash does not match the expected hash. Please run "rush update" to ensure the ' + @@ -450,15 +421,7 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { } } - let shrinkwrapContent: string = yaml.safeDump(shrinkwrapToSerialize, SHRINKWRAP_YAML_FORMAT); - if (this._shrinkwrapHashEnabled) { - this._shrinkwrapHash = crypto.createHash('sha1').update(shrinkwrapContent).digest('hex'); - shrinkwrapContent = `${shrinkwrapContent.trimRight()}\n${PnpmShrinkwrapFile._shrinkwrapHashPrefix} ${ - this._shrinkwrapHash - }\n`; - } - - return shrinkwrapContent; + return yaml.safeDump(shrinkwrapToSerialize, SHRINKWRAP_YAML_FORMAT); } /** diff --git a/apps/rush-lib/src/logic/policy/ShrinkwrapFilePolicy.ts b/apps/rush-lib/src/logic/policy/ShrinkwrapFilePolicy.ts index d82e3ca3265..9185a1e96a2 100644 --- a/apps/rush-lib/src/logic/policy/ShrinkwrapFilePolicy.ts +++ b/apps/rush-lib/src/logic/policy/ShrinkwrapFilePolicy.ts @@ -2,10 +2,16 @@ // See LICENSE in the project root for license information. import * as os from 'os'; + import { RushConfiguration } from '../../api/RushConfiguration'; import { IPolicyValidatorOptions } from './PolicyValidator'; import { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; import { ShrinkwrapFileFactory } from '../ShrinkwrapFileFactory'; +import { RepoStateFile } from '../RepoStateFile'; + +export interface IShrinkwrapFilePolicyValidatorOptions extends IPolicyValidatorOptions { + repoState: RepoStateFile; +} /** * A policy that validates shrinkwrap files used by package managers. @@ -25,6 +31,9 @@ export class ShrinkwrapFilePolicy { } // Run shrinkwrap-specific validation - shrinkwrapFile.validate(rushConfiguration.packageManagerOptions, options); + shrinkwrapFile.validate(rushConfiguration.packageManagerOptions, { + ...options, + repoState: rushConfiguration.getRepoState(options.shrinkwrapVariant) + }); } } diff --git a/apps/rush-lib/src/schemas/repo-state.schema.json b/apps/rush-lib/src/schemas/repo-state.schema.json index 9bfb102ac97..916f2fb69aa 100644 --- a/apps/rush-lib/src/schemas/repo-state.schema.json +++ b/apps/rush-lib/src/schemas/repo-state.schema.json @@ -9,6 +9,10 @@ "description": "Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.", "type": "string" }, + "pnpmShrinkwrapHash": { + "description": "A hash of the contents of the PNPM shrinkwrap file for the repository. This hash is used to determine whether or not the shrinkwrap has been modified prior to install.", + "type": "string" + }, "preferredVersionsHash": { "description": "A hash of \"preferred versions\" for the repository. This hash is used to determine whether or not preferred versions have been modified prior to install.", "type": "string" diff --git a/common/reviews/api/rush-lib.api.md b/common/reviews/api/rush-lib.api.md index 5ff693226e3..e0fac2dd2eb 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -68,10 +68,10 @@ export class CommonVersionsConfiguration { readonly allowedAlternativeVersions: Map>; readonly filePath: string; getAllPreferredVersions(): Map; + getPreferredVersionsHash(): string; readonly implicitlyPreferredVersions: boolean | undefined; static loadFromFile(jsonFilename: string): CommonVersionsConfiguration; readonly preferredVersions: Map; - readonly preferredVersionsHash: string; save(): boolean; readonly xstitchPreferredVersions: Map; } From a886fb14d35319f032ce843d54252a6e04004bcf Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Mon, 29 Jun 2020 19:06:11 -0700 Subject: [PATCH 22/33] PR feedback --- .../src/api/CommonVersionsConfiguration.ts | 11 +++- apps/rush-lib/src/api/PackageJsonEditor.ts | 2 + .../cli/scriptActions/GlobalScriptAction.ts | 14 ++--- apps/rush-lib/src/cli/test/Cli.test.ts | 7 ++- apps/rush-lib/src/index.ts | 2 + apps/rush-lib/src/logic/PublishUtilities.ts | 9 ++- apps/rush-lib/src/logic/RepoStateFile.ts | 16 +++++- .../src/logic/base/BaseInstallManager.ts | 12 ++-- .../logic/installManager/InstallHelpers.ts | 2 +- .../installManager/RushInstallManager.ts | 42 +++++++------- .../installManager/WorkspaceInstallManager.ts | 53 ++++++++--------- .../src/logic/pnpm/PnpmLinkManager.ts | 4 ++ apps/rush-lib/src/utilities/Utilities.ts | 57 ++++++++++--------- .../supportWorkspaces2_2020-06-17-19-59.json | 4 +- common/reviews/api/rush-lib.api.md | 10 +++- 15 files changed, 145 insertions(+), 100 deletions(-) diff --git a/apps/rush-lib/src/api/CommonVersionsConfiguration.ts b/apps/rush-lib/src/api/CommonVersionsConfiguration.ts index fb074c08b76..90514feacec 100644 --- a/apps/rush-lib/src/api/CommonVersionsConfiguration.ts +++ b/apps/rush-lib/src/api/CommonVersionsConfiguration.ts @@ -155,11 +155,16 @@ export class CommonVersionsConfiguration { */ public getPreferredVersionsHash(): string { // Sort so that the hash is stable - const preferredVersionsToHash: Map = new Map( + const orderedPreferredVersions: Map = new Map( this._preferredVersions.protectedView ); - Sort.sortMapKeys(preferredVersionsToHash); - return crypto.createHash('sha1').update(JSON.stringify(preferredVersionsToHash)).digest('hex'); + Sort.sortMapKeys(orderedPreferredVersions); + + // JSON.stringify does not support maps, so we need to convert to an object first + const preferredVersionsObj: { [dependency: string]: string } = MapExtensions.toObject( + orderedPreferredVersions + ); + return crypto.createHash('sha1').update(JSON.stringify(preferredVersionsObj)).digest('hex'); } /** diff --git a/apps/rush-lib/src/api/PackageJsonEditor.ts b/apps/rush-lib/src/api/PackageJsonEditor.ts index 62e7d8eeafe..a6a5c82e5fc 100644 --- a/apps/rush-lib/src/api/PackageJsonEditor.ts +++ b/apps/rush-lib/src/api/PackageJsonEditor.ts @@ -201,6 +201,8 @@ export class PackageJsonEditor { this._onChange.bind(this) ); + // Rush collapses everything that isn't a devDependency into the dependencies + // field, so we need to set the value dependening on dependency type if ( dependencyType === DependencyType.Regular || dependencyType === DependencyType.Optional || diff --git a/apps/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts b/apps/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts index 61b88d4afa6..b3753e3ca77 100644 --- a/apps/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts +++ b/apps/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts @@ -138,14 +138,12 @@ export class GlobalScriptAction extends BaseScriptAction { console.log(`Installing dependencies under ${this._autoinstallerNameFullPath}...\n`); - Utilities.executeCommand( - this.rushConfiguration.packageManagerToolFilename, - ['install', '--frozen-lockfile'], - this._autoinstallerNameFullPath, - undefined, - /* suppressOutput */ false, - /* keepEnvironment */ true - ); + Utilities.executeCommand({ + command: this.rushConfiguration.packageManagerToolFilename, + args: ['install', '--frozen-lockfile'], + workingDirectory: this._autoinstallerNameFullPath, + keepEnvironment: true + }); // Create file: ../common/autoinstallers/my-task/.rush/temp/last-install.flag lastInstallFlag.create(); diff --git a/apps/rush-lib/src/cli/test/Cli.test.ts b/apps/rush-lib/src/cli/test/Cli.test.ts index b9577fc8440..e2372c8f4b3 100644 --- a/apps/rush-lib/src/cli/test/Cli.test.ts +++ b/apps/rush-lib/src/cli/test/Cli.test.ts @@ -11,7 +11,12 @@ describe('CLI', () => { const startPath: string = path.resolve(path.join(__dirname, '../../start.js')); expect(() => { - Utilities.executeCommand('node', [startPath], workingDir, undefined, true); + Utilities.executeCommand({ + command: 'node', + args: [startPath], + workingDirectory: workingDir, + suppressOutput: true + }); }).not.toThrow(); }); }); diff --git a/apps/rush-lib/src/index.ts b/apps/rush-lib/src/index.ts index 969686353d6..7a31829cc75 100644 --- a/apps/rush-lib/src/index.ts +++ b/apps/rush-lib/src/index.ts @@ -39,6 +39,8 @@ export { CommonVersionsConfiguration } from './api/CommonVersionsConfiguration'; export { PackageJsonEditor, PackageJsonDependency, DependencyType } from './api/PackageJsonEditor'; +export { RepoStateFile } from './logic/RepoStateFile'; + export { EventHooks, Event } from './api/EventHooks'; export { ChangeManager } from './api/ChangeManager'; diff --git a/apps/rush-lib/src/logic/PublishUtilities.ts b/apps/rush-lib/src/logic/PublishUtilities.ts index 8ccd8017e8b..00700abcf60 100644 --- a/apps/rush-lib/src/logic/PublishUtilities.ts +++ b/apps/rush-lib/src/logic/PublishUtilities.ts @@ -212,7 +212,14 @@ export class PublishUtilities { ); if (shouldExecute) { - Utilities.executeCommand(command, args, workingDirectory, environment, false, true); + Utilities.executeCommand({ + command, + args, + workingDirectory, + environment, + suppressOutput: false, + keepEnvironment: true + }); } } diff --git a/apps/rush-lib/src/logic/RepoStateFile.ts b/apps/rush-lib/src/logic/RepoStateFile.ts index 3a5ebc71efd..5de164089ce 100644 --- a/apps/rush-lib/src/logic/RepoStateFile.ts +++ b/apps/rush-lib/src/logic/RepoStateFile.ts @@ -9,9 +9,10 @@ import { PnpmShrinkwrapFile } from './pnpm/PnpmShrinkwrapFile'; import { CommonVersionsConfiguration } from '../api/CommonVersionsConfiguration'; /** - * This interface represents the raw pnpm-workspace.YAML file + * This interface represents the raw repo-state.json file * Example: * { + * "pnpmShrinkwrapHash": "...", * "preferredVersionsHash": "..." * } */ @@ -29,6 +30,8 @@ interface IRepoStateJson { /** * This file is used to track the state of various Rush-related features. It is generated * and updated by Rush. + * + * @public */ export class RepoStateFile { private static _jsonSchema: JsonSchema = JsonSchema.fromFile( @@ -78,6 +81,9 @@ export class RepoStateFile { /** * Loads the repo-state.json data from the specified file path. * If the file has not been created yet, then an empty object is returned. + * + * @param jsonFilename - The path to the repo-state.json file. + * @param variant - The variant currently being used by Rush. */ public static loadFromFile(jsonFilename: string, variant: string | undefined): RepoStateFile { let repoStateJson: IRepoStateJson | undefined = undefined; @@ -92,6 +98,14 @@ export class RepoStateFile { return new RepoStateFile(repoStateJson, jsonFilename, variant); } + /** + * Refresh the data contained in repo-state.json using the current state + * of the Rush repo, and save the file if changes were made. + * + * @param rushConfiguration - The Rush configuration for the repo. + * + * @returns true if the file was modified, otherwise false. + */ public refreshState(rushConfiguration: RushConfiguration): boolean { // Only support saving the pnpm shrinkwrap hash if it was enabled const preventShrinkwrapChanges: boolean = diff --git a/apps/rush-lib/src/logic/base/BaseInstallManager.ts b/apps/rush-lib/src/logic/base/BaseInstallManager.ts index 3b54e2c8858..785c6495aec 100644 --- a/apps/rush-lib/src/logic/base/BaseInstallManager.ts +++ b/apps/rush-lib/src/logic/base/BaseInstallManager.ts @@ -147,7 +147,7 @@ export abstract class BaseInstallManager { } public async doInstall(): Promise { - const { shrinkwrapIsUpToDate, variantIsUpToDate } = await this.prepare(); + const { shrinkwrapIsUpToDate, variantIsUpToDate } = await this.prepareAsync(); // This marker file indicates that the last "rush install" completed successfully. // If "--purge" was specified, or if the last install was interrupted, then we will need to @@ -184,7 +184,7 @@ export abstract class BaseInstallManager { this._commonTempInstallFlag.clear(); // Perform the actual install - await this.install(cleanInstall); + await this.installAsync(cleanInstall); const usePnpmFrozenLockfile: boolean = this._rushConfiguration.packageManager === 'pnpm' && @@ -228,15 +228,15 @@ export abstract class BaseInstallManager { } } - protected abstract prepareAndCheckShrinkwrap( + protected abstract prepareCommonTempAsync( shrinkwrapFile: BaseShrinkwrapFile | undefined ): Promise<{ shrinkwrapIsUpToDate: boolean; shrinkwrapWarnings: string[] }>; protected abstract canSkipInstall(lastInstallDate: Date): boolean; - protected abstract install(cleanInstall: boolean): Promise; + protected abstract installAsync(cleanInstall: boolean): Promise; - protected async prepare(): Promise<{ variantIsUpToDate: boolean; shrinkwrapIsUpToDate: boolean }> { + protected async prepareAsync(): Promise<{ variantIsUpToDate: boolean; shrinkwrapIsUpToDate: boolean }> { // Check the policies PolicyValidator.validatePolicy(this._rushConfiguration, this.options); @@ -366,7 +366,7 @@ export abstract class BaseInstallManager { // Allow for package managers to do their own preparation and check that the shrinkwrap is up to date // eslint-disable-next-line prefer-const - let { shrinkwrapIsUpToDate, shrinkwrapWarnings } = await this.prepareAndCheckShrinkwrap(shrinkwrapFile); + let { shrinkwrapIsUpToDate, shrinkwrapWarnings } = await this.prepareCommonTempAsync(shrinkwrapFile); shrinkwrapIsUpToDate = shrinkwrapIsUpToDate && !this.options.recheckShrinkwrap; // Write out the reported warnings diff --git a/apps/rush-lib/src/logic/installManager/InstallHelpers.ts b/apps/rush-lib/src/logic/installManager/InstallHelpers.ts index 2551d489bf9..464a257fc01 100644 --- a/apps/rush-lib/src/logic/installManager/InstallHelpers.ts +++ b/apps/rush-lib/src/logic/installManager/InstallHelpers.ts @@ -106,7 +106,7 @@ export class InstallHelpers { const implicitlyPreferred: Map = new Map(); versionsForDependencies.forEach((versions: Set, dep: string) => { if (versions.size === 1) { - const version: string = versions.values().next().value; + const version: string = Array.from(versions)[0]; implicitlyPreferred.set(dep, version); } }); diff --git a/apps/rush-lib/src/logic/installManager/RushInstallManager.ts b/apps/rush-lib/src/logic/installManager/RushInstallManager.ts index f6bfbdbbf66..f7ace96acd3 100644 --- a/apps/rush-lib/src/logic/installManager/RushInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/RushInstallManager.ts @@ -57,7 +57,7 @@ export class RushInstallManager extends BaseInstallManager { * * @override */ - protected async prepareAndCheckShrinkwrap( + protected async prepareCommonTempAsync( shrinkwrapFile: BaseShrinkwrapFile | undefined ): Promise<{ shrinkwrapIsUpToDate: boolean; shrinkwrapWarnings: string[] }> { const stopwatch: Stopwatch = Stopwatch.start(); @@ -165,7 +165,7 @@ export class RushInstallManager extends BaseInstallManager { // These can be regular, optional, or peer dependencies (but NOT dev dependencies). // (A given packageName will never appear more than once in this list.) for (const dependency of packageJson.dependencyList) { - if (this._revertWorkspaceNotation(dependency)) { + if (this.options.fullUpgrade && this._revertWorkspaceNotation(dependency)) { shrinkwrapIsUpToDate = false; } @@ -181,7 +181,7 @@ export class RushInstallManager extends BaseInstallManager { } for (const dependency of packageJson.devDependencyList) { - if (this._revertWorkspaceNotation(dependency)) { + if (this.options.fullUpgrade && this._revertWorkspaceNotation(dependency)) { shrinkwrapIsUpToDate = false; } @@ -449,7 +449,7 @@ export class RushInstallManager extends BaseInstallManager { * * @override */ - protected async install(cleanInstall: boolean): Promise { + protected async installAsync(cleanInstall: boolean): Promise { // Since we are actually running npm/pnpm/yarn install, recreate all the temp project tarballs. // This ensures that any existing tarballs with older header bits will be regenerated. // It is safe to assume that temp project pacakge.jsons already exist. @@ -508,11 +508,13 @@ export class RushInstallManager extends BaseInstallManager { this.pushConfigurationArgs(args, this.options); Utilities.executeCommandWithRetry( - this.options.maxInstallAttempts, - packageManagerFilename, - args, - this.rushConfiguration.commonTempFolder, - packageManagerEnv + { + command: packageManagerFilename, + args: args, + workingDirectory: this.rushConfiguration.commonTempFolder, + environment: packageManagerEnv + }, + this.options.maxInstallAttempts ); // Delete the (installed image of) the temp projects, since "npm install" does not @@ -582,12 +584,14 @@ export class RushInstallManager extends BaseInstallManager { try { Utilities.executeCommandWithRetry( + { + command: packageManagerFilename, + args: installArgs, + workingDirectory: this.rushConfiguration.commonTempFolder, + environment: packageManagerEnv, + suppressOutput: false + }, this.options.maxInstallAttempts, - packageManagerFilename, - installArgs, - this.rushConfiguration.commonTempFolder, - packageManagerEnv, - false, () => { if (this.rushConfiguration.packageManager === 'pnpm') { console.log(colors.yellow(`Deleting the "node_modules" folder`)); @@ -622,11 +626,11 @@ export class RushInstallManager extends BaseInstallManager { console.log(os.EOL + colors.bold('Running "npm shrinkwrap"...')); const npmArgs: string[] = ['shrinkwrap']; this.pushConfigurationArgs(npmArgs, this.options); - Utilities.executeCommand( - this.rushConfiguration.packageManagerToolFilename, - npmArgs, - this.rushConfiguration.commonTempFolder - ); + Utilities.executeCommand({ + command: this.rushConfiguration.packageManagerToolFilename, + args: npmArgs, + workingDirectory: this.rushConfiguration.commonTempFolder + }); console.log('"npm shrinkwrap" completed' + os.EOL); this._fixupNpm5Regression(); diff --git a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts index 41d256f24a1..2717a47c13e 100644 --- a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -13,7 +13,6 @@ import { BaseShrinkwrapFile } from '../../logic/base/BaseShrinkwrapFile'; import { DependencySpecifier } from '../DependencySpecifier'; import { PackageJsonEditor, DependencyType } from '../../api/PackageJsonEditor'; import { PnpmWorkspaceFile } from '../pnpm/PnpmWorkspaceFile'; -import { RushConfiguration } from '../../api/RushConfiguration'; import { RushConfigurationProject } from '../../api/RushConfigurationProject'; import { RushConstants } from '../../logic/RushConstants'; import { Stopwatch } from '../../utilities/Stopwatch'; @@ -26,15 +25,6 @@ import { RepoStateFile } from '../RepoStateFile'; * This class implements common logic between "rush install" and "rush update". */ export class WorkspaceInstallManager extends BaseInstallManager { - public static getCommonWorkspaceKey(rushConfiguration: RushConfiguration): string { - switch (rushConfiguration.packageManager) { - case 'pnpm': - return '.'; - default: - throw new InternalError('Not implemented'); - } - } - /** * @override */ @@ -55,14 +45,14 @@ export class WorkspaceInstallManager extends BaseInstallManager { } /** - * Regenerates the common/package.json and related workspace files. + * Regenerates the common/temp/package.json and related workspace files. * If shrinkwrapFile is provided, this function also validates whether it contains * everything we need to install and returns true if so; in all other cases, * the return value is false. * * @override */ - protected async prepareAndCheckShrinkwrap( + protected async prepareCommonTempAsync( shrinkwrapFile: BaseShrinkwrapFile | undefined ): Promise<{ shrinkwrapIsUpToDate: boolean; shrinkwrapWarnings: string[] }> { const stopwatch: Stopwatch = Stopwatch.start(); @@ -188,16 +178,18 @@ export class WorkspaceInstallManager extends BaseInstallManager { throw new AlreadyReportedError(); } - // We will update to `workspace` notation. If the version specified is a range, then use the provided range. - // Otherwise, use `workspace:*` to ensure we're always using the workspace package. - const workspaceRange: string = - !!semver.validRange(dependencySpecifier.versionSpecifier) && - !semver.valid(dependencySpecifier.versionSpecifier) - ? dependencySpecifier.versionSpecifier - : '*'; - packageJson.addOrUpdateDependency(name, `workspace:${workspaceRange}`, dependencyType); - shrinkwrapIsUpToDate = false; - continue; + if (this.options.fullUpgrade) { + // We will update to `workspace` notation. If the version specified is a range, then use the provided range. + // Otherwise, use `workspace:*` to ensure we're always using the workspace package. + const workspaceRange: string = + !!semver.validRange(dependencySpecifier.versionSpecifier) && + !semver.valid(dependencySpecifier.versionSpecifier) + ? dependencySpecifier.versionSpecifier + : '*'; + packageJson.addOrUpdateDependency(name, `workspace:${workspaceRange}`, dependencyType); + shrinkwrapIsUpToDate = false; + continue; + } } else if (dependencySpecifier.specifierType === 'workspace') { // Already specified as a local project. Allow the package manager to validate this continue; @@ -269,8 +261,7 @@ export class WorkspaceInstallManager extends BaseInstallManager { path.join(this.rushConfiguration.commonTempFolder, RushConstants.nodeModulesFolderName) ); - // Additionally, if they pulled an updated npm-shrinkwrap.json file from Git, - // then we can't skip this install + // Additionally, if they pulled an updated shrinkwrap file from Git, then we can't skip this install potentiallyChangedFiles.push(this.rushConfiguration.getCommittedShrinkwrapFilename(this.options.variant)); // Add common-versions.json file to the potentially changed files list. @@ -311,7 +302,7 @@ export class WorkspaceInstallManager extends BaseInstallManager { /** * Runs "npm install" in the common folder. */ - protected async install(cleanInstall: boolean): Promise { + protected async installAsync(cleanInstall: boolean): Promise { // Example: "C:\MyRepo\common\temp\npm-local\node_modules\.bin\npm" const packageManagerFilename: string = this.rushConfiguration.packageManagerToolFilename; @@ -367,12 +358,14 @@ export class WorkspaceInstallManager extends BaseInstallManager { try { Utilities.executeCommandWithRetry( + { + command: packageManagerFilename, + args: installArgs, + workingDirectory: this.rushConfiguration.commonTempFolder, + environment: packageManagerEnv, + suppressOutput: false + }, this.options.maxInstallAttempts, - packageManagerFilename, - installArgs, - this.rushConfiguration.commonTempFolder, - packageManagerEnv, - false, () => { if (this.rushConfiguration.packageManager === 'pnpm') { console.log(colors.yellow(`Deleting the "node_modules" folder`)); diff --git a/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts b/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts index 2475037dda0..5a67409695d 100644 --- a/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts +++ b/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts @@ -307,6 +307,10 @@ export class PnpmLinkManager extends BaseLinkManager { /** * This is called once for each local project from Rush.json. + * + * TODO: This should be moved into WorkspaceInstallManager directly, since there is no actual linking + * being done by Rush for this style of install. + * * @param project The local project that we will create symlinks for * @param rushLinkJson The common/temp/rush-link.json output file */ diff --git a/apps/rush-lib/src/utilities/Utilities.ts b/apps/rush-lib/src/utilities/Utilities.ts index d61d658ddf8..4cec356fc3d 100644 --- a/apps/rush-lib/src/utilities/Utilities.ts +++ b/apps/rush-lib/src/utilities/Utilities.ts @@ -19,6 +19,18 @@ export interface IEnvironment { [environmentVariableName: string]: string | undefined; } +/** + * Options for Utilities.executeCommand(). + */ +export interface IExecuteCommandOptions { + command: string; + args: string[]; + workingDirectory: string; + environment?: IEnvironment; + suppressOutput?: boolean; + keepEnvironment?: boolean; +} + /** * Options for Utilities.installPackageInDirectory(). */ @@ -321,21 +333,14 @@ export class Utilities { * Executes the command with the specified command-line parameters, and waits for it to complete. * The current directory will be set to the specified workingDirectory. */ - public static executeCommand( - command: string, - args: string[], - workingDirectory: string, - environment?: IEnvironment, - suppressOutput: boolean = false, - keepEnvironment: boolean = false - ): void { + public static executeCommand(options: IExecuteCommandOptions): void { Utilities._executeCommandInternal( - command, - args, - workingDirectory, - suppressOutput ? undefined : [0, 1, 2], - environment, - keepEnvironment + options.command, + options.args, + options.workingDirectory, + options.suppressOutput ? undefined : [0, 1, 2], + options.environment, + options.keepEnvironment ); } @@ -366,12 +371,8 @@ export class Utilities { * Attempts to run Utilities.executeCommand() up to maxAttempts times before giving up. */ public static executeCommandWithRetry( + options: IExecuteCommandOptions, maxAttempts: number, - command: string, - args: string[], - workingDirectory: string, - environment?: IEnvironment, - suppressOutput: boolean = false, retryCallback?: () => void ): void { if (maxAttempts < 1) { @@ -382,10 +383,10 @@ export class Utilities { for (;;) { try { - Utilities.executeCommand(command, args, workingDirectory, environment, suppressOutput); + Utilities.executeCommand(options); } catch (error) { console.log(os.EOL + 'The command failed:'); - console.log(` ${command} ` + args.join(' ')); + console.log(` ${options.command} ` + options.args.join(' ')); console.log(`ERROR: ${error.toString()}`); if (attemptNumber < maxAttempts) { @@ -481,12 +482,14 @@ export class Utilities { // NOTE: Here we use whatever version of NPM we happen to find in the PATH Utilities.executeCommandWithRetry( - options.maxInstallAttempts, - 'npm', - ['install'], - directory, - Utilities._createEnvironmentForRushCommand({}), - options.suppressOutput + { + command: 'npm', + args: ['install'], + workingDirectory: directory, + environment: Utilities._createEnvironmentForRushCommand({}), + suppressOutput: options.suppressOutput + }, + options.maxInstallAttempts ); } diff --git a/common/changes/@microsoft/rush/supportWorkspaces2_2020-06-17-19-59.json b/common/changes/@microsoft/rush/supportWorkspaces2_2020-06-17-19-59.json index 0143cb521c2..d918ca72cfb 100644 --- a/common/changes/@microsoft/rush/supportWorkspaces2_2020-06-17-19-59.json +++ b/common/changes/@microsoft/rush/supportWorkspaces2_2020-06-17-19-59.json @@ -2,8 +2,8 @@ "changes": [ { "packageName": "@microsoft/rush", - "comment": "", - "type": "none" + "comment": "Add preliminary workspaces support for PNPM", + "type": "minor" } ], "packageName": "@microsoft/rush", diff --git a/common/reviews/api/rush-lib.api.md b/common/reviews/api/rush-lib.api.md index e0fac2dd2eb..56e4fd7853b 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -297,6 +297,15 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration // @public export type PnpmStoreOptions = 'local' | 'global'; +// @public +export class RepoStateFile { + readonly filePath: string; + static loadFromFile(jsonFilename: string, variant: string | undefined): RepoStateFile; + readonly pnpmShrinkwrapHash: string | undefined; + readonly preferredVersionsHash: string | undefined; + refreshState(rushConfiguration: RushConfiguration): boolean; + } + // @public export type ResolutionStrategy = 'fewer-dependencies' | 'fast'; @@ -334,7 +343,6 @@ export class RushConfiguration { getCommonVersionsFilePath(variant?: string | undefined): string; getPnpmfilePath(variant?: string | undefined): string; getProjectByName(projectName: string): RushConfigurationProject | undefined; - // Warning: (ae-forgotten-export) The symbol "RepoStateFile" needs to be exported by the entry point index.d.ts getRepoState(variant?: string | undefined): RepoStateFile; getRepoStateFilePath(variant?: string | undefined): string; readonly gitAllowedEmailRegExps: string[]; From e94bfa19f8977e10e093d92b3b0ef1e613164ea1 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Tue, 30 Jun 2020 16:24:52 -0700 Subject: [PATCH 23/33] Fix RepoStateFile serialization error --- apps/rush-lib/src/logic/RepoStateFile.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/rush-lib/src/logic/RepoStateFile.ts b/apps/rush-lib/src/logic/RepoStateFile.ts index 5de164089ce..23bffc9f36a 100644 --- a/apps/rush-lib/src/logic/RepoStateFile.ts +++ b/apps/rush-lib/src/logic/RepoStateFile.ts @@ -164,10 +164,15 @@ export class RepoStateFile { } private _serialize(): string { - const repoStateJson: IRepoStateJson = { - pnpmShrinkwrapHash: this.pnpmShrinkwrapHash, - preferredVersionsHash: this.preferredVersionsHash - }; + // We need to set these one-by-one, since JsonFile.stringify does not like undefined values + const repoStateJson: IRepoStateJson = {}; + if (this._pnpmShrinkwrapHash) { + repoStateJson.pnpmShrinkwrapHash = this._pnpmShrinkwrapHash; + } + if (this._preferredVersionsHash) { + repoStateJson.preferredVersionsHash = this._preferredVersionsHash; + } + return JsonFile.stringify(repoStateJson, { newlineConversion: NewlineKind.Lf }); } } From c83abf7cc04563ea85156c318e7ecf7176cefcff Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Wed, 1 Jul 2020 12:45:33 -0700 Subject: [PATCH 24/33] Add "workspaces" property to the last-install.flag file --- apps/rush-lib/src/logic/base/BaseInstallManager.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/rush-lib/src/logic/base/BaseInstallManager.ts b/apps/rush-lib/src/logic/base/BaseInstallManager.ts index 785c6495aec..102e32dc360 100644 --- a/apps/rush-lib/src/logic/base/BaseInstallManager.ts +++ b/apps/rush-lib/src/logic/base/BaseInstallManager.ts @@ -120,8 +120,11 @@ export abstract class BaseInstallManager { packageManagerVersion: rushConfiguration.packageManagerToolVersion }; - if (lastInstallState.packageManager === 'pnpm') { + if (lastInstallState.packageManager === 'pnpm' && rushConfiguration.pnpmOptions) { lastInstallState.storePath = rushConfiguration.pnpmOptions.pnpmStorePath; + if (rushConfiguration.pnpmOptions.useWorkspaces) { + lastInstallState.workspaces = rushConfiguration.pnpmOptions.useWorkspaces; + } } this._commonTempInstallFlag = new LastInstallFlag( From 952b0bc5c260af82a772b7de0aabf8431197b32c Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Thu, 2 Jul 2020 18:50:37 -0700 Subject: [PATCH 25/33] Add SpecifierType enum --- .../rush-lib/src/logic/DependencySpecifier.ts | 108 ++++++++++++++---- apps/rush-lib/src/logic/PublishUtilities.ts | 13 ++- .../src/logic/base/BaseShrinkwrapFile.ts | 10 +- .../installManager/RushInstallManager.ts | 4 +- .../installManager/WorkspaceInstallManager.ts | 8 +- .../src/logic/pnpm/PnpmLinkManager.ts | 6 +- 6 files changed, 108 insertions(+), 41 deletions(-) diff --git a/apps/rush-lib/src/logic/DependencySpecifier.ts b/apps/rush-lib/src/logic/DependencySpecifier.ts index 6249004dac5..d503f296058 100644 --- a/apps/rush-lib/src/logic/DependencySpecifier.ts +++ b/apps/rush-lib/src/logic/DependencySpecifier.ts @@ -4,6 +4,56 @@ import npmPackageArg = require('npm-package-arg'); import { InternalError } from '@rushstack/node-core-library'; +/** + * The parsed format of a provided version specifier. + */ +export const enum SpecifierType { + /** + * A git repository + */ + Git = 'Git', + + /** + * A tagged version, e.g. "example@latest" + */ + Tag = 'Tag', + + /** + * A specific version number, e.g. "example@1.2.3" + */ + Version = 'Version', + + /** + * A version range, e.g. "example@2.x" + */ + Range = 'Range', + + /** + * A local .tar.gz, .tar or .tgz file + */ + File = 'File', + + /** + * A local directory + */ + Directory = 'Directory', + + /** + * An HTTP url to a .tar.gz, .tar or .tgz file + */ + Remote = 'Remote', + + /** + * A package alias, e.g. "npm:other-package@^1.2.3" + */ + Alias = 'Alias', + + /** + * A package specified using workspace protocol, e.g. "workspace:^1.2.3" + */ + Workspace = 'Workspace' +} + /** * An NPM "version specifier" is a string that can appear as a package.json "dependencies" value. * Example version specifiers: `^1.2.3`, `file:./blah.tgz`, `npm:other-package@~1.2.3`, and so forth. @@ -22,19 +72,9 @@ export class DependencySpecifier { public readonly versionSpecifier: string; /** - * The type of `versionSpecifier`: - * - * git - a git repository - * tag - a tagged version, e.g. "example@latest" - * version - A specific version number, e.g. "example@1.2.3" - * range - A version range, e.g. "example@2.x" - * file - A local .tar.gz, .tar or .tgz file - * directory - A local directory - * remote - An HTTP url to a .tar.gz, .tar or .tgz file - * alias - A package alias such as "npm:other-package@^1.2.3" - * workspace - A package specified using workspace protocol such as "workspace:^1.2.3" + * The type of the `versionSpecifier`. */ - public readonly specifierType: string; + public readonly specifierType: SpecifierType; /** * If `specifierType` is `alias`, then this is the parsed target dependency. @@ -50,24 +90,48 @@ export class DependencySpecifier { // Workspace ranges are a feature from PNPM and Yarn. Set the version specifier // to the trimmed version range. if (versionSpecifier.startsWith('workspace:')) { - this.specifierType = 'workspace'; + this.specifierType = SpecifierType.Workspace; this.versionSpecifier = versionSpecifier.slice(this.specifierType.length + 1).trim(); this.aliasTarget = undefined; return; } - const result: npmPackageArg.AliasResult = npmPackageArg.resolve( - packageName, - versionSpecifier - ) as npmPackageArg.AliasResult; - - this.specifierType = result.type; + const result: npmPackageArg.Result = npmPackageArg.resolve(packageName, versionSpecifier); + switch (result.type) { + case 'git': + this.specifierType = SpecifierType.Git; + break; + case 'tag': + this.specifierType = SpecifierType.Tag; + break; + case 'version': + this.specifierType = SpecifierType.Version; + break; + case 'range': + this.specifierType = SpecifierType.Range; + break; + case 'file': + this.specifierType = SpecifierType.File; + break; + case 'directory': + this.specifierType = SpecifierType.Directory; + break; + case 'remote': + this.specifierType = SpecifierType.Remote; + break; + case 'alias': + this.specifierType = SpecifierType.Alias; + break; + default: + throw new InternalError(`Unexpected npm-package-arg result type "${result.type}"`); + } - if (result.type === 'alias') { - if (!result.subSpec || !result.subSpec.name) { + if (this.specifierType === SpecifierType.Alias) { + const aliasResult: npmPackageArg.AliasResult = result as npmPackageArg.AliasResult; + if (!aliasResult.subSpec || !aliasResult.subSpec.name) { throw new InternalError('Unexpected result from npm-package-arg'); } - this.aliasTarget = new DependencySpecifier(result.subSpec.name, result.subSpec.rawSpec); + this.aliasTarget = new DependencySpecifier(aliasResult.subSpec.name, aliasResult.subSpec.rawSpec); } else { this.aliasTarget = undefined; } diff --git a/apps/rush-lib/src/logic/PublishUtilities.ts b/apps/rush-lib/src/logic/PublishUtilities.ts index 00700abcf60..72e56c1d324 100644 --- a/apps/rush-lib/src/logic/PublishUtilities.ts +++ b/apps/rush-lib/src/logic/PublishUtilities.ts @@ -19,7 +19,7 @@ import { execSync } from 'child_process'; import { PrereleaseToken } from './PrereleaseToken'; import { ChangeFiles } from './ChangeFiles'; import { RushConfiguration } from '../api/RushConfiguration'; -import { DependencySpecifier } from './DependencySpecifier'; +import { DependencySpecifier, SpecifierType } from './DependencySpecifier'; export interface IChangeInfoHash { [key: string]: IChangeInfo; @@ -246,7 +246,7 @@ export class PublishUtilities { } else { newDependencyVersion = newProjectVersion; } - return currentDependencySpecifier.specifierType === 'workspace' + return currentDependencySpecifier.specifierType === SpecifierType.Workspace ? `workspace:${newDependencyVersion}` : newDependencyVersion; } @@ -434,7 +434,9 @@ export class PublishUtilities { ); const newVersion: string = PublishUtilities._getChangeInfoNewVersion(depChange, prereleaseToken); dependencies[depName] = - currentSpecifier.specifierType === 'workspace' ? `workspace:${newVersion}` : newVersion; + currentSpecifier.specifierType === SpecifierType.Workspace + ? `workspace:${newVersion}` + : newVersion; } else if (depChange && depChange.changeType! >= ChangeType.hotfix) { PublishUtilities._updateDependencyVersion( packageName, @@ -712,7 +714,7 @@ export class PublishUtilities { currentDependencyVersion ); currentDependencyVersion = - currentDependencySpecifier.specifierType === 'workspace' && + currentDependencySpecifier.specifierType === SpecifierType.Workspace && currentDependencySpecifier.versionSpecifier === '*' ? undefined : currentDependencySpecifier.versionSpecifier; @@ -722,7 +724,8 @@ export class PublishUtilities { newDependencyVersion ); newDependencyVersion = - newDependencySpecifier.specifierType === 'workspace' && newDependencySpecifier.versionSpecifier === '*' + newDependencySpecifier.specifierType === SpecifierType.Workspace && + newDependencySpecifier.versionSpecifier === '*' ? dependencyChange.newVersion! : newDependencySpecifier.versionSpecifier; diff --git a/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts b/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts index fe7ebc9b14e..8235c1f0f92 100644 --- a/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts +++ b/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts @@ -6,7 +6,7 @@ import * as semver from 'semver'; import { FileSystem } from '@rushstack/node-core-library'; import { RushConstants } from '../../logic/RushConstants'; -import { DependencySpecifier } from '../DependencySpecifier'; +import { DependencySpecifier, SpecifierType } from '../DependencySpecifier'; import { IShrinkwrapFilePolicyValidatorOptions } from '../policy/ShrinkwrapFilePolicy'; import { PackageManagerOptionsConfigurationBase } from '../../api/RushConfiguration'; import { PackageNameParsers } from '../../api/PackageNameParsers'; @@ -193,9 +193,9 @@ export abstract class BaseShrinkwrapFile { // // In this case, the shrinkwrap file will have a key equivalent to "npm:target-name@1.2.5", // and so we need to unwrap the target and compare "1.2.5" with "^1.2.3". - if (projectDependency.specifierType === 'alias') { + if (projectDependency.specifierType === SpecifierType.Alias) { // Does the shrinkwrap install it as an alias? - if (shrinkwrapDependency.specifierType === 'alias') { + if (shrinkwrapDependency.specifierType === SpecifierType.Alias) { // Does the shrinkwrap have the right package name? if (projectDependency.packageName === shrinkwrapDependency.packageName) { // Yes, the aliases match, so let's compare their targets in the logic below @@ -212,8 +212,8 @@ export abstract class BaseShrinkwrapFile { } switch (normalizedProjectDependency.specifierType) { - case 'version': - case 'range': + case SpecifierType.Version: + case SpecifierType.Range: return semver.satisfies( normalizedShrinkwrapDependency.versionSpecifier, normalizedProjectDependency.versionSpecifier diff --git a/apps/rush-lib/src/logic/installManager/RushInstallManager.ts b/apps/rush-lib/src/logic/installManager/RushInstallManager.ts index f7ace96acd3..004cf355e83 100644 --- a/apps/rush-lib/src/logic/installManager/RushInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/RushInstallManager.ts @@ -26,7 +26,7 @@ import { RushConstants } from '../../logic/RushConstants'; import { Stopwatch } from '../../utilities/Stopwatch'; import { Utilities } from '../../utilities/Utilities'; import { PackageJsonEditor, DependencyType, PackageJsonDependency } from '../../api/PackageJsonEditor'; -import { DependencySpecifier } from '../DependencySpecifier'; +import { DependencySpecifier, SpecifierType } from '../DependencySpecifier'; import { InstallHelpers } from './InstallHelpers'; import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; @@ -374,7 +374,7 @@ export class RushInstallManager extends BaseInstallManager { private _revertWorkspaceNotation(dependency: PackageJsonDependency): boolean { const specifier: DependencySpecifier = new DependencySpecifier(dependency.name, dependency.version); - if (specifier.specifierType !== 'workspace') { + if (specifier.specifierType !== SpecifierType.Workspace) { return false; } // Replace workspace notation with the supplied version range diff --git a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts index 2717a47c13e..c7929297b68 100644 --- a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -10,7 +10,7 @@ import { FileSystem, InternalError, MapExtensions, NewlineKind } from '@rushstac import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; import { BaseInstallManager, IInstallManagerOptions } from '../base/BaseInstallManager'; import { BaseShrinkwrapFile } from '../../logic/base/BaseShrinkwrapFile'; -import { DependencySpecifier } from '../DependencySpecifier'; +import { DependencySpecifier, SpecifierType } from '../DependencySpecifier'; import { PackageJsonEditor, DependencyType } from '../../api/PackageJsonEditor'; import { PnpmWorkspaceFile } from '../pnpm/PnpmWorkspaceFile'; import { RushConfigurationProject } from '../../api/RushConfigurationProject'; @@ -143,8 +143,8 @@ export class WorkspaceInstallManager extends BaseInstallManager { // cyclic dependency, then it needs to be updated to specify `workspace:*` explicitly. Currently only // supporting versions and version ranges for specifying a local project. if ( - (dependencySpecifier.specifierType === 'version' || - dependencySpecifier.specifierType === 'range') && + (dependencySpecifier.specifierType === SpecifierType.Version || + dependencySpecifier.specifierType === SpecifierType.Range) && referencedLocalProject && !rushProject.cyclicDependencyProjects.has(name) ) { @@ -190,7 +190,7 @@ export class WorkspaceInstallManager extends BaseInstallManager { shrinkwrapIsUpToDate = false; continue; } - } else if (dependencySpecifier.specifierType === 'workspace') { + } else if (dependencySpecifier.specifierType === SpecifierType.Workspace) { // Already specified as a local project. Allow the package manager to validate this continue; } diff --git a/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts b/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts index 5a67409695d..4c1988cf3f5 100644 --- a/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts +++ b/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts @@ -22,7 +22,7 @@ import { } from './PnpmShrinkwrapFile'; import { PnpmProjectDependencyManifest } from './PnpmProjectDependencyManifest'; import { PackageJsonDependency, DependencyType } from '../../api/PackageJsonEditor'; -import { DependencySpecifier } from '../DependencySpecifier'; +import { DependencySpecifier, SpecifierType } from '../DependencySpecifier'; // special flag for debugging, will print extra diagnostic information, // but comes with performance cost @@ -324,7 +324,7 @@ export class PnpmLinkManager extends BaseLinkManager { const localDependencies: PackageJsonDependency[] = [ ...project.packageJsonEditor.dependencyList, ...project.packageJsonEditor.devDependencyList - ].filter((x) => new DependencySpecifier(x.name, x.version).specifierType === 'workspace'); + ].filter((x) => new DependencySpecifier(x.name, x.version).specifierType === SpecifierType.Workspace); for (const { name } of localDependencies) { const matchedRushPackage: @@ -369,7 +369,7 @@ export class PnpmLinkManager extends BaseLinkManager { const dependencies: PackageJsonDependency[] = [ ...project.packageJsonEditor.dependencyList, ...project.packageJsonEditor.devDependencyList - ].filter((x) => new DependencySpecifier(x.name, x.version).specifierType !== 'workspace'); + ].filter((x) => new DependencySpecifier(x.name, x.version).specifierType !== SpecifierType.Workspace); for (const { name, dependencyType } of dependencies) { // read the version number from the shrinkwrap entry From 46a7d3db4a4bb8fad206e3faa057751d54171e68 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Thu, 2 Jul 2020 21:26:17 -0700 Subject: [PATCH 26/33] PR feedback --- .../installManager/WorkspaceInstallManager.ts | 110 +++++------------- apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts | 83 +++++++++++++ 2 files changed, 110 insertions(+), 83 deletions(-) create mode 100644 apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts diff --git a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts index c7929297b68..aa60511c5ce 100644 --- a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -5,7 +5,7 @@ import * as colors from 'colors'; import * as os from 'os'; import * as path from 'path'; import * as semver from 'semver'; -import { FileSystem, InternalError, MapExtensions, NewlineKind } from '@rushstack/node-core-library'; +import { FileSystem, InternalError, MapExtensions } from '@rushstack/node-core-library'; import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; import { BaseInstallManager, IInstallManagerOptions } from '../base/BaseInstallManager'; @@ -419,89 +419,12 @@ export class WorkspaceInstallManager extends BaseInstallManager { * shim will subsequently call into the provided pnpmfile, if one exists. */ protected async createShimPnpmfile(filename: string): Promise { - // Get the versions we want to add to the shim pnpmfile - const allPreferredVersions: Map = InstallHelpers.collectPreferredVersions( - this.rushConfiguration, - this.options - ); - const allowedAlternativeVersions: Map< - string, - ReadonlyArray - > = this.rushConfiguration.getCommonVersions(this.options.variant).allowedAlternativeVersions; - - const clientPnpmfileName: string = 'clientPnpmfile.js'; - const pnpmfileContent: string[] = [ - '// THIS IS A GENERATED FILE. DO NOT MODIFY.', - '"use strict";', - 'module.exports = { hooks: { readPackage, afterAllResolved } };', - - // Obtain the original pnpmfile provided by the repo, if it exists. - 'const { existsSync } = require("fs");', - 'const clientPnpmfile = ', - ` existsSync("${clientPnpmfileName}") ? require("./${path.basename( - clientPnpmfileName, - '.js' - )}") : undefined;`, - // We will require semver from this path on disk, since this is the version of semver shipping with Rush - `const semver = require(${JSON.stringify(require.resolve('semver'))});`, - - // Include all the preferredVersions and allowedAlternativeVersions directly since there is no need to - // generate them on the fly - `const allPreferredVersions = ${JSON.stringify(MapExtensions.toObject(allPreferredVersions))};`, - `const allowedAlternativeVersions = ${JSON.stringify( - MapExtensions.toObject(allowedAlternativeVersions) - )};`, - - // Call the original pnpmfile (if it exists) - 'function afterAllResolved(lockfile, context) {', - ' return (clientPnpmfile && clientPnpmfile.hooks && clientPnpmfile.hooks.afterAllResolved)', - ' ? clientPnpmfile.hooks.afterAllResolved(lockfile, context)', - ' : lockfile;', - '}', - - // Set the preferred versions in the package, then call the original pnpmfile (if it exists) - 'function readPackage(pkg, context) {', - ' setPreferredVersions(pkg.dependencies);', - ' setPreferredVersions(pkg.devDependencies);', - ' setPreferredVersions(pkg.optionalDependencies);', - ' return (clientPnpmfile && clientPnpmfile.hooks && clientPnpmfile.hooks.readPackage)', - ' ? clientPnpmfile.hooks.readPackage(pkg, context)', - ' : pkg;', - '}', - - // Set the preferred versions on the dependency map. If the version on the map is an allowedAlternativeVersion - // then skip it. Otherwise, check to ensure that the common version is a subset of the specified version. If - // it is, then replace the specified version with the preferredVersion - 'function setPreferredVersions(dependencies) {', - ' for (const name of Object.keys(dependencies || {})) {', - ' if (allPreferredVersions.hasOwnProperty(name)) {', - ' const preferredVersion = allPreferredVersions[name];', - ' const version = dependencies[name];', - ' if (allowedAlternativeVersions.hasOwnProperty(name)) {', - ' const allowedAlternatives = allowedAlternativeVersions[name];', - ' if (allowedAlternatives && allowedAlternatives.indexOf(version) > -1) {', - ' continue;', - ' }', - ' }', - ' let isValidRange = false;', - ' try {', - ' isValidRange = !!semver.validRange(preferredVersion) && !!semver.validRange(version);', - ' } catch {', - ' }', - ' if (isValidRange && semver.subset(preferredVersion, version)) {', - ' dependencies[name] = preferredVersion;', - ' }', - ' }', - ' }', - '}' - ]; - // Attempt to move the existing pnpmfile if there is one try { const pnpmfileDir: string = path.dirname(filename); await FileSystem.moveAsync({ sourcePath: filename, - destinationPath: path.join(pnpmfileDir, clientPnpmfileName) + destinationPath: path.join(pnpmfileDir, 'clientPnpmfile.js') }); } catch (error) { if (!FileSystem.isNotExistError(error)) { @@ -509,10 +432,31 @@ export class WorkspaceInstallManager extends BaseInstallManager { } } - // Write the shim pnpmfile to the original file path - await FileSystem.writeFileAsync(filename, pnpmfileContent.join(NewlineKind.Lf), { - ensureFolderExists: true - }); + // Read the shim pnpmfile and replace the placeholders + let pnpmfileContent: string = await FileSystem.readFileAsync( + path.resolve(__dirname, '..', 'pnpm', 'PnpmfileShim.js') + ); + pnpmfileContent = pnpmfileContent.replace( + /__semverPath/, + JSON.stringify(require.resolve('semver')).replace(/^"|"$/g, '') + ); + pnpmfileContent = pnpmfileContent.replace( + /__allowedAlternativeVersions/, + JSON.stringify( + MapExtensions.toObject( + this.rushConfiguration.getCommonVersions(this.options.variant).allowedAlternativeVersions + ) + ) + ); + pnpmfileContent = pnpmfileContent.replace( + /__allPreferredVersions/, + JSON.stringify( + MapExtensions.toObject(InstallHelpers.collectPreferredVersions(this.rushConfiguration, this.options)) + ) + ); + + // Save the shim pnpmfile to the original path + await FileSystem.writeFileAsync(filename, pnpmfileContent, { ensureFolderExists: true }); } /** diff --git a/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts b/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts new file mode 100644 index 00000000000..f8648c12e51 --- /dev/null +++ b/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts @@ -0,0 +1,83 @@ +// THIS FILE IS PROVIDED BY RUSH. ANY MODIFICATIONS WILL BE OVERWRITTEN. +import { existsSync } from 'fs'; + +interface ILockfile {} + +interface IPackageJson { + dependencies?: { [dependencyName: string]: string }; + devDependencies?: { [dependencyName: string]: string }; + optionalDependencies?: { [dependencyName: string]: string }; +} + +interface IPnpmfile { + hooks?: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + afterAllResolved?: (lockfile: ILockfile, context: any) => ILockfile; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + readPackage?: (pkg: IPackageJson, context: any) => IPackageJson; + }; +} + +// We will require semver from this path on disk, since this is the version of semver shipping with Rush +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const semver: any = require('__semverPath'); +// Only require the client pnpmfile if it exists +const clientPnpmfile: IPnpmfile | undefined = existsSync('clientPnpmfile.js') + ? require('./clientPnpmfile') + : undefined; +const allPreferredVersions: { [dependencyName: string]: string } = JSON.parse('__allPreferredVersions'); +const allowedAlternativeVersions: { [dependencyName: string]: string[] } = JSON.parse( + '__allowedAlternativeVersions' +); + +// Set the preferred versions on the dependency map. If the version on the map is an allowedAlternativeVersion +// then skip it. Otherwise, check to ensure that the common version is a subset of the specified version. If +// it is, then replace the specified version with the preferredVersion +function setPreferredVersions(dependencies?: { [dependencyName: string]: string }): void { + for (const name of Object.keys(dependencies || {})) { + if (allPreferredVersions.hasOwnProperty(name)) { + const preferredVersion: string = allPreferredVersions[name]; + const version: string = dependencies![name]; + if (allowedAlternativeVersions.hasOwnProperty(name)) { + const allowedAlternatives: string[] | undefined = allowedAlternativeVersions[name]; + if (allowedAlternatives && allowedAlternatives.indexOf(version) > -1) { + continue; + } + } + let isValidRange: boolean = false; + try { + isValidRange = !!semver.validRange(preferredVersion) && !!semver.validRange(version); + } catch { + // Swallow invalid range errors + } + if (isValidRange && semver.subset(preferredVersion, version)) { + dependencies![name] = preferredVersion; + } + } + } +} + +const pnpmfileShim: IPnpmfile = { + hooks: { + // Call the original pnpmfile (if it exists) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + afterAllResolved: (lockfile: ILockfile, context: any) => { + return clientPnpmfile && clientPnpmfile.hooks && clientPnpmfile.hooks.afterAllResolved + ? clientPnpmfile.hooks.afterAllResolved(lockfile, context) + : lockfile; + }, + + // Set the preferred versions in the package, then call the original pnpmfile (if it exists) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + readPackage: (pkg: IPackageJson, context: any) => { + setPreferredVersions(pkg.dependencies); + setPreferredVersions(pkg.devDependencies); + setPreferredVersions(pkg.optionalDependencies); + return clientPnpmfile && clientPnpmfile.hooks && clientPnpmfile.hooks.readPackage + ? clientPnpmfile.hooks.readPackage(pkg, context) + : pkg; + } + } +}; + +export = pnpmfileShim; From 58eb27379404a0e7d4aab1a538b8e2cb75227567 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Thu, 2 Jul 2020 21:30:09 -0700 Subject: [PATCH 27/33] Remove 'generated' comment from checked in file --- .../src/logic/installManager/WorkspaceInstallManager.ts | 6 +++++- apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts index aa60511c5ce..1d317af052c 100644 --- a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -456,7 +456,11 @@ export class WorkspaceInstallManager extends BaseInstallManager { ); // Save the shim pnpmfile to the original path - await FileSystem.writeFileAsync(filename, pnpmfileContent, { ensureFolderExists: true }); + await FileSystem.writeFileAsync( + filename, + `// THIS FILE IS GENERATED BY RUSH. ANY MODIFICATIONS WILL BE OVERWRITTEN.\n${pnpmfileContent}`, + { ensureFolderExists: true } + ); } /** diff --git a/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts b/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts index f8648c12e51..1c6b9301b38 100644 --- a/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts +++ b/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts @@ -1,4 +1,6 @@ -// THIS FILE IS PROVIDED BY RUSH. ANY MODIFICATIONS WILL BE OVERWRITTEN. +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + import { existsSync } from 'fs'; interface ILockfile {} From c225f185db5e9449201554a180bd903dc41532ed Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Thu, 2 Jul 2020 21:48:01 -0700 Subject: [PATCH 28/33] Bump semver --- apps/api-extractor/package.json | 4 +-- common/config/rush/pnpm-lock.yaml | 57 ++++++++++++++++--------------- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/apps/api-extractor/package.json b/apps/api-extractor/package.json index 331c9e5ffe7..79bca873ec3 100644 --- a/apps/api-extractor/package.json +++ b/apps/api-extractor/package.json @@ -39,7 +39,7 @@ "colors": "~1.2.1", "lodash": "~4.17.15", "resolve": "~1.17.0", - "semver": "~5.3.0", + "semver": "~7.3.0", "source-map": "~0.6.1", "typescript": "~3.9.5" }, @@ -49,7 +49,7 @@ "@rushstack/eslint-config": "1.0.2", "@types/jest": "25.2.1", "@types/lodash": "4.14.116", - "@types/semver": "5.3.33", + "@types/semver": "~7.2.0", "@types/node": "10.17.13", "@types/resolve": "1.17.1", "gulp": "~4.0.2" diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index d4f06fd32af..f696b838647 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -14212,11 +14212,11 @@ packages: '@types/jest': 25.2.1 '@types/node': 10.17.13 fs-extra: 7.0.1 - typescript: 3.7.5 + typescript: 3.9.5 dev: false name: '@rush-temp/api-documenter-test' resolution: - integrity: sha512-oSQHe/WAGn2pGDzHNxy/ebbHwgV5EkUiaHoDC5mFveZi/YbZt8DfhcFzCAIzP/7M19h4bhhD9dkmDencC/4Q/A== + integrity: sha512-Qk1biNNk3nWYenDTiIqYW70vLuReSnw31Rc2Fd85le2izmqMzpVYoisw+KF8ja6Xt9ypQd1h0eUvDy31hTEyDQ== tarball: 'file:projects/api-documenter-test.tgz' version: 0.0.0 'file:projects/api-documenter.tgz': @@ -14253,11 +14253,11 @@ packages: '@types/jest': 25.2.1 '@types/node': 10.17.13 fs-extra: 7.0.1 - typescript: 3.7.5 + typescript: 3.9.5 dev: false name: '@rush-temp/api-extractor-lib2-test' resolution: - integrity: sha512-d/guVZZpVbV7X0N8WYQfltz0frTUO/Al4vq73fb9AF22TcWTmA+lFxlc7bMuXi/UZNtmpkH/kJ27YCSbeCuMkg== + integrity: sha512-0u0G7fscl+qgsZ7GNjTcRgAKGFVUvrk8UhgIe0bHUQhwruHEjrTvpjdM0HbsdOhfVt63fn+AkP4q0JCK15ZxKQ== tarball: 'file:projects/api-extractor-lib2-test.tgz' version: 0.0.0 'file:projects/api-extractor-lib3-test.tgz': @@ -14265,11 +14265,11 @@ packages: '@types/jest': 25.2.1 '@types/node': 10.17.13 fs-extra: 7.0.1 - typescript: 3.7.5 + typescript: 3.9.5 dev: false name: '@rush-temp/api-extractor-lib3-test' resolution: - integrity: sha512-B3J22QVJJC5kWnBLgDh6XjcwyEwwFRKvdA43oi1wPCvlqLW6RTrH8YA2SJVAMNf3rVSYWJHnFpwekfeGuqJ0Kg== + integrity: sha512-W+ZrYIx1rYjFin/GB0CmDltXHLL3OsJ9xxoPcH5wuZQWODiP6bBD6rpeREeoZ3webIwF7yz5RWKZ27PDgUCJDg== tarball: 'file:projects/api-extractor-lib3-test.tgz' version: 0.0.0 'file:projects/api-extractor-model.tgz': @@ -14293,11 +14293,11 @@ packages: '@types/node': 10.17.13 colors: 1.2.5 fs-extra: 7.0.1 - typescript: 3.7.5 + typescript: 3.9.5 dev: false name: '@rush-temp/api-extractor-scenarios' resolution: - integrity: sha512-dioxOVTQZgT+tuCvtcottdkiVTOvej/eLPIiz+W+vp71jbjzComxaKwxXokzw3XmvqIiW/HJajG55q+B0O+WDw== + integrity: sha512-eUE0t2GtLcGwT3WjFlgrRtxwNKaizkYauWQew1fRglDIMQp+KBwslGEVkqq60fy9vUQF5ccnP+Vp9l42kxrXAw== tarball: 'file:projects/api-extractor-scenarios.tgz' version: 0.0.0 'file:projects/api-extractor-test-01.tgz': @@ -14307,11 +14307,11 @@ packages: '@types/node': 10.17.13 fs-extra: 7.0.1 long: 4.0.0 - typescript: 3.7.5 + typescript: 3.9.5 dev: false name: '@rush-temp/api-extractor-test-01' resolution: - integrity: sha512-gRBxDF1RjKcabsNcInRgWQ0cll2J0+XInXCpvuemXNl/oIRBPDbB6R8Hhfm5q7mw5mVOympHX9fRSnTeIw9fJg== + integrity: sha512-gtQg1x+6BbSPaQJzE2lXPhYuASORkogG94ctPkiyst6rEYlHifzW0rPB8TyEo+SjzcsVNil6Q8UygxxtBkR/dg== tarball: 'file:projects/api-extractor-test-01.tgz' version: 0.0.0 'file:projects/api-extractor-test-02.tgz': @@ -14320,11 +14320,11 @@ packages: '@types/semver': 7.2.0 fs-extra: 7.0.1 semver: 7.3.2 - typescript: 3.7.5 + typescript: 3.9.5 dev: false name: '@rush-temp/api-extractor-test-02' resolution: - integrity: sha512-0APEr7rC+gvyoY3jlfwSCSeIDAAQ5KQ3sq1xZR1/7+hs1ikzbjAVN+kebcnlCkANm28rXePFOKceUPQ51tFW2Q== + integrity: sha512-h9Vb7Rts0J3jH380YqWmoi7+58++gY9gKFyLCLDViod83x02U89jK5eKViOSYG9+JDiphLtdXJ8JN4aiVMqPtg== tarball: 'file:projects/api-extractor-test-02.tgz' version: 0.0.0 'file:projects/api-extractor-test-03.tgz': @@ -14332,21 +14332,21 @@ packages: '@types/jest': 25.2.1 '@types/node': 10.17.13 fs-extra: 7.0.1 - typescript: 3.7.5 + typescript: 3.9.5 dev: false name: '@rush-temp/api-extractor-test-03' resolution: - integrity: sha512-ZvlDjrJG25V7ogORzsOPh4nVRVeG/nrL76fjzlBBgloKTx8/IDbpesiwir9eFgL6mZKjW7Tsl69ueatf2x5NQQ== + integrity: sha512-18X0hgAkdqA62AK05QDSJhrdxEa29yRZ+lZ98jFzISa4ae0oovpvHfdkELnZCpzaSpDrsGO/iC8D2SRlPhWQ1w== tarball: 'file:projects/api-extractor-test-03.tgz' version: 0.0.0 'file:projects/api-extractor-test-04.tgz': dependencies: fs-extra: 7.0.1 - typescript: 3.7.5 + typescript: 3.9.5 dev: false name: '@rush-temp/api-extractor-test-04' resolution: - integrity: sha512-JwMGU3lYK4vjLm/0SnnM632y3lJNxBALjTcjnNQGVaT1DbLUS7wNWit9PM+cG7Wf4RUxxsRnLYLgEYVv12/SnQ== + integrity: sha512-kuJ7xZ9rFAB1Xha/iTothhJRqXIUF2s3t+c6hj6Ls8jufjpo+jwnk2ho4TrjzCI7hzGP7ydLnXywFKZhZ0GuIQ== tarball: 'file:projects/api-extractor-test-04.tgz' version: 0.0.0 'file:projects/api-extractor.tgz': @@ -14358,16 +14358,18 @@ packages: '@types/lodash': 4.14.116 '@types/node': 10.17.13 '@types/resolve': 1.17.1 + '@types/semver': 7.2.0 colors: 1.2.5 gulp: 4.0.2 lodash: 4.17.15 resolve: 1.17.0 + semver: 7.3.2 source-map: 0.6.1 - typescript: 3.7.5 + typescript: 3.9.5 dev: false name: '@rush-temp/api-extractor' resolution: - integrity: sha512-0Hc/hnyjcrx2L8a6Ff0ovcb+MogtCyyzeE4q8LgN6hjzAP1Yn3DKh9k3LVSJNOuHNR5j8Ru9OSnFgR+lI8FITg== + integrity: sha512-4kEzephkXZuLulJrW+CAIU1ieoPrHjHlSJXpYqIoVvAqd2okqrysnBx4LBZd51Qmo6OkLslC25wOmgZDwsJXJw== tarball: 'file:projects/api-extractor.tgz' version: 0.0.0 'file:projects/debug-certificate-manager.tgz': @@ -14623,10 +14625,11 @@ packages: glob-escape: 0.0.2 resolve: 1.17.0 tapable: 1.1.3 + true-case-path: 2.2.1 dev: false name: '@rush-temp/heft' resolution: - integrity: sha512-oqxC8xYIHFYvP9Z4oGlnsIgaQYrG+0s3Vr/B4wP/pj7GJtl6h8+lhh2PwI0OzcpsOr3IebO5P1TMnXsM1iqZaA== + integrity: sha512-of6kz/4U9YQ+9xvHtrXWg1hQYlCEyrHJdUIptbeBpwJgBxS7DLn2ffzvWHm4Rts2Vs2NLiXm3OZS96tAoG5qSQ== tarball: 'file:projects/heft.tgz' version: 0.0.0 'file:projects/load-themed-styles.tgz': @@ -14824,7 +14827,7 @@ packages: dev: false name: '@rush-temp/repo-toolbox' resolution: - integrity: sha512-F7usln44ENLWV3PAM/qS8efUFWy1nvu2TiU/S3SvEiptO4xG1cobMQ0jXCc4SrFRVBdRVPjzC3HmtCsZIzQKWw== + integrity: sha512-YQulqxSmK0+VHyzZO8qHNVmkapqqZ7m2znjnH0pWmc75loYrUHMUFjxUPOIA6ZL5TK43/MtX/EHfOaxGVUqpXw== tarball: 'file:projects/repo-toolbox.tgz' version: 0.0.0 'file:projects/rush-buildxl.tgz': @@ -14835,7 +14838,7 @@ packages: dev: false name: '@rush-temp/rush-buildxl' resolution: - integrity: sha512-VpkPux6A6n/Gzljtfsrd9Z7YGvUVTYiBkRvC6a7SKcLkiggLNFOX6R+6OSI7jhCHmLKi+I0+4jJNQ+uxuL0Ckg== + integrity: sha512-5z4k+kvvd7xBlG51bsnNCMBJTbCgoHzv8zzH5l8qNQoeS9MZ1K24xYvl4dfsq4OvGiOHwCEoX/zAzZH1LQTxbw== tarball: 'file:projects/rush-buildxl.tgz' version: 0.0.0 'file:projects/rush-lib.tgz': @@ -15291,7 +15294,7 @@ packages: dev: false name: '@rush-temp/rush' resolution: - integrity: sha512-U9KhjMT8Yool5GBDtLaBLBQVwVn4UK90Jh9rqhQsBvMQ7XIBjnrvVJjghDt9GY6fzyxb2nGh6Z8MAaPsrjOrNQ== + integrity: sha512-G21na3eJjXCIrQyAq4aEt1hZxlHn+Fe0PNYJk8AVA4UaG/0jJAqThLdBMaVtZGjyBLjbi3IpMuvRjU+fObR8vQ== tarball: 'file:projects/rush.tgz' version: 0.0.0 'file:projects/rushell.tgz': @@ -15347,11 +15350,11 @@ packages: dependencies: '@types/node': 10.17.13 fs-extra: 7.0.1 - typescript: 3.7.5 + typescript: 3.9.5 dev: false name: '@rush-temp/ts-command-line-test' resolution: - integrity: sha512-BXoCr1E3CZHjcqlnDYLLP1F18ExjaJ8/m2qUTxBHEnayfy0Xmt9L3ZmslWzt6hFWSkuUEt5NlxkdGBXlFFNZfQ== + integrity: sha512-AQxi+9T6peEEsJWdyCZVEzd6r4jQaQ5EVbQEoWAZ9NOIIVEpjUZLaiEO/d93ggEGQqKvHB479OgtbgJbUyXhFg== tarball: 'file:projects/ts-command-line-test.tgz' version: 0.0.0 'file:projects/ts-command-line.tgz': @@ -15392,7 +15395,7 @@ packages: dev: false name: '@rush-temp/web-library-build-test' resolution: - integrity: sha512-zK8JowWRhZ4Lbwzec4wvWmLqSWg4xY0xalIitKd1WHz3VoxW50BY/kJM/iWtcvjKtxCoYIdNbGNuDkOKkgzEIw== + integrity: sha512-je59bh3sOKxZhpn5mFV8FTFi7HPqkmP9B847THbPQKYd5Hs6xjiVGIRHDxqAtffCt1ZloNn8ffwFeRQualPUeg== tarball: 'file:projects/web-library-build-test.tgz' version: 0.0.0 'file:projects/web-library-build.tgz': @@ -15404,7 +15407,7 @@ packages: dev: false name: '@rush-temp/web-library-build' resolution: - integrity: sha512-2I0Hk+AmU4AtPc0R1PUNdsIewWhTvMuK0XDQBLYIg9XMWm5W41ValoiQV6mhxmPKNsg4MJvfhsktN6VltyUJgA== + integrity: sha512-AtGayKEU+vyg+dSs9x/lz/S6YcJHKk4ZA19sdyO8McgEMMpwn/aHOzrSKPRrdm8t7x3scUZgpIsVwYcEvZI/1g== tarball: 'file:projects/web-library-build.tgz' version: 0.0.0 registry: '' @@ -15641,4 +15644,4 @@ specifiers: xmldoc: ~1.1.2 yargs: ~4.6.0 z-schema: ~3.18.3 -# shrinkwrap hash: 7fd4f219613327fb0c3b58cc18af77a4183033bf +# shrinkwrap hash: f035df37bd55f6d14b9e0b7de37069024f5b4b23 From e6da401362fe40dfc9d02bf223ebc5f064397579 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Thu, 2 Jul 2020 21:54:19 -0700 Subject: [PATCH 29/33] rush change --- .../supportWorkspaces2_2020-07-03-04-54.json | 11 +++++++++++ .../supportWorkspaces2_2020-07-03-04-54.json | 11 +++++++++++ 2 files changed, 22 insertions(+) create mode 100644 common/changes/@microsoft/api-extractor/supportWorkspaces2_2020-07-03-04-54.json create mode 100644 common/changes/@microsoft/gulp-core-build-sass/supportWorkspaces2_2020-07-03-04-54.json diff --git a/common/changes/@microsoft/api-extractor/supportWorkspaces2_2020-07-03-04-54.json b/common/changes/@microsoft/api-extractor/supportWorkspaces2_2020-07-03-04-54.json new file mode 100644 index 00000000000..f55c74c0ad2 --- /dev/null +++ b/common/changes/@microsoft/api-extractor/supportWorkspaces2_2020-07-03-04-54.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@microsoft/api-extractor", + "comment": "", + "type": "none" + } + ], + "packageName": "@microsoft/api-extractor", + "email": "3473356+D4N14L@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@microsoft/gulp-core-build-sass/supportWorkspaces2_2020-07-03-04-54.json b/common/changes/@microsoft/gulp-core-build-sass/supportWorkspaces2_2020-07-03-04-54.json new file mode 100644 index 00000000000..b962decb437 --- /dev/null +++ b/common/changes/@microsoft/gulp-core-build-sass/supportWorkspaces2_2020-07-03-04-54.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@microsoft/gulp-core-build-sass", + "comment": "", + "type": "none" + } + ], + "packageName": "@microsoft/gulp-core-build-sass", + "email": "3473356+D4N14L@users.noreply.github.com" +} \ No newline at end of file From 2aaf287143f5ba56ced8cf738c9dd32fed5cc4b5 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Fri, 3 Jul 2020 00:34:15 -0700 Subject: [PATCH 30/33] PR feedback --- .../rush-lib/src/logic/DependencySpecifier.ts | 58 +++++++++---------- apps/rush-lib/src/logic/PublishUtilities.ts | 10 ++-- .../src/logic/base/BaseShrinkwrapFile.ts | 10 ++-- .../installManager/RushInstallManager.ts | 4 +- .../installManager/WorkspaceInstallManager.ts | 24 +++++--- .../src/logic/pnpm/PnpmLinkManager.ts | 10 +++- apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts | 10 ++-- 7 files changed, 65 insertions(+), 61 deletions(-) diff --git a/apps/rush-lib/src/logic/DependencySpecifier.ts b/apps/rush-lib/src/logic/DependencySpecifier.ts index d503f296058..bdcf3d8a31f 100644 --- a/apps/rush-lib/src/logic/DependencySpecifier.ts +++ b/apps/rush-lib/src/logic/DependencySpecifier.ts @@ -7,7 +7,7 @@ import { InternalError } from '@rushstack/node-core-library'; /** * The parsed format of a provided version specifier. */ -export const enum SpecifierType { +export enum DependencySpecifierType { /** * A git repository */ @@ -74,7 +74,7 @@ export class DependencySpecifier { /** * The type of the `versionSpecifier`. */ - public readonly specifierType: SpecifierType; + public readonly specifierType: DependencySpecifierType; /** * If `specifierType` is `alias`, then this is the parsed target dependency. @@ -90,50 +90,46 @@ export class DependencySpecifier { // Workspace ranges are a feature from PNPM and Yarn. Set the version specifier // to the trimmed version range. if (versionSpecifier.startsWith('workspace:')) { - this.specifierType = SpecifierType.Workspace; + this.specifierType = DependencySpecifierType.Workspace; this.versionSpecifier = versionSpecifier.slice(this.specifierType.length + 1).trim(); this.aliasTarget = undefined; return; } const result: npmPackageArg.Result = npmPackageArg.resolve(packageName, versionSpecifier); - switch (result.type) { + this.specifierType = DependencySpecifier.getDependencySpecifierType(result.type); + + if (this.specifierType === DependencySpecifierType.Alias) { + const aliasResult: npmPackageArg.AliasResult = result as npmPackageArg.AliasResult; + if (!aliasResult.subSpec || !aliasResult.subSpec.name) { + throw new InternalError('Unexpected result from npm-package-arg'); + } + this.aliasTarget = new DependencySpecifier(aliasResult.subSpec.name, aliasResult.subSpec.rawSpec); + } else { + this.aliasTarget = undefined; + } + } + + public static getDependencySpecifierType(specifierType: string): DependencySpecifierType { + switch (specifierType) { case 'git': - this.specifierType = SpecifierType.Git; - break; + return DependencySpecifierType.Git; case 'tag': - this.specifierType = SpecifierType.Tag; - break; + return DependencySpecifierType.Tag; case 'version': - this.specifierType = SpecifierType.Version; - break; + return DependencySpecifierType.Version; case 'range': - this.specifierType = SpecifierType.Range; - break; + return DependencySpecifierType.Range; case 'file': - this.specifierType = SpecifierType.File; - break; + return DependencySpecifierType.File; case 'directory': - this.specifierType = SpecifierType.Directory; - break; + return DependencySpecifierType.Directory; case 'remote': - this.specifierType = SpecifierType.Remote; - break; + return DependencySpecifierType.Remote; case 'alias': - this.specifierType = SpecifierType.Alias; - break; + return DependencySpecifierType.Alias; default: - throw new InternalError(`Unexpected npm-package-arg result type "${result.type}"`); - } - - if (this.specifierType === SpecifierType.Alias) { - const aliasResult: npmPackageArg.AliasResult = result as npmPackageArg.AliasResult; - if (!aliasResult.subSpec || !aliasResult.subSpec.name) { - throw new InternalError('Unexpected result from npm-package-arg'); - } - this.aliasTarget = new DependencySpecifier(aliasResult.subSpec.name, aliasResult.subSpec.rawSpec); - } else { - this.aliasTarget = undefined; + throw new InternalError(`Unexpected npm-package-arg result type "${specifierType}"`); } } } diff --git a/apps/rush-lib/src/logic/PublishUtilities.ts b/apps/rush-lib/src/logic/PublishUtilities.ts index 72e56c1d324..829a9c451f9 100644 --- a/apps/rush-lib/src/logic/PublishUtilities.ts +++ b/apps/rush-lib/src/logic/PublishUtilities.ts @@ -19,7 +19,7 @@ import { execSync } from 'child_process'; import { PrereleaseToken } from './PrereleaseToken'; import { ChangeFiles } from './ChangeFiles'; import { RushConfiguration } from '../api/RushConfiguration'; -import { DependencySpecifier, SpecifierType } from './DependencySpecifier'; +import { DependencySpecifier, DependencySpecifierType } from './DependencySpecifier'; export interface IChangeInfoHash { [key: string]: IChangeInfo; @@ -246,7 +246,7 @@ export class PublishUtilities { } else { newDependencyVersion = newProjectVersion; } - return currentDependencySpecifier.specifierType === SpecifierType.Workspace + return currentDependencySpecifier.specifierType === DependencySpecifierType.Workspace ? `workspace:${newDependencyVersion}` : newDependencyVersion; } @@ -434,7 +434,7 @@ export class PublishUtilities { ); const newVersion: string = PublishUtilities._getChangeInfoNewVersion(depChange, prereleaseToken); dependencies[depName] = - currentSpecifier.specifierType === SpecifierType.Workspace + currentSpecifier.specifierType === DependencySpecifierType.Workspace ? `workspace:${newVersion}` : newVersion; } else if (depChange && depChange.changeType! >= ChangeType.hotfix) { @@ -714,7 +714,7 @@ export class PublishUtilities { currentDependencyVersion ); currentDependencyVersion = - currentDependencySpecifier.specifierType === SpecifierType.Workspace && + currentDependencySpecifier.specifierType === DependencySpecifierType.Workspace && currentDependencySpecifier.versionSpecifier === '*' ? undefined : currentDependencySpecifier.versionSpecifier; @@ -724,7 +724,7 @@ export class PublishUtilities { newDependencyVersion ); newDependencyVersion = - newDependencySpecifier.specifierType === SpecifierType.Workspace && + newDependencySpecifier.specifierType === DependencySpecifierType.Workspace && newDependencySpecifier.versionSpecifier === '*' ? dependencyChange.newVersion! : newDependencySpecifier.versionSpecifier; diff --git a/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts b/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts index 8235c1f0f92..eb46a829821 100644 --- a/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts +++ b/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts @@ -6,7 +6,7 @@ import * as semver from 'semver'; import { FileSystem } from '@rushstack/node-core-library'; import { RushConstants } from '../../logic/RushConstants'; -import { DependencySpecifier, SpecifierType } from '../DependencySpecifier'; +import { DependencySpecifier, DependencySpecifierType } from '../DependencySpecifier'; import { IShrinkwrapFilePolicyValidatorOptions } from '../policy/ShrinkwrapFilePolicy'; import { PackageManagerOptionsConfigurationBase } from '../../api/RushConfiguration'; import { PackageNameParsers } from '../../api/PackageNameParsers'; @@ -193,9 +193,9 @@ export abstract class BaseShrinkwrapFile { // // In this case, the shrinkwrap file will have a key equivalent to "npm:target-name@1.2.5", // and so we need to unwrap the target and compare "1.2.5" with "^1.2.3". - if (projectDependency.specifierType === SpecifierType.Alias) { + if (projectDependency.specifierType === DependencySpecifierType.Alias) { // Does the shrinkwrap install it as an alias? - if (shrinkwrapDependency.specifierType === SpecifierType.Alias) { + if (shrinkwrapDependency.specifierType === DependencySpecifierType.Alias) { // Does the shrinkwrap have the right package name? if (projectDependency.packageName === shrinkwrapDependency.packageName) { // Yes, the aliases match, so let's compare their targets in the logic below @@ -212,8 +212,8 @@ export abstract class BaseShrinkwrapFile { } switch (normalizedProjectDependency.specifierType) { - case SpecifierType.Version: - case SpecifierType.Range: + case DependencySpecifierType.Version: + case DependencySpecifierType.Range: return semver.satisfies( normalizedShrinkwrapDependency.versionSpecifier, normalizedProjectDependency.versionSpecifier diff --git a/apps/rush-lib/src/logic/installManager/RushInstallManager.ts b/apps/rush-lib/src/logic/installManager/RushInstallManager.ts index 004cf355e83..731946d9e6b 100644 --- a/apps/rush-lib/src/logic/installManager/RushInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/RushInstallManager.ts @@ -26,7 +26,7 @@ import { RushConstants } from '../../logic/RushConstants'; import { Stopwatch } from '../../utilities/Stopwatch'; import { Utilities } from '../../utilities/Utilities'; import { PackageJsonEditor, DependencyType, PackageJsonDependency } from '../../api/PackageJsonEditor'; -import { DependencySpecifier, SpecifierType } from '../DependencySpecifier'; +import { DependencySpecifier, DependencySpecifierType } from '../DependencySpecifier'; import { InstallHelpers } from './InstallHelpers'; import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; @@ -374,7 +374,7 @@ export class RushInstallManager extends BaseInstallManager { private _revertWorkspaceNotation(dependency: PackageJsonDependency): boolean { const specifier: DependencySpecifier = new DependencySpecifier(dependency.name, dependency.version); - if (specifier.specifierType !== SpecifierType.Workspace) { + if (specifier.specifierType !== DependencySpecifierType.Workspace) { return false; } // Replace workspace notation with the supplied version range diff --git a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts index 1d317af052c..24bf3b0edda 100644 --- a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -10,7 +10,7 @@ import { FileSystem, InternalError, MapExtensions } from '@rushstack/node-core-l import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; import { BaseInstallManager, IInstallManagerOptions } from '../base/BaseInstallManager'; import { BaseShrinkwrapFile } from '../../logic/base/BaseShrinkwrapFile'; -import { DependencySpecifier, SpecifierType } from '../DependencySpecifier'; +import { DependencySpecifier, DependencySpecifierType } from '../DependencySpecifier'; import { PackageJsonEditor, DependencyType } from '../../api/PackageJsonEditor'; import { PnpmWorkspaceFile } from '../pnpm/PnpmWorkspaceFile'; import { RushConfigurationProject } from '../../api/RushConfigurationProject'; @@ -69,7 +69,7 @@ export class WorkspaceInstallManager extends BaseInstallManager { this.rushConfiguration.commonTempFolder, RushConstants.pnpmfileFilename ); - await this.createShimPnpmfile(tempPnpmFilePath); + await this.createShimPnpmfileAsync(tempPnpmFilePath); } const shrinkwrapWarnings: string[] = []; @@ -143,8 +143,8 @@ export class WorkspaceInstallManager extends BaseInstallManager { // cyclic dependency, then it needs to be updated to specify `workspace:*` explicitly. Currently only // supporting versions and version ranges for specifying a local project. if ( - (dependencySpecifier.specifierType === SpecifierType.Version || - dependencySpecifier.specifierType === SpecifierType.Range) && + (dependencySpecifier.specifierType === DependencySpecifierType.Version || + dependencySpecifier.specifierType === DependencySpecifierType.Range) && referencedLocalProject && !rushProject.cyclicDependencyProjects.has(name) ) { @@ -190,7 +190,7 @@ export class WorkspaceInstallManager extends BaseInstallManager { shrinkwrapIsUpToDate = false; continue; } - } else if (dependencySpecifier.specifierType === SpecifierType.Workspace) { + } else if (dependencySpecifier.specifierType === DependencySpecifierType.Workspace) { // Already specified as a local project. Allow the package manager to validate this continue; } @@ -418,14 +418,16 @@ export class WorkspaceInstallManager extends BaseInstallManager { * is a subset of the dependency version range. Allowed alternate versions are not modified. The pnpmfile * shim will subsequently call into the provided pnpmfile, if one exists. */ - protected async createShimPnpmfile(filename: string): Promise { + protected async createShimPnpmfileAsync(filename: string): Promise { // Attempt to move the existing pnpmfile if there is one + let pnpmfileExists: boolean = false; try { const pnpmfileDir: string = path.dirname(filename); await FileSystem.moveAsync({ sourcePath: filename, destinationPath: path.join(pnpmfileDir, 'clientPnpmfile.js') }); + pnpmfileExists = true; } catch (error) { if (!FileSystem.isNotExistError(error)) { throw error; @@ -437,11 +439,15 @@ export class WorkspaceInstallManager extends BaseInstallManager { path.resolve(__dirname, '..', 'pnpm', 'PnpmfileShim.js') ); pnpmfileContent = pnpmfileContent.replace( - /__semverPath/, + /__pnpmfileExists/g, + JSON.stringify(pnpmfileExists).replace(/^'|'$/g, '') + ); + pnpmfileContent = pnpmfileContent.replace( + /__semverPath/g, JSON.stringify(require.resolve('semver')).replace(/^"|"$/g, '') ); pnpmfileContent = pnpmfileContent.replace( - /__allowedAlternativeVersions/, + /__allowedAlternativeVersions/g, JSON.stringify( MapExtensions.toObject( this.rushConfiguration.getCommonVersions(this.options.variant).allowedAlternativeVersions @@ -449,7 +455,7 @@ export class WorkspaceInstallManager extends BaseInstallManager { ) ); pnpmfileContent = pnpmfileContent.replace( - /__allPreferredVersions/, + /__allPreferredVersions/g, JSON.stringify( MapExtensions.toObject(InstallHelpers.collectPreferredVersions(this.rushConfiguration, this.options)) ) diff --git a/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts b/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts index 4c1988cf3f5..4e3471ccd29 100644 --- a/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts +++ b/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts @@ -22,7 +22,7 @@ import { } from './PnpmShrinkwrapFile'; import { PnpmProjectDependencyManifest } from './PnpmProjectDependencyManifest'; import { PackageJsonDependency, DependencyType } from '../../api/PackageJsonEditor'; -import { DependencySpecifier, SpecifierType } from '../DependencySpecifier'; +import { DependencySpecifier, DependencySpecifierType } from '../DependencySpecifier'; // special flag for debugging, will print extra diagnostic information, // but comes with performance cost @@ -324,7 +324,9 @@ export class PnpmLinkManager extends BaseLinkManager { const localDependencies: PackageJsonDependency[] = [ ...project.packageJsonEditor.dependencyList, ...project.packageJsonEditor.devDependencyList - ].filter((x) => new DependencySpecifier(x.name, x.version).specifierType === SpecifierType.Workspace); + ].filter( + (x) => new DependencySpecifier(x.name, x.version).specifierType === DependencySpecifierType.Workspace + ); for (const { name } of localDependencies) { const matchedRushPackage: @@ -369,7 +371,9 @@ export class PnpmLinkManager extends BaseLinkManager { const dependencies: PackageJsonDependency[] = [ ...project.packageJsonEditor.dependencyList, ...project.packageJsonEditor.devDependencyList - ].filter((x) => new DependencySpecifier(x.name, x.version).specifierType !== SpecifierType.Workspace); + ].filter( + (x) => new DependencySpecifier(x.name, x.version).specifierType !== DependencySpecifierType.Workspace + ); for (const { name, dependencyType } of dependencies) { // read the version number from the shrinkwrap entry diff --git a/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts b/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts index 1c6b9301b38..710057ce4ff 100644 --- a/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts +++ b/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { existsSync } from 'fs'; - interface ILockfile {} interface IPackageJson { @@ -20,13 +18,13 @@ interface IPnpmfile { }; } -// We will require semver from this path on disk, since this is the version of semver shipping with Rush -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const semver: any = require('__semverPath'); // Only require the client pnpmfile if it exists -const clientPnpmfile: IPnpmfile | undefined = existsSync('clientPnpmfile.js') +const clientPnpmfile: IPnpmfile | undefined = JSON.parse('__pnpmfileExists') ? require('./clientPnpmfile') : undefined; +// We will require semver from this path on disk, since this is the version of semver shipping with Rush +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const semver: any = require('__semverPath'); const allPreferredVersions: { [dependencyName: string]: string } = JSON.parse('__allPreferredVersions'); const allowedAlternativeVersions: { [dependencyName: string]: string[] } = JSON.parse( '__allowedAlternativeVersions' From 5e3c3ea32dfe48f5fa881a2fa6504e44348ed3a8 Mon Sep 17 00:00:00 2001 From: Daniel Nadeau <3473356+D4N14L@users.noreply.github.com> Date: Fri, 3 Jul 2020 01:00:32 -0700 Subject: [PATCH 31/33] Move dynamic data to pnpmfileSettings.json --- .../installManager/WorkspaceInstallManager.ts | 54 ++++++++----------- apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts | 31 ++++++----- 2 files changed, 39 insertions(+), 46 deletions(-) diff --git a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts index 24bf3b0edda..f7d01c441ef 100644 --- a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -5,7 +5,7 @@ import * as colors from 'colors'; import * as os from 'os'; import * as path from 'path'; import * as semver from 'semver'; -import { FileSystem, InternalError, MapExtensions } from '@rushstack/node-core-library'; +import { FileSystem, InternalError, MapExtensions, JsonFile } from '@rushstack/node-core-library'; import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; import { BaseInstallManager, IInstallManagerOptions } from '../base/BaseInstallManager'; @@ -419,10 +419,10 @@ export class WorkspaceInstallManager extends BaseInstallManager { * shim will subsequently call into the provided pnpmfile, if one exists. */ protected async createShimPnpmfileAsync(filename: string): Promise { - // Attempt to move the existing pnpmfile if there is one + const pnpmfileDir: string = path.dirname(filename); let pnpmfileExists: boolean = false; try { - const pnpmfileDir: string = path.dirname(filename); + // Attempt to move the existing pnpmfile if there is one await FileSystem.moveAsync({ sourcePath: filename, destinationPath: path.join(pnpmfileDir, 'clientPnpmfile.js') @@ -434,39 +434,27 @@ export class WorkspaceInstallManager extends BaseInstallManager { } } - // Read the shim pnpmfile and replace the placeholders - let pnpmfileContent: string = await FileSystem.readFileAsync( - path.resolve(__dirname, '..', 'pnpm', 'PnpmfileShim.js') - ); - pnpmfileContent = pnpmfileContent.replace( - /__pnpmfileExists/g, - JSON.stringify(pnpmfileExists).replace(/^'|'$/g, '') - ); - pnpmfileContent = pnpmfileContent.replace( - /__semverPath/g, - JSON.stringify(require.resolve('semver')).replace(/^"|"$/g, '') - ); - pnpmfileContent = pnpmfileContent.replace( - /__allowedAlternativeVersions/g, - JSON.stringify( - MapExtensions.toObject( + // Write the settings to be consumed by the pnpmfile + await JsonFile.saveAsync( + { + allPreferredVersions: MapExtensions.toObject( + InstallHelpers.collectPreferredVersions(this.rushConfiguration, this.options) + ), + allowedAlternativeVersions: MapExtensions.toObject( this.rushConfiguration.getCommonVersions(this.options.variant).allowedAlternativeVersions - ) - ) - ); - pnpmfileContent = pnpmfileContent.replace( - /__allPreferredVersions/g, - JSON.stringify( - MapExtensions.toObject(InstallHelpers.collectPreferredVersions(this.rushConfiguration, this.options)) - ) - ); - - // Save the shim pnpmfile to the original path - await FileSystem.writeFileAsync( - filename, - `// THIS FILE IS GENERATED BY RUSH. ANY MODIFICATIONS WILL BE OVERWRITTEN.\n${pnpmfileContent}`, + ), + semverPath: require.resolve('semver'), + useClientPnpmfile: pnpmfileExists + }, + path.resolve(pnpmfileDir, 'pnpmfileSettings.json'), { ensureFolderExists: true } ); + + // Copy the shim pnpmfile to the original path + await FileSystem.copyFileAsync({ + sourcePath: path.resolve(__dirname, '..', 'pnpm', 'PnpmfileShim.js'), + destinationPath: filename + }); } /** diff --git a/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts b/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts index 710057ce4ff..acf37d782b6 100644 --- a/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts +++ b/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts @@ -18,28 +18,33 @@ interface IPnpmfile { }; } -// Only require the client pnpmfile if it exists -const clientPnpmfile: IPnpmfile | undefined = JSON.parse('__pnpmfileExists') - ? require('./clientPnpmfile') - : undefined; +interface IPnpmfileSettings { + allPreferredVersions: { [dependencyName: string]: string }; + allowedAlternativeVersions: { [dependencyName: string]: string[] }; + semverPath: string; + useClientPnpmfile: boolean; +} + +// Load in the generated settings file +const pnpmfileSettings: IPnpmfileSettings = require('./pnpmfileSettings.json'); // We will require semver from this path on disk, since this is the version of semver shipping with Rush // eslint-disable-next-line @typescript-eslint/no-explicit-any -const semver: any = require('__semverPath'); -const allPreferredVersions: { [dependencyName: string]: string } = JSON.parse('__allPreferredVersions'); -const allowedAlternativeVersions: { [dependencyName: string]: string[] } = JSON.parse( - '__allowedAlternativeVersions' -); +const semver: any = require(pnpmfileSettings.semverPath); +// Only require the client pnpmfile if requested +const clientPnpmfile: IPnpmfile | undefined = pnpmfileSettings.useClientPnpmfile + ? require('./clientPnpmfile') + : undefined; // Set the preferred versions on the dependency map. If the version on the map is an allowedAlternativeVersion // then skip it. Otherwise, check to ensure that the common version is a subset of the specified version. If // it is, then replace the specified version with the preferredVersion function setPreferredVersions(dependencies?: { [dependencyName: string]: string }): void { for (const name of Object.keys(dependencies || {})) { - if (allPreferredVersions.hasOwnProperty(name)) { - const preferredVersion: string = allPreferredVersions[name]; + if (pnpmfileSettings.allPreferredVersions.hasOwnProperty(name)) { + const preferredVersion: string = pnpmfileSettings.allPreferredVersions[name]; const version: string = dependencies![name]; - if (allowedAlternativeVersions.hasOwnProperty(name)) { - const allowedAlternatives: string[] | undefined = allowedAlternativeVersions[name]; + if (pnpmfileSettings.allowedAlternativeVersions.hasOwnProperty(name)) { + const allowedAlternatives: string[] | undefined = pnpmfileSettings.allowedAlternativeVersions[name]; if (allowedAlternatives && allowedAlternatives.indexOf(version) > -1) { continue; } From 1771839131fca5d068f07a35bb5eb1b305e09c01 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Fri, 3 Jul 2020 02:05:40 -0700 Subject: [PATCH 32/33] Upgrade semver types to match package version. --- apps/api-extractor/package.json | 2 +- apps/rush-lib/package.json | 2 +- apps/rush/package.json | 2 +- .../api-extractor-test-02/package.json | 2 +- common/config/rush/pnpm-lock.yaml | 162 +++++++++--------- core-build/gulp-core-build/package.json | 2 +- libraries/node-core-library/package.json | 2 +- 7 files changed, 87 insertions(+), 87 deletions(-) diff --git a/apps/api-extractor/package.json b/apps/api-extractor/package.json index 620d359340c..94634e98886 100644 --- a/apps/api-extractor/package.json +++ b/apps/api-extractor/package.json @@ -49,7 +49,7 @@ "@rushstack/eslint-config": "1.0.2", "@types/jest": "25.2.1", "@types/lodash": "4.14.116", - "@types/semver": "~7.2.0", + "@types/semver": "~7.3.1", "@types/node": "10.17.13", "@types/resolve": "1.17.1", "gulp": "~4.0.2" diff --git a/apps/rush-lib/package.json b/apps/rush-lib/package.json index 7b73b68c36d..10d66f0e668 100644 --- a/apps/rush-lib/package.json +++ b/apps/rush-lib/package.json @@ -64,7 +64,7 @@ "@types/npm-packlist": "~1.1.1", "@types/read-package-tree": "5.1.0", "@types/resolve": "1.17.1", - "@types/semver": "~7.2.0", + "@types/semver": "~7.3.1", "@types/strict-uri-encode": "2.0.0", "@types/tar": "4.0.3", "@types/wordwrap": "1.0.0", diff --git a/apps/rush/package.json b/apps/rush/package.json index 83a04338301..fdf48bda16e 100644 --- a/apps/rush/package.json +++ b/apps/rush/package.json @@ -42,7 +42,7 @@ "@rushstack/eslint-config": "1.0.2", "@types/jest": "25.2.1", "@types/node": "10.17.13", - "@types/semver": "~7.2.0", + "@types/semver": "~7.3.1", "@types/sinon": "1.16.34", "chai": "~3.5.0", "gulp": "~4.0.2", diff --git a/build-tests/api-extractor-test-02/package.json b/build-tests/api-extractor-test-02/package.json index 129f7166369..4ce70aed023 100644 --- a/build-tests/api-extractor-test-02/package.json +++ b/build-tests/api-extractor-test-02/package.json @@ -9,7 +9,7 @@ "build": "node build.js" }, "dependencies": { - "@types/semver": "~7.2.0", + "@types/semver": "~7.3.1", "api-extractor-test-01": "1.0.0", "semver": "~7.3.0" }, diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index f696b838647..723f15e992d 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -118,7 +118,7 @@ dependencies: '@types/orchestrator': 0.0.30 '@types/read-package-tree': 5.1.0 '@types/resolve': 1.17.1 - '@types/semver': 7.2.0 + '@types/semver': 7.3.1 '@types/serve-static': 1.13.1 '@types/sinon': 1.16.34 '@types/source-map': 0.5.0 @@ -1385,12 +1385,12 @@ packages: dev: false resolution: integrity: sha512-UwrBgjsRS8BSsckIEdrAhIAmdh0MJidtKTvD3S6tpMq6qHLY3uGaNYcRDUjPxpF4hOAOEbMNSXhhfxmNHB1QNQ== - /@types/semver/7.2.0: + /@types/semver/7.3.1: dependencies: '@types/node': 10.17.13 dev: false resolution: - integrity: sha512-TbB0A8ACUWZt3Y6bQPstW9QNbhNeebdgLX4T/ZfkrswAfUzRiXrgd9seol+X379Wa589Pu4UEx9Uok0D4RjRCQ== + integrity: sha512-ooD/FJ8EuwlDKOI6D9HWxgIgJjMg2cuziXm/42npDC8y4NjxplBUn9loewZiBNCt44450lHAU0OSb51/UqXeag== /@types/serve-static/1.13.1: dependencies: '@types/express-serve-static-core': 4.11.0 @@ -14216,7 +14216,7 @@ packages: dev: false name: '@rush-temp/api-documenter-test' resolution: - integrity: sha512-Qk1biNNk3nWYenDTiIqYW70vLuReSnw31Rc2Fd85le2izmqMzpVYoisw+KF8ja6Xt9ypQd1h0eUvDy31hTEyDQ== + integrity: sha512-N3sX6Wn+j3iX5n/0/hgQlE9cGDGjicw2md5w8pICe3wZ+EdhPGKhb+/T9f+6/gLN7ze9UQK3r+Was0jn+15Yng== tarball: 'file:projects/api-documenter-test.tgz' version: 0.0.0 'file:projects/api-documenter.tgz': @@ -14234,7 +14234,7 @@ packages: dev: false name: '@rush-temp/api-documenter' resolution: - integrity: sha512-NP2auGxTmo90sgiJQaYfXT7rAr6LM//a9D2cwZOC8ll0AZrI1Zj7mkLiqGQzEkZ0E0qVqoM2RHbl4AeJqq4XOg== + integrity: sha512-26IFpsCHnC8xswRADM6yNgyjSpamM/4dr2HQ0i2vJP4+T1CAp+fQB/c/6DTAPSrkRJh4JoUk+2vEAnyKdyxX+A== tarball: 'file:projects/api-documenter.tgz' version: 0.0.0 'file:projects/api-extractor-lib1-test.tgz': @@ -14245,7 +14245,7 @@ packages: dev: false name: '@rush-temp/api-extractor-lib1-test' resolution: - integrity: sha512-j4cGvRknTDXwBbM7rx7X+V62UfeTK9kAGkSpT3GpaZrRTwbtZhzPWyqY9lzw6tN43xlX/Iuc1g4FmnVDe1lqWA== + integrity: sha512-GJEYULnJp6VrMhne9cAQ+6sG7eqQcLfOErf4GkzxPjTm8Rcw41y0loj+Fg39XDTkHxIP4+7RVgUCBHnpCo044w== tarball: 'file:projects/api-extractor-lib1-test.tgz' version: 0.0.0 'file:projects/api-extractor-lib2-test.tgz': @@ -14257,7 +14257,7 @@ packages: dev: false name: '@rush-temp/api-extractor-lib2-test' resolution: - integrity: sha512-0u0G7fscl+qgsZ7GNjTcRgAKGFVUvrk8UhgIe0bHUQhwruHEjrTvpjdM0HbsdOhfVt63fn+AkP4q0JCK15ZxKQ== + integrity: sha512-GSbBTZXZLdyBB5tDty+Z3KVQASBC++6ATAXQexS+lKWUL+0+sypToNUxrakMqySNdxa2lkguApHEERuR/ux49A== tarball: 'file:projects/api-extractor-lib2-test.tgz' version: 0.0.0 'file:projects/api-extractor-lib3-test.tgz': @@ -14269,7 +14269,7 @@ packages: dev: false name: '@rush-temp/api-extractor-lib3-test' resolution: - integrity: sha512-W+ZrYIx1rYjFin/GB0CmDltXHLL3OsJ9xxoPcH5wuZQWODiP6bBD6rpeREeoZ3webIwF7yz5RWKZ27PDgUCJDg== + integrity: sha512-ZsBehU1FmzR9k3oWlFo14DVTzOIAPxuT8l3KamEMnUJy/Jr2Hr8yDHq2BiWgOozf905CMC0VisJWK5MoJKZrRQ== tarball: 'file:projects/api-extractor-lib3-test.tgz' version: 0.0.0 'file:projects/api-extractor-model.tgz': @@ -14297,7 +14297,7 @@ packages: dev: false name: '@rush-temp/api-extractor-scenarios' resolution: - integrity: sha512-eUE0t2GtLcGwT3WjFlgrRtxwNKaizkYauWQew1fRglDIMQp+KBwslGEVkqq60fy9vUQF5ccnP+Vp9l42kxrXAw== + integrity: sha512-sL6YBKqdUloUWJMuaH8atKi2wjaao5DWeDcDnGBz/F91AM9WKvyxIFIVk2GfMhPdDqSIG1CofGWlDjJCZf1g4A== tarball: 'file:projects/api-extractor-scenarios.tgz' version: 0.0.0 'file:projects/api-extractor-test-01.tgz': @@ -14311,20 +14311,20 @@ packages: dev: false name: '@rush-temp/api-extractor-test-01' resolution: - integrity: sha512-gtQg1x+6BbSPaQJzE2lXPhYuASORkogG94ctPkiyst6rEYlHifzW0rPB8TyEo+SjzcsVNil6Q8UygxxtBkR/dg== + integrity: sha512-ivgavBxw3KbtXdnokXG6NJTx3PB6e5UOs9hfpdRbEnbYgXe02UEpxq2i6yeyxC4mONjsRu7Srp9nQ0bgtOg7VA== tarball: 'file:projects/api-extractor-test-01.tgz' version: 0.0.0 'file:projects/api-extractor-test-02.tgz': dependencies: '@types/node': 10.17.13 - '@types/semver': 7.2.0 + '@types/semver': 7.3.1 fs-extra: 7.0.1 semver: 7.3.2 typescript: 3.9.5 dev: false name: '@rush-temp/api-extractor-test-02' resolution: - integrity: sha512-h9Vb7Rts0J3jH380YqWmoi7+58++gY9gKFyLCLDViod83x02U89jK5eKViOSYG9+JDiphLtdXJ8JN4aiVMqPtg== + integrity: sha512-bLdmbASOurd5ETsUGmQzu5d82bNCcIbsvtopdksrjqHVur62TBlK80EiegmoXDe8J3V5MYgI92KPHYgHG9iFtg== tarball: 'file:projects/api-extractor-test-02.tgz' version: 0.0.0 'file:projects/api-extractor-test-03.tgz': @@ -14346,7 +14346,7 @@ packages: dev: false name: '@rush-temp/api-extractor-test-04' resolution: - integrity: sha512-kuJ7xZ9rFAB1Xha/iTothhJRqXIUF2s3t+c6hj6Ls8jufjpo+jwnk2ho4TrjzCI7hzGP7ydLnXywFKZhZ0GuIQ== + integrity: sha512-FpnFl6J0BRmdkq6Y7Mvv+HM3yOQUEZVB5rvmusfxmDk1eLfdIVJqSBmlbAmefVOeRLozfTca3rL/t02nU+VvbQ== tarball: 'file:projects/api-extractor-test-04.tgz' version: 0.0.0 'file:projects/api-extractor.tgz': @@ -14358,7 +14358,7 @@ packages: '@types/lodash': 4.14.116 '@types/node': 10.17.13 '@types/resolve': 1.17.1 - '@types/semver': 7.2.0 + '@types/semver': 7.3.1 colors: 1.2.5 gulp: 4.0.2 lodash: 4.17.15 @@ -14369,7 +14369,7 @@ packages: dev: false name: '@rush-temp/api-extractor' resolution: - integrity: sha512-4kEzephkXZuLulJrW+CAIU1ieoPrHjHlSJXpYqIoVvAqd2okqrysnBx4LBZd51Qmo6OkLslC25wOmgZDwsJXJw== + integrity: sha512-TnLRREXVw5WT36j+XkIIx1SyOuoxJTJL1ruaT572GLqDAEs+8SjxjxKb59H+XltYL8LZTjlUrusiXjS/Xkj4xQ== tarball: 'file:projects/api-extractor.tgz' version: 0.0.0 'file:projects/debug-certificate-manager.tgz': @@ -14384,7 +14384,7 @@ packages: dev: false name: '@rush-temp/debug-certificate-manager' resolution: - integrity: sha512-RCmD4L/QRni3fAbW7QQIZWxgQ2BxCoaMBHhJNl+MN7Bt4mBZ7jZf1770fNzTba8TTXpq5RasjUU7ihGEL7qsOQ== + integrity: sha512-w4g2wfUNni3VvvwfSwurrF8lzrtL2iRs8Wh+rltj+d4mad+kUYlJKTaatUC7QH47z3aOhBvXgQ6z/cNVlHMfLQ== tarball: 'file:projects/debug-certificate-manager.tgz' version: 0.0.0 'file:projects/doc-plugin-rush-stack.tgz': @@ -14397,7 +14397,7 @@ packages: dev: false name: '@rush-temp/doc-plugin-rush-stack' resolution: - integrity: sha512-N6qFz5WIhWV7dvh2FWM8knYWOx7AHQHg8LYJWTTXnfWHeJx74XlKiK+EzVYmOEMNXKCFj8ihIvNmUMBNZpUlzw== + integrity: sha512-S9Su0lWdXAS+9hD874FIYZMDOS+QhcGHk1LuhMsHqAmKs57IRnIbKQY8J2CBe4u4oCXXvqHf/tM6VlLLsBbp+A== tarball: 'file:projects/doc-plugin-rush-stack.tgz' version: 0.0.0 'file:projects/eslint-config.tgz': @@ -14454,7 +14454,7 @@ packages: dev: false name: '@rush-temp/generate-api-docs' resolution: - integrity: sha512-kYuy0KhmbVlRgzysnD3WPVUVnWCIELSGDkiyY9ggRdvrTAbBacjYEPbYp7qep6BXAzdqd7eDPuWv6e3mzwvVvg== + integrity: sha512-P5sPB7nmoQSRPByV3DNoj6DvFTPLFfgfDvTMjh0q7GwQxjkcO5Fcjzi2dgn5Bw2NqY90fHQXg0mn3M1ECpy+0g== tarball: 'file:projects/generate-api-docs.tgz' version: 0.0.0 'file:projects/gulp-core-build-mocha.tgz': @@ -14498,7 +14498,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-sass' resolution: - integrity: sha512-Mlna3VhrcK35LdQBockrHzexTwQj1LnjHrL+vlhi70m9UcCgrXSucynGMPNvGDHCv9O0mUC2O/XIFoUXdf8eeQ== + integrity: sha512-H43Cg5Pi1tkvprKzPbmwfy1FR5XAO4F+HlSDLl8PQ4j0kbchC1QG4xmw3JyYlZoytXDj+bBLPemKvbH4w3nuRw== tarball: 'file:projects/gulp-core-build-sass.tgz' version: 0.0.0 'file:projects/gulp-core-build-serve.tgz': @@ -14521,7 +14521,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-serve' resolution: - integrity: sha512-EcDZupb0dv3v+0Yve3aVwNEK0amNhR8o7nwaVOx+gOxhxXdUW1D2gv0ekKomJhO+m2xnWngGiCIY4qBGQlnwPA== + integrity: sha512-WqO9Fxz/JzIDWu43Jjlz7UM8Ndsj7uT+UJwCyKZYHiDzlpd9iy3ZyYg5PZmC//qFd2v0V+DdRMdKNdtX/R2Hyg== tarball: 'file:projects/gulp-core-build-serve.tgz' version: 0.0.0 'file:projects/gulp-core-build-typescript.tgz': @@ -14540,7 +14540,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-typescript' resolution: - integrity: sha512-6wSeAy3PrwsXxBCmWnAtqK/xVuu40Nb42vQ/ym0fQ50mTTRDB6qhTgY+Yl3wseHBtf4UvVX8JaZExsaQdLhqqg== + integrity: sha512-SlNQaM+F6T7rtrTu0fHQDOxB6qxnyyyzbIapwWF40Wii+Rkl/8M4v2uIpuH0bkdTn3jjKDukj6VneWiIft16Dw== tarball: 'file:projects/gulp-core-build-typescript.tgz' version: 0.0.0 'file:projects/gulp-core-build-webpack.tgz': @@ -14558,7 +14558,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build-webpack' resolution: - integrity: sha512-QC5XgdjN+DvNrs3GkM/txMlLSL+cWXdSrVyr4x4VKCaZtTUrdePomtnC0EptxRLIiDHdkP7L8kPxcJi5uGE69A== + integrity: sha512-vI88woBOs3twABx66INX2c34IeqcPY+c1pVFnCSxkE+rz1xUmDU/eScAAiYDZ4gM49IYqNfLSgRF7hP4ZLFwUg== tarball: 'file:projects/gulp-core-build-webpack.tgz' version: 0.0.0 'file:projects/gulp-core-build.tgz': @@ -14576,7 +14576,7 @@ packages: '@types/node': 10.17.13 '@types/node-notifier': 0.0.28 '@types/orchestrator': 0.0.30 - '@types/semver': 7.2.0 + '@types/semver': 7.3.1 '@types/through2': 2.0.32 '@types/vinyl': 2.0.3 '@types/yargs': 0.0.34 @@ -14611,7 +14611,7 @@ packages: dev: false name: '@rush-temp/gulp-core-build' resolution: - integrity: sha512-shYhDXfrdXxFzB3H50wpPM4iY/a1ZU98Xa4g0CKrgwjbwyG+r+trVasnkN7taRNxLF2uFs5b/AHrIh48AzYwoQ== + integrity: sha512-FwoXkTqeyxoYFYrfi3OD9nJeRo4Kei5n0nmm+i5wVW2zK8wn/hpYyWrZfNMZG+OtreFhQ6kXDpwqUOXh+JK3aA== tarball: 'file:projects/gulp-core-build.tgz' version: 0.0.0 'file:projects/heft.tgz': @@ -14629,7 +14629,7 @@ packages: dev: false name: '@rush-temp/heft' resolution: - integrity: sha512-of6kz/4U9YQ+9xvHtrXWg1hQYlCEyrHJdUIptbeBpwJgBxS7DLn2ffzvWHm4Rts2Vs2NLiXm3OZS96tAoG5qSQ== + integrity: sha512-ZM/Il5u9m3Z6vORYQHEev9UE6gDysPrPFe92dh+cv/FDiDI9jk9h/x/OFs6mh53DgS1alKkOrJ4F92YJA2geCg== tarball: 'file:projects/heft.tgz' version: 0.0.0 'file:projects/load-themed-styles.tgz': @@ -14643,7 +14643,7 @@ packages: dev: false name: '@rush-temp/load-themed-styles' resolution: - integrity: sha512-01vIZKCCPY6M/uPP94vTdUGrFllQ7PFfmmdy/mY8oGDwETMqhahB08al3DizNfnf4mGCuWbvogPd3QvpLHQqlA== + integrity: sha512-N+8Bu3SSYU/ywsuMFcIEoYE/cia02gdfnE7+nkLV3BQTTmEWRWKCLLKMLuHYRNHNWfiBR54Xv63LcePz26PceA== tarball: 'file:projects/load-themed-styles.tgz' version: 0.0.0 'file:projects/loader-load-themed-styles.tgz': @@ -14659,7 +14659,7 @@ packages: dev: false name: '@rush-temp/loader-load-themed-styles' resolution: - integrity: sha512-p7Iw5IsjI2eu+A2NgaOiqndBPJ46DHdd/cpykA7DoS8nF8geTM6/74DuTnAWRzrVSbbEHT44+04zCeMZeu9Mrg== + integrity: sha512-peoYtJIZrwnKHPiSObHs/6ScZzVzrphJPQhaWQK/inqJ2mXo93mEcTjL4wzbDiubiR5JWb6IBla3OWyvM+/bBg== tarball: 'file:projects/loader-load-themed-styles.tgz' version: 0.0.0 'file:projects/loader-raw-script.tgz': @@ -14674,7 +14674,7 @@ packages: dev: false name: '@rush-temp/loader-raw-script' resolution: - integrity: sha512-g0YMLdY/Df2nQnUg3tP4osBSxrXDliwTFR8sD3qw5wrh7xtuF2JhsUXjMMeheAe31igxYUI2mYhPIsTUnDi1YQ== + integrity: sha512-pxNT3U49dpxqZEjjd7e98RP8W9wrPDVlxI/DgZRYaddlmknfWZlUg7gNYOihk0rr78V+5vsdl7T/xmk80u0eWw== tarball: 'file:projects/loader-raw-script.tgz' version: 0.0.0 'file:projects/localization-plugin-test-01.tgz': @@ -14689,7 +14689,7 @@ packages: dev: false name: '@rush-temp/localization-plugin-test-01' resolution: - integrity: sha512-T1h640rfmZr9IjXFfJU79OBnKR24s3d/T63izdP7l5QQSx0+ypQ3nZJX8cNK1LbuFPto31C7A0vcf/RjbM5j6w== + integrity: sha512-awh8RmQ7k/SeDz0aBtV9Q1rU/Oa0FcvKa1ZmiEueX95D/Q4dsx9sKIZ6EngI9wARKUBybnMd7S4XKhAfI/4sog== tarball: 'file:projects/localization-plugin-test-01.tgz' version: 0.0.0 'file:projects/localization-plugin-test-02.tgz': @@ -14706,7 +14706,7 @@ packages: dev: false name: '@rush-temp/localization-plugin-test-02' resolution: - integrity: sha512-oI6y8e286Uk1W1/153DjcpIWF+0hSST/JhOxzG83DI7SVNN49k/VWaM4YAXXmGe2WdhUsQDqh8sopm0HAhNq0w== + integrity: sha512-X2BlXkZD9TumA9AdUmKRmtJk/BDHIqgRZMXj34kwKB4vVgoYntLxdSGlcgSJNusHDlSXMNWMiT11PvorcjME2g== tarball: 'file:projects/localization-plugin-test-02.tgz' version: 0.0.0 'file:projects/localization-plugin-test-03.tgz': @@ -14721,7 +14721,7 @@ packages: dev: false name: '@rush-temp/localization-plugin-test-03' resolution: - integrity: sha512-1FZYUFCd91HyzzVV656MKZS/Pce9++sM5L6NhXZmKzFfKsDwFWhD3TbruN3L7qfDJ4fEAH9m64hVgYLcjA6Biw== + integrity: sha512-s87/fvvpIdQzrtl1c/HIjcgze/l29CYbv4r/9Hb0LPipsv9OQ8a3SAEI5R//YDzaCE3tFSlwuVq5A+Rpakxvkg== tarball: 'file:projects/localization-plugin-test-03.tgz' version: 0.0.0 'file:projects/localization-plugin.tgz': @@ -14742,7 +14742,7 @@ packages: dev: false name: '@rush-temp/localization-plugin' resolution: - integrity: sha512-NGBE5WLIbTDgzylanE3T46NtyiIzG1HhUKNIDwpmVQy8ZxD+IIqeWNHOM9utBEz/KzBVBMuKlfPg3vl+gOxMIw== + integrity: sha512-/vxTSha51J4tm9TCFijIma1f6pG5VV2mFofbypj5TaY9lnbVdqV+63WA1JFQgEf4qZSO0UyjZLCtdqeW6YLYsg== tarball: 'file:projects/localization-plugin.tgz' version: 0.0.0 'file:projects/node-core-library.tgz': @@ -14753,7 +14753,7 @@ packages: '@types/jest': 25.2.1 '@types/jju': 1.4.1 '@types/node': 10.17.13 - '@types/semver': 7.2.0 + '@types/semver': 7.3.1 '@types/timsort': 0.3.0 '@types/z-schema': 3.16.31 colors: 1.2.5 @@ -14766,7 +14766,7 @@ packages: dev: false name: '@rush-temp/node-core-library' resolution: - integrity: sha512-RDJ2BrVdYldUKa5lXoSlyBooJzJJkNDEwRBBV4q4XxFzKyHKvctWBt0UQasKrxywPvMq0FcfJtf8Wp88iYKXyw== + integrity: sha512-+QxiCr+dzamzPCYnGHY5Ttuss+UuIKXMsxDpEEcYiQfPKYCdzS6tm22gJiwc1eG1Exd2sfqJ/ILdQdH0nYOOIw== tarball: 'file:projects/node-core-library.tgz' version: 0.0.0 'file:projects/node-library-build-eslint-test.tgz': @@ -14779,7 +14779,7 @@ packages: dev: false name: '@rush-temp/node-library-build-eslint-test' resolution: - integrity: sha512-hOP/rEc21giPwlkAXL9oMWM1kWDOwQfFbucvUvwFtnIvwRW5BU5hwfLUpLsjgiC5tQ1XBCLFojZqoGY8G9vRPQ== + integrity: sha512-MBzeUZk62MvhUzW3mLeVUXIgULkCgGUk8Ehi+4PXLIaEaOPCdBIFVGkZDhLnk39Eub/8Egjh7gH22T9po24Dbg== tarball: 'file:projects/node-library-build-eslint-test.tgz' version: 0.0.0 'file:projects/node-library-build-tslint-test.tgz': @@ -14792,7 +14792,7 @@ packages: dev: false name: '@rush-temp/node-library-build-tslint-test' resolution: - integrity: sha512-OSj8uA034CdrDT/08Nlptckd168hDytKHXXXUPAXQ6QiMBfKm8Z2g577vZyH1lfE9WWK9yRpVljs7+7DtFIMWg== + integrity: sha512-+D1eYp72IgyoC9cgAs/w9sWdUCo/MBe+oB4lQ8lQ69YEY42XsYVVGDyNABrRiiT/luUUU5ECciLhWT/Dpuvq4Q== tarball: 'file:projects/node-library-build-tslint-test.tgz' version: 0.0.0 'file:projects/node-library-build.tgz': @@ -14803,7 +14803,7 @@ packages: dev: false name: '@rush-temp/node-library-build' resolution: - integrity: sha512-3x3En+KDCO8RFVxwvrzP614SP8nUTc9R/5eAfUC5Gm0mzmLZaNHBFOXHANDWvbM6nCH09p7hK2QXmu93wHcw1A== + integrity: sha512-LKHrOcDmEhsJnedyGUHqoC3RwHDZptOrJsE2JpXJnBXOiwbq56y35mtSXCvfXaMtmX4rMZVBClFq7Hbrsfw7WQ== tarball: 'file:projects/node-library-build.tgz' version: 0.0.0 'file:projects/package-deps-hash.tgz': @@ -14817,7 +14817,7 @@ packages: dev: false name: '@rush-temp/package-deps-hash' resolution: - integrity: sha512-HvlJgTBK1wsoSq697epvJWYsuF0tu85yD+IXlBqkc77oub2YgpjP9An3CNxo7Kvm+FUnYCq3AoJFn62MVjgTSA== + integrity: sha512-teCk5NgTOrJdXvUaBfuWJH8BRxL05rTuh8kf6mprUkPKZ2hIpmvA7riXxuuVeW8PNtHozffrQZ4WWALTW/8AmA== tarball: 'file:projects/package-deps-hash.tgz' version: 0.0.0 'file:projects/repo-toolbox.tgz': @@ -14827,7 +14827,7 @@ packages: dev: false name: '@rush-temp/repo-toolbox' resolution: - integrity: sha512-YQulqxSmK0+VHyzZO8qHNVmkapqqZ7m2znjnH0pWmc75loYrUHMUFjxUPOIA6ZL5TK43/MtX/EHfOaxGVUqpXw== + integrity: sha512-kpl0zSrwq98YiabSjKn/C/fyNj0AaSmPQZoe5HvF7BJ/PHANhKt9oODwkO5d9BOItshbb5nUkowwt7mFhv1C6g== tarball: 'file:projects/repo-toolbox.tgz' version: 0.0.0 'file:projects/rush-buildxl.tgz': @@ -14838,7 +14838,7 @@ packages: dev: false name: '@rush-temp/rush-buildxl' resolution: - integrity: sha512-5z4k+kvvd7xBlG51bsnNCMBJTbCgoHzv8zzH5l8qNQoeS9MZ1K24xYvl4dfsq4OvGiOHwCEoX/zAzZH1LQTxbw== + integrity: sha512-daV3LDqarUTJvk3PBp9YDnyaWRToca3CGH08sGoDkbJGCKTF1qtuHio5hTO+tVB9BStBe0DqPxMQyn+cy01EGQ== tarball: 'file:projects/rush-buildxl.tgz' version: 0.0.0 'file:projects/rush-lib.tgz': @@ -14856,7 +14856,7 @@ packages: '@types/npm-packlist': 1.1.1 '@types/read-package-tree': 5.1.0 '@types/resolve': 1.17.1 - '@types/semver': 7.2.0 + '@types/semver': 7.3.1 '@types/strict-uri-encode': 2.0.0 '@types/tar': 4.0.3 '@types/wordwrap': 1.0.0 @@ -14890,7 +14890,7 @@ packages: dev: false name: '@rush-temp/rush-lib' resolution: - integrity: sha512-PHze32ux9+k3o8RQKhepW4OrPQXOVOvhjC9tG0JrJdTuzIcqpycFG0xQQJaJDm6wzbn/H3iuLhUxA3AXQGRfLA== + integrity: sha512-s6KNN2WSiLi+AgoLQkeB5GTStGp4XVZNkF4E5LnIHRGxOkxW1PInIp3uMH5lq0goD5uVssQoSQu1m6e2dG5Cgg== tarball: 'file:projects/rush-lib.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.4-library-test.tgz': @@ -14900,7 +14900,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.4-library-test' resolution: - integrity: sha512-4VhQoGUInk8shJLdM6lCb9GsOll3oWH4OcJVQ6cAwgK6YKdFb1eH23Tw/ZooOeb6MxnUu7fLZV2vYLZeBGWieg== + integrity: sha512-VHngAbPFlPEIJu03Es93w1f3M4qeTzIsRF139TeWm+xZdLVxG1t0YngcVf8oYtaBgFXAulqMmMj404ExXzl3CA== tarball: 'file:projects/rush-stack-compiler-2.4-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.4.tgz': @@ -14917,7 +14917,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.4' resolution: - integrity: sha512-hG1r5yVDkBfx71HPn3Mev3yLwwOW95hi5Lr252mIkJnm+ahdIWalooVao0FD7iobjbBSDiLOHTytiJU4B32Igg== + integrity: sha512-iC5Irn0ZTtJtQQOjgHAlVk/09woLuwHgsqkeBsb2fJDqrR61Ju5J95wwiaU538JcJmyxh7ZJBDOCvbqLKmoG5w== tarball: 'file:projects/rush-stack-compiler-2.4.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.7-library-test.tgz': @@ -14927,7 +14927,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.7-library-test' resolution: - integrity: sha512-srXLgtPwX+/ohQ8xpWKCPF8QbMBuNpSyG35DhKK3KhrMOhcgjT391Hgk1x1WIeZQtV5PlPphoc3VNqO6ouZb6w== + integrity: sha512-sCfTPALT5gAgV7hWrT3N4qO/H2NXisKx5eIrjhdiAUK0SqB8ratcGH3V/TRpEqaRgTXWZq8UzSh+XcnHAaVIOw== tarball: 'file:projects/rush-stack-compiler-2.7-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.7.tgz': @@ -14944,7 +14944,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.7' resolution: - integrity: sha512-rMrR8wum1C9L+d3rTjiWk6XCec7lVJvYiaHhjIXtTd0ES4dLdosgCia3uq9ajD0+NToY4QAAwoq+Y+gsTaT+3A== + integrity: sha512-QW7Ei6IkWSDe9won4aCLSrGdWHvVCL81SKYFtefN1ccYAiZjPeEyTs5JIcuPNio9FBbj9ywxSEQFd0iQrluoLw== tarball: 'file:projects/rush-stack-compiler-2.7.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.8-library-test.tgz': @@ -14954,7 +14954,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.8-library-test' resolution: - integrity: sha512-AXRaABTMx4u38YP67laQmqB+9Q5nLVnxAzQgC3Tz2ukUtg7VOwW78aSbJS6tWi6r40koxf0kjza1xaJys/LbEg== + integrity: sha512-jSqVwOewBxVxWkldehxsLZh4RTjXeu3Y5HK8z4b/MP4MLVvCSiSJjRsWYHPOcHtC4GwbmiLrnFemkzRJYTccdg== tarball: 'file:projects/rush-stack-compiler-2.8-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.8.tgz': @@ -14971,7 +14971,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.8' resolution: - integrity: sha512-BgpuKWwcQsUPz/CnVlSa5I0RCHt14HtoVDsxSgts+OftigNAqwbYDS+bLIIaPH13CVWJj4hXkY+8SVUGtBtHpw== + integrity: sha512-ywquBd0lbKHaQWLZ76Oq83gBxlqegtp1xaOic59iLfi0HESaiJh3q8jrYYbWG/x2iJSxJ7ySimUfNq+b6iYs9w== tarball: 'file:projects/rush-stack-compiler-2.8.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.9-library-test.tgz': @@ -14981,7 +14981,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.9-library-test' resolution: - integrity: sha512-COU64dI/gxMf5Fde2Hpk+XCkcB64qzY47rIJ9qZWTp7b42rEPkqBZCCmOvdprCV1QRXezeY+E+SYSxirN/1f/w== + integrity: sha512-aX/auHxjJtfSBGnwbvEFRiiWva2WPbEFAAnSXlz0MwpJKSLx/elRezLxTizewi8tfmOWf9/zJkllI/OwEpxKaQ== tarball: 'file:projects/rush-stack-compiler-2.9-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-2.9.tgz': @@ -14998,7 +14998,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-2.9' resolution: - integrity: sha512-Tq6IFsZBQvwJfaRARpw7a51TXHUlPeHJT2MX69eXN1vXQQWle9pIoSpq4iQS5CWy7J8f+j2honpUy6DpuCEzlQ== + integrity: sha512-xOUdXc3fFgOlMROjPRfOWg0YVygMXsUpG3A5RoCiYimZLl6yOUhndR54UA+4EQYt9PpwgNOOORumQxgQaKRwOQ== tarball: 'file:projects/rush-stack-compiler-2.9.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.0-library-test.tgz': @@ -15008,7 +15008,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.0-library-test' resolution: - integrity: sha512-KbHGX9685/56jgLK+OXEphJa7PATxHNUrmNadMkKFTejTky68+PqpqZd/aV9HPC/XW+TuHwH5/vYq3Ih5tUXDQ== + integrity: sha512-dIdMFIfLwY9rhsAnYyaBvKeadBMiHf2gx3nWxJxruO9HSahdrMrQ9jDaEXej5MK/weD+1Pd76HURUC2k2W9tGg== tarball: 'file:projects/rush-stack-compiler-3.0-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.0.tgz': @@ -15025,7 +15025,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.0' resolution: - integrity: sha512-vMLB2XFdd0LGxgFcllFuQSvzzwXn6TqFdmb4xeki/2mSbYZku1AQaV3a8IWybiX59Xh9XpPanNhMsuu0iqiNog== + integrity: sha512-n3cUf0o1gKbMQvjVEc+4AQpll7brDVQ5BHqMckV5jiHIGodhVTMttQOKl6wq80OsWdqSNvHLu7r9JcxmHohb6Q== tarball: 'file:projects/rush-stack-compiler-3.0.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.1-library-test.tgz': @@ -15035,7 +15035,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.1-library-test' resolution: - integrity: sha512-FdL2pswO0WrPpMYll+E3Wg2TA97tOm7wFPOklI+Z+Y4Zw8FuGO7eG0lRMC76skBwyeaM7K/ZRYcX8MFQWvNBJA== + integrity: sha512-9Y2vi2YbRp8jBgqtIU3NM7DngyS15+sBCSUVHiXHopxgzQsNcb+H/FnVottHzIjQdk4l4WU2Hm/N2TnA8SKAxA== tarball: 'file:projects/rush-stack-compiler-3.1-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.1.tgz': @@ -15052,7 +15052,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.1' resolution: - integrity: sha512-/ti1UbntA4cFzQr0ZgG9rqUIQXqNGydcjmhMXpn/p9hEjZaQdJ/R+xTCQcwt14vLiaXZqkwziad+cDM2GAQyKQ== + integrity: sha512-w5EuBcFgTLYP+lh1OjTZKqKaVaQI/ZDQmdkyVrkBNUadJkVcb8G7TotndrgEYfYyNsYE/KX066UujXaGJgN+Dw== tarball: 'file:projects/rush-stack-compiler-3.1.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.2-library-test.tgz': @@ -15062,7 +15062,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.2-library-test' resolution: - integrity: sha512-aniHkRDpldzVnHxvrXBtXjbAHxh3swMCIo9vEnB0hHw9FFFUdFWxKVowmAj4lj7os2cLgimq3URLfom1k2kWzQ== + integrity: sha512-nc2B1hO9W3VrYZ8R2/4X1DSQVzUTDhxuhm0bIsb2zmbkMIGK4FnPcDy0wRgorLx1DgC0kkR1jHFvh8ZLChGPkA== tarball: 'file:projects/rush-stack-compiler-3.2-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.2.tgz': @@ -15079,7 +15079,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.2' resolution: - integrity: sha512-cU/RSNyebjIUmJfbnWZQW96KoMAFKEFtyehPVguTA9vSalA+kTfFAQ9gkGwlmCQ3aTpM4f9z3VJgew/4QM2ifw== + integrity: sha512-MDIMKdD6HRm5K4CI325dlkHCveiBjR+BoUORFr4sqCN9s4mJhlRtdxfaBn1i/04AJFgcCgPMa7L7KgReEPSPNg== tarball: 'file:projects/rush-stack-compiler-3.2.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.3-library-test.tgz': @@ -15089,7 +15089,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.3-library-test' resolution: - integrity: sha512-efsGPnFV/RsutIBBRgyLx2Zq0C15rNtxN9lY6VJXhS5CA8wPA0H9MrIxDrMZo4t4Slxu2y61XMYbU6J/opelXw== + integrity: sha512-1HxiLT7wSfKyPfdLnO1asb4MJ4NSViZNAgVr29HU8cFIETVD+B+rBan/qKWJWcKBMDntgEYOwPAh9tKBGTrvBw== tarball: 'file:projects/rush-stack-compiler-3.3-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.3.tgz': @@ -15106,7 +15106,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.3' resolution: - integrity: sha512-b7NF93lucZ3408ZIizqdda01HqEGoFbaDrGSf89B6gN1i88WrrXoQ2K+17v+vc4dLY32+HDM0mgw6xy8rYCMVQ== + integrity: sha512-y3VhB0CpRezYiSiZRi+LOvjmaeX49I5akoxPZsAbMZZQEJR2OuYXAMuPWg+g8vHrAldEG9FXN1y3Kaj/G6ZuYg== tarball: 'file:projects/rush-stack-compiler-3.3.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.4-library-test.tgz': @@ -15116,7 +15116,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.4-library-test' resolution: - integrity: sha512-R4TRjNCH5A+ER7bucWPT4+NlyD6MFumjSrMak2KLYDg33KXbJN051fzieqJQoltfNHGkQDIgXCh/6qZR8OFISg== + integrity: sha512-cC+RIr/IyFTcV/ftDha8Y7jMDc2G1AuzeWlTune/f4ep/uc9+PeLfwUwODDQcpxUycIL9TzUwnDd3ZKMAlKtIw== tarball: 'file:projects/rush-stack-compiler-3.4-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.4.tgz': @@ -15133,7 +15133,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.4' resolution: - integrity: sha512-LdDJIHD+jg+T2JsfdquoatKkxL8hHnH6Tt/1IcOxku7ZIqTWpFeQ+g3Et5eGQ99ki33u2jN5zCLijR3NPGQYxA== + integrity: sha512-z/hX/vrdwJHwc2cbBnMSWyy84CMJelGrSDfnaAa5j4emwVtKntyOcJkU3krj//Z9UNknLYp2c8xStVLykud3Ig== tarball: 'file:projects/rush-stack-compiler-3.4.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.5-library-test.tgz': @@ -15143,7 +15143,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.5-library-test' resolution: - integrity: sha512-fyZKZsfcBG+y2FEzqfVyMgykQf6OceXQ9nGviE6WAwKBtz0Q0+PMPIYUuUmYDLXwSYaDSr5teXUk1rcva1vSag== + integrity: sha512-cfAbSdwPvWTgq6D9F/SGvhdyLwJcpVg+SIqM0l45gSFR7Rg44IzDIc5QiZ+uzDKGnDupMX0V5Kuu1O9eW02i7Q== tarball: 'file:projects/rush-stack-compiler-3.5-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.5.tgz': @@ -15160,7 +15160,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.5' resolution: - integrity: sha512-JTxecGPqctAodYS7PndNd7oncQ5bk6WTx9wxIjLnm00BG0mvPcksngOEQ81GT7c9Gi65S3OF6/5tZpN3Yf/ADA== + integrity: sha512-cbHr87qGapmZNrpcINuVVni6vDyiQn07yHz3euGfGg/3EWWV9INOG9C6nPd5K5vQXgPtz68kuzaJjXt/ybrfDQ== tarball: 'file:projects/rush-stack-compiler-3.5.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.6-library-test.tgz': @@ -15170,7 +15170,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.6-library-test' resolution: - integrity: sha512-8JdP1KV8bF0cjH6CORh+D+dRzW6ekO0TTFpEdcysnR/eUcDcNlDYhyifOqymkp/xfsCB8zRZh2uwi51N5v4P1g== + integrity: sha512-sOm2pJJJfcYJK4SeDofcqMZ9BFZATfxIhucyS7Xai9elIlI1zTUJyeSWZgVUS531MxcKoWrQnwHwBWpJr8DmqQ== tarball: 'file:projects/rush-stack-compiler-3.6-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.6.tgz': @@ -15187,7 +15187,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.6' resolution: - integrity: sha512-+2EQQ8/YMqzqc/bi2CiUwpQnKUpvGzTepNtVdtodO+zkUy5fLElf+5nzmet3dPEWCreR1pAc/ce16MHE6qVTnA== + integrity: sha512-PctVC5qNzfm21MNdRAYF+3eXWSb6cxNnPa2pGvKrUKG5F36uAg/w/lUvTiFG5xCZj5t19s0WfATZbXGCRwThHg== tarball: 'file:projects/rush-stack-compiler-3.6.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.7-library-test.tgz': @@ -15197,7 +15197,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.7-library-test' resolution: - integrity: sha512-s4Sh6RDfa/jml/8XxxYA2XpGSHZubZGnFtiy+nYuzUyKeqlZITaZ21lmK3/SMKBrvFhLRHsopk1YdWFPARRVhw== + integrity: sha512-RgA22oa8sMN5ZPP03C27Dp2bZ2zBD69OnaNsbQ7veDmuiT5io6tNDno2KDKD2krBUleIyP5uG18eITwjK+cjsA== tarball: 'file:projects/rush-stack-compiler-3.7-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.7.tgz': @@ -15214,7 +15214,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.7' resolution: - integrity: sha512-rLsIDtuo9SRh3D64477T1JQWJ+xgK4M9PU1MDaK46iAWNyAjohUcKSaaiAcSROfgthWtWRMo/bKOIJ+nDwFAlQ== + integrity: sha512-LDG2a36dFPVNQ/R8md/LClKBtmwSlal2Oj0CVQAbtUezuB5M7dI1eb99wxKASxY7qKltE6rM8qsyIFPjOpgD3w== tarball: 'file:projects/rush-stack-compiler-3.7.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.8-library-test.tgz': @@ -15224,7 +15224,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.8-library-test' resolution: - integrity: sha512-2SuQ8Q166CtI6gUn4EDk4noGJvM1z3Lf+S9T2Qdeq9U/2phIXbdvlvDU3Uas6HmCIfOazBifOz+Kg2K/r1uN5Q== + integrity: sha512-5UysTUeQWuRX6vXnUi8K90NtbpLKi2eWSJvUFymgD3H7bkE48BvJkL9kIAX25sw7TR+TlzPTPIWasnk44MTGeA== tarball: 'file:projects/rush-stack-compiler-3.8-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.8.tgz': @@ -15241,7 +15241,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.8' resolution: - integrity: sha512-H/wZFsTyYIq7c0crHhDXDoct6T5+l3NvyrzkZBinRNv11EZgYLsbpYb/504HhFGGMSgXc8iwltLNlc/JA8TDmQ== + integrity: sha512-9rYR/uTXYOxcexqdgE7I2H8/N+8tUdMGa7RFM1FzebhbCcbzUadwTfQjbmuWdrDoDC+mlERdDe/kibbnAMdakg== tarball: 'file:projects/rush-stack-compiler-3.8.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.9-library-test.tgz': @@ -15251,7 +15251,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.9-library-test' resolution: - integrity: sha512-e4zCSyw0fH/N1UmJiHkIcSvfzH8P01fIrf9MeEuSW+xG+BGXp73GHcNvJTsMcj9xNO/MIPOqZhW5YDLz5KNQug== + integrity: sha512-5+x3XdYejC2TzmIw25PSsUxkJvEUhaLf6fOInJZXVw9MymDrNJb89GAnj38j0RCNfmeGCAQZzpvoGAYT0IK13w== tarball: 'file:projects/rush-stack-compiler-3.9-library-test.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-3.9.tgz': @@ -15268,7 +15268,7 @@ packages: dev: false name: '@rush-temp/rush-stack-compiler-3.9' resolution: - integrity: sha512-xVJGjTvwoKsEaL4jZSCOazIX148/7CLF0IVh7kplkm2mGuHfoHRWMOXV5Y5I1DQRBw6d1CF/yOtRxgafd85EZw== + integrity: sha512-qlSS3pTeBugJsj9Zv2U+4eTAzEx5LdLD22Abo6Iir/C03452R+Nlp8BFr90i509y2M+tnhdhpncLQQMl4Hv4wg== tarball: 'file:projects/rush-stack-compiler-3.9.tgz' version: 0.0.0 'file:projects/rush-stack-compiler-shared.tgz': @@ -15284,7 +15284,7 @@ packages: '@types/jest': 25.2.1 '@types/mocha': 5.2.5 '@types/node': 10.17.13 - '@types/semver': 7.2.0 + '@types/semver': 7.3.1 '@types/sinon': 1.16.34 chai: 3.5.0 colors: 1.2.5 @@ -15294,7 +15294,7 @@ packages: dev: false name: '@rush-temp/rush' resolution: - integrity: sha512-G21na3eJjXCIrQyAq4aEt1hZxlHn+Fe0PNYJk8AVA4UaG/0jJAqThLdBMaVtZGjyBLjbi3IpMuvRjU+fObR8vQ== + integrity: sha512-KZrz7WcO/R9aDkBcbPuBnZwE4XEdPKtBMDZ59Jzgx+63taV7oriAnE/GIsOtyFRk5irD9CyBdVkvRmbi7Aye9Q== tarball: 'file:projects/rush.tgz' version: 0.0.0 'file:projects/rushell.tgz': @@ -15307,7 +15307,7 @@ packages: dev: false name: '@rush-temp/rushell' resolution: - integrity: sha512-sj5UrwwDh615gbhQbi8VgtSHhI89Ze+12DPBixnsa7sXZwYTQ+YVJ0dOBSYqITUyed/ZpPR70ADeW5hf90MCKg== + integrity: sha512-ARflLxFkROH79kLtn5NyqfMYGWltLLR636nqI7fwU29ek6UGhR7L9YUN7XlCQc0UtvBWo5QHkP94/1qSsR6g5Q== tarball: 'file:projects/rushell.tgz' version: 0.0.0 'file:projects/set-webpack-public-path-plugin.tgz': @@ -15327,7 +15327,7 @@ packages: dev: false name: '@rush-temp/set-webpack-public-path-plugin' resolution: - integrity: sha512-yOQKXWQq3wS4mYOeM5yhKJetDcASn5jaOpPfpI6OByacPGdSvT0bUBWM8pxuPGGp0cchdq2+yAYYsDWJ1rbJ1g== + integrity: sha512-bUzd+GoM1njjrqu/s9ipifyEIjNI3iyrGMM6sYG9KsZ/Ps/oj1Sjyz9C5b9vg2/LD8+08UjLkrilzTicR6sAZQ== tarball: 'file:projects/set-webpack-public-path-plugin.tgz' version: 0.0.0 'file:projects/stream-collator.tgz': @@ -15343,7 +15343,7 @@ packages: dev: false name: '@rush-temp/stream-collator' resolution: - integrity: sha512-Nm5Bfyl1i2EnfGG7ijwlP2TBmti/JSJmgS14pl0FtRMDWOP599DOh36N5jw/z0krrYfieaF2zYOJBRqiHl+pzw== + integrity: sha512-S1St/fmGk12uLVgXmLTzUDWYqilQz/N+sepOLHyqyNSQY+vTutwOjtu1anmcVmmBEMOpxslRvB5SGDagq4I45Q== tarball: 'file:projects/stream-collator.tgz' version: 0.0.0 'file:projects/ts-command-line-test.tgz': @@ -15354,7 +15354,7 @@ packages: dev: false name: '@rush-temp/ts-command-line-test' resolution: - integrity: sha512-AQxi+9T6peEEsJWdyCZVEzd6r4jQaQ5EVbQEoWAZ9NOIIVEpjUZLaiEO/d93ggEGQqKvHB479OgtbgJbUyXhFg== + integrity: sha512-aH/q8anIDQ/909Lx6fRAm9977X5/u3pTHoCkQ7iG03HijH2PV/5ryIlUQCQmRccEDIQco1EdVTrYDWXqhD4yEw== tarball: 'file:projects/ts-command-line-test.tgz' version: 0.0.0 'file:projects/ts-command-line.tgz': @@ -15383,7 +15383,7 @@ packages: dev: false name: '@rush-temp/typings-generator' resolution: - integrity: sha512-NAT3Xv0oy0P4+NDUceFMc9vlJ4O1C/JZkH5cEBmNS0iQQ3hAo+SO1SFkJ4ihTNMPBVd0DS5b7XGm5xgRODLxjA== + integrity: sha512-XDbicbj2x8mvxcjqTE/s1LWNky6u8FwiU6w8iPCreK8qHu9xc5lUGltErrxD3Jq7IY/OzqL23QfluKZs0qF2Kw== tarball: 'file:projects/typings-generator.tgz' version: 0.0.0 'file:projects/web-library-build-test.tgz': @@ -15395,7 +15395,7 @@ packages: dev: false name: '@rush-temp/web-library-build-test' resolution: - integrity: sha512-je59bh3sOKxZhpn5mFV8FTFi7HPqkmP9B847THbPQKYd5Hs6xjiVGIRHDxqAtffCt1ZloNn8ffwFeRQualPUeg== + integrity: sha512-xHQuFo8rVslpAgvxRrUeURmporLuqxx3sQLXuX1QGgxqdkKJJ2tX5nC9PoZQmN6SmdDcpR2QxEAe1Uq5t3YQfQ== tarball: 'file:projects/web-library-build-test.tgz' version: 0.0.0 'file:projects/web-library-build.tgz': @@ -15407,7 +15407,7 @@ packages: dev: false name: '@rush-temp/web-library-build' resolution: - integrity: sha512-AtGayKEU+vyg+dSs9x/lz/S6YcJHKk4ZA19sdyO8McgEMMpwn/aHOzrSKPRrdm8t7x3scUZgpIsVwYcEvZI/1g== + integrity: sha512-ySCvbIGDLrN/g2HLip529IhUvGuCjjshx5VAb9HAH4ORXHRo/xgRUdG6L/frAYDwp4Zoa2Hhx4x4CvjjRBl95g== tarball: 'file:projects/web-library-build.tgz' version: 0.0.0 registry: '' @@ -15531,7 +15531,7 @@ specifiers: '@types/orchestrator': 0.0.30 '@types/read-package-tree': 5.1.0 '@types/resolve': 1.17.1 - '@types/semver': ~7.2.0 + '@types/semver': ~7.3.1 '@types/serve-static': 1.13.1 '@types/sinon': 1.16.34 '@types/source-map': 0.5.0 @@ -15644,4 +15644,4 @@ specifiers: xmldoc: ~1.1.2 yargs: ~4.6.0 z-schema: ~3.18.3 -# shrinkwrap hash: f035df37bd55f6d14b9e0b7de37069024f5b4b23 +# shrinkwrap hash: 1156756a2cb99c2e5fa67b2956ad9e699f52234a diff --git a/core-build/gulp-core-build/package.json b/core-build/gulp-core-build/package.json index ad362dce01e..bd1f4c7ea6d 100644 --- a/core-build/gulp-core-build/package.json +++ b/core-build/gulp-core-build/package.json @@ -20,7 +20,7 @@ "@types/node": "10.17.13", "@types/node-notifier": "0.0.28", "@types/orchestrator": "0.0.30", - "@types/semver": "~7.2.0", + "@types/semver": "~7.3.1", "@types/through2": "2.0.32", "@types/vinyl": "2.0.3", "@types/yargs": "0.0.34", diff --git a/libraries/node-core-library/package.json b/libraries/node-core-library/package.json index 7adb4731570..02868f46474 100644 --- a/libraries/node-core-library/package.json +++ b/libraries/node-core-library/package.json @@ -27,7 +27,7 @@ "@types/fs-extra": "7.0.0", "@types/jest": "25.2.1", "@types/jju": "1.4.1", - "@types/semver": "~7.2.0", + "@types/semver": "~7.3.1", "@types/timsort": "0.3.0", "@types/z-schema": "3.16.31", "gulp": "~4.0.2" From 0e8d05afead69e759ef10c598e9bede63f6f8782 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Fri, 3 Jul 2020 02:06:20 -0700 Subject: [PATCH 33/33] Improve typesafety in PnpmfileShim. --- .../installManager/WorkspaceInstallManager.ts | 29 ++++++++++--------- .../src/logic/pnpm/IPnpmfileShimSettings.ts | 9 ++++++ apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts | 27 +++++++---------- 3 files changed, 34 insertions(+), 31 deletions(-) create mode 100644 apps/rush-lib/src/logic/pnpm/IPnpmfileShimSettings.ts diff --git a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts index f7d01c441ef..584c35c6c1a 100644 --- a/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts +++ b/apps/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -20,6 +20,7 @@ import { Utilities } from '../../utilities/Utilities'; import { InstallHelpers } from './InstallHelpers'; import { CommonVersionsConfiguration } from '../../api/CommonVersionsConfiguration'; import { RepoStateFile } from '../RepoStateFile'; +import { IPnpmfileShimSettings } from '../pnpm/IPnpmfileShimSettings'; /** * This class implements common logic between "rush install" and "rush update". @@ -434,21 +435,21 @@ export class WorkspaceInstallManager extends BaseInstallManager { } } + const pnpmfileShimSettings: IPnpmfileShimSettings = { + allPreferredVersions: MapExtensions.toObject( + InstallHelpers.collectPreferredVersions(this.rushConfiguration, this.options) + ), + allowedAlternativeVersions: MapExtensions.toObject( + this.rushConfiguration.getCommonVersions(this.options.variant).allowedAlternativeVersions + ), + semverPath: require.resolve('semver'), + useClientPnpmfile: pnpmfileExists + }; + // Write the settings to be consumed by the pnpmfile - await JsonFile.saveAsync( - { - allPreferredVersions: MapExtensions.toObject( - InstallHelpers.collectPreferredVersions(this.rushConfiguration, this.options) - ), - allowedAlternativeVersions: MapExtensions.toObject( - this.rushConfiguration.getCommonVersions(this.options.variant).allowedAlternativeVersions - ), - semverPath: require.resolve('semver'), - useClientPnpmfile: pnpmfileExists - }, - path.resolve(pnpmfileDir, 'pnpmfileSettings.json'), - { ensureFolderExists: true } - ); + await JsonFile.saveAsync(pnpmfileShimSettings, path.resolve(pnpmfileDir, 'pnpmfileSettings.json'), { + ensureFolderExists: true + }); // Copy the shim pnpmfile to the original path await FileSystem.copyFileAsync({ diff --git a/apps/rush-lib/src/logic/pnpm/IPnpmfileShimSettings.ts b/apps/rush-lib/src/logic/pnpm/IPnpmfileShimSettings.ts new file mode 100644 index 00000000000..d1f37be422e --- /dev/null +++ b/apps/rush-lib/src/logic/pnpm/IPnpmfileShimSettings.ts @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export interface IPnpmfileShimSettings { + allPreferredVersions: { [dependencyName: string]: string }; + allowedAlternativeVersions: { [dependencyName: string]: ReadonlyArray }; + semverPath: string; + useClientPnpmfile: boolean; +} diff --git a/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts b/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts index acf37d782b6..bd8cfe052c1 100644 --- a/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts +++ b/apps/rush-lib/src/logic/pnpm/PnpmfileShim.ts @@ -1,13 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -interface ILockfile {} +// Uncomment "/* type */" when we upgrade to TS 3.9 +import { /* type */ IPackageJson } from '@rushstack/node-core-library'; +import { /* type */ IPnpmfileShimSettings } from './IPnpmfileShimSettings'; +import /* type */ * as TSemver from 'semver'; -interface IPackageJson { - dependencies?: { [dependencyName: string]: string }; - devDependencies?: { [dependencyName: string]: string }; - optionalDependencies?: { [dependencyName: string]: string }; -} +interface ILockfile {} interface IPnpmfile { hooks?: { @@ -18,18 +17,10 @@ interface IPnpmfile { }; } -interface IPnpmfileSettings { - allPreferredVersions: { [dependencyName: string]: string }; - allowedAlternativeVersions: { [dependencyName: string]: string[] }; - semverPath: string; - useClientPnpmfile: boolean; -} - // Load in the generated settings file -const pnpmfileSettings: IPnpmfileSettings = require('./pnpmfileSettings.json'); +const pnpmfileSettings: IPnpmfileShimSettings = require('./pnpmfileSettings.json'); // We will require semver from this path on disk, since this is the version of semver shipping with Rush -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const semver: any = require(pnpmfileSettings.semverPath); +const semver: typeof TSemver = require(pnpmfileSettings.semverPath); // Only require the client pnpmfile if requested const clientPnpmfile: IPnpmfile | undefined = pnpmfileSettings.useClientPnpmfile ? require('./clientPnpmfile') @@ -44,7 +35,8 @@ function setPreferredVersions(dependencies?: { [dependencyName: string]: string const preferredVersion: string = pnpmfileSettings.allPreferredVersions[name]; const version: string = dependencies![name]; if (pnpmfileSettings.allowedAlternativeVersions.hasOwnProperty(name)) { - const allowedAlternatives: string[] | undefined = pnpmfileSettings.allowedAlternativeVersions[name]; + const allowedAlternatives: ReadonlyArray | undefined = + pnpmfileSettings.allowedAlternativeVersions[name]; if (allowedAlternatives && allowedAlternatives.indexOf(version) > -1) { continue; } @@ -55,6 +47,7 @@ function setPreferredVersions(dependencies?: { [dependencyName: string]: string } catch { // Swallow invalid range errors } + if (isValidRange && semver.subset(preferredVersion, version)) { dependencies![name] = preferredVersion; }