diff --git a/common/changes/@microsoft/rush/fix-dependencies-meta-custom-fields_2024-11-06-16-08.json b/common/changes/@microsoft/rush/fix-dependencies-meta-custom-fields_2024-11-06-16-08.json new file mode 100644 index 00000000000..ba0c4e08b02 --- /dev/null +++ b/common/changes/@microsoft/rush/fix-dependencies-meta-custom-fields_2024-11-06-16-08.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "Fix an issue where usage of custom fields in dependenciesMeta caused rush install to think that shrinkwrap file is outdated", + "type": "none" + } + ], + "packageName": "@microsoft/rush" +} \ No newline at end of file diff --git a/common/changes/@rushstack/node-core-library/fix-dependencies-meta-custom-fields_2024-11-15-00-04.json b/common/changes/@rushstack/node-core-library/fix-dependencies-meta-custom-fields_2024-11-15-00-04.json new file mode 100644 index 00000000000..8642c408ee6 --- /dev/null +++ b/common/changes/@rushstack/node-core-library/fix-dependencies-meta-custom-fields_2024-11-15-00-04.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/node-core-library", + "comment": "Extend IDependenciesMetaTable interface to support custom properties in \"dependenciesMeta\" entries", + "type": "minor" + } + ], + "packageName": "@rushstack/node-core-library" +} \ No newline at end of file diff --git a/common/reviews/api/node-core-library.api.md b/common/reviews/api/node-core-library.api.md index a11e5a042da..ba439c97ec1 100644 --- a/common/reviews/api/node-core-library.api.md +++ b/common/reviews/api/node-core-library.api.md @@ -244,6 +244,7 @@ export interface IDependenciesMetaTable { // (undocumented) [dependencyName: string]: { injected?: boolean; + [key: string]: unknown; }; } diff --git a/common/reviews/api/rush-lib.api.md b/common/reviews/api/rush-lib.api.md index 454ac3daa07..4a7d22ad640 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -684,6 +684,14 @@ export interface _IOperationStateJson { nonCachedDurationMs: number; } +// @public (undocumented) +export interface IPackageJsonDependencyMetaSourceData { + // (undocumented) + [key: string]: unknown; + // (undocumented) + injected?: boolean; +} + // @public export interface IPackageManagerOptionsJsonBase { environmentVariables?: IConfigurationEnvironment; @@ -1005,11 +1013,13 @@ export class PackageJsonDependency { // @public (undocumented) export class PackageJsonDependencyMeta { - constructor(name: string, injected: boolean, onChange: () => void); + constructor(name: string, sourceData: IPackageJsonDependencyMetaSourceData, onChange: () => void); // (undocumented) get injected(): boolean; // (undocumented) readonly name: string; + // (undocumented) + get sourceData(): IPackageJsonDependencyMetaSourceData; } // @public (undocumented) diff --git a/libraries/node-core-library/src/IPackageJson.ts b/libraries/node-core-library/src/IPackageJson.ts index 74d2c062439..9d0d0c51243 100644 --- a/libraries/node-core-library/src/IPackageJson.ts +++ b/libraries/node-core-library/src/IPackageJson.ts @@ -68,6 +68,7 @@ export interface IPeerDependenciesMetaTable { export interface IDependenciesMetaTable { [dependencyName: string]: { injected?: boolean; + [key: string]: unknown; }; } diff --git a/libraries/rush-lib/src/api/PackageJsonEditor.ts b/libraries/rush-lib/src/api/PackageJsonEditor.ts index 8212164169b..a4b3f2388b8 100644 --- a/libraries/rush-lib/src/api/PackageJsonEditor.ts +++ b/libraries/rush-lib/src/api/PackageJsonEditor.ts @@ -16,6 +16,14 @@ export enum DependencyType { YarnResolutions = 'resolutions' } +/** + * @public + */ +export interface IPackageJsonDependencyMetaSourceData { + injected?: boolean; + [key: string]: unknown; +} + /** * @public */ @@ -50,19 +58,23 @@ export class PackageJsonDependency { * @public */ export class PackageJsonDependencyMeta { - private _injected: boolean; + private _sourceData: IPackageJsonDependencyMetaSourceData; private _onChange: () => void; public readonly name: string; - public constructor(name: string, injected: boolean, onChange: () => void) { + public constructor(name: string, sourceData: IPackageJsonDependencyMetaSourceData, onChange: () => void) { this.name = name; - this._injected = injected; + this._sourceData = sourceData; this._onChange = onChange; } + public get sourceData(): IPackageJsonDependencyMetaSourceData { + return this._sourceData; + } + public get injected(): boolean { - return this._injected; + return this._sourceData.injected ?? false; } } @@ -107,7 +119,8 @@ export class PackageJsonEditor { const devDependencies: { [key: string]: string } = data.devDependencies || {}; const resolutions: { [key: string]: string } = data.resolutions || {}; - const dependenciesMeta: { [key: string]: { [key: string]: boolean } } = data.dependenciesMeta || {}; + const dependenciesMeta: { [key: string]: IPackageJsonDependencyMetaSourceData } = + data.dependenciesMeta || {}; const _onChange: () => void = this._onChange.bind(this); @@ -180,10 +193,10 @@ export class PackageJsonEditor { ); }); - Object.keys(dependenciesMeta || {}).forEach((packageName: string) => { + Object.entries(dependenciesMeta || {}).forEach(([packageName, dependencyMeta]: [string, IPackageJsonDependencyMetaSourceData]) => { this._dependenciesMeta.set( packageName, - new PackageJsonDependencyMeta(packageName, dependenciesMeta[packageName].injected, _onChange) + new PackageJsonDependencyMeta(packageName, dependencyMeta, _onChange) ); }); diff --git a/libraries/rush-lib/src/index.ts b/libraries/rush-lib/src/index.ts index e3c5e19c20e..7929e023956 100644 --- a/libraries/rush-lib/src/index.ts +++ b/libraries/rush-lib/src/index.ts @@ -86,6 +86,7 @@ export { PackageJsonEditor, PackageJsonDependency, DependencyType, + type IPackageJsonDependencyMetaSourceData, PackageJsonDependencyMeta } from './api/PackageJsonEditor'; diff --git a/libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts index 8308aef00c8..2f5fd7af367 100644 --- a/libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts +++ b/libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -325,9 +325,7 @@ export class WorkspaceInstallManager extends BaseInstallManager { if (dependencyMetaList.length !== 0) { const dependenciesMeta: IDependenciesMetaTable = {}; for (const dependencyMeta of dependencyMetaList) { - dependenciesMeta[dependencyMeta.name] = { - injected: dependencyMeta.injected - }; + dependenciesMeta[dependencyMeta.name] = dependencyMeta.sourceData; } // get the relative path from common temp folder to package folder, to align with the value in pnpm-lock.yaml diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts b/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts index 5801d1dc1cc..67a9c57b183 100644 --- a/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts +++ b/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts @@ -23,7 +23,12 @@ import type { IShrinkwrapFilePolicyValidatorOptions } from '../policy/Shrinkwrap import { PNPM_SHRINKWRAP_YAML_FORMAT } from './PnpmYamlCommon'; import { RushConstants } from '../RushConstants'; import type { IExperimentsJson } from '../../api/ExperimentsConfiguration'; -import { DependencyType, type PackageJsonDependency, PackageJsonEditor } from '../../api/PackageJsonEditor'; +import { + DependencyType, + type PackageJsonDependency, + type IPackageJsonDependencyMetaSourceData, + PackageJsonEditor +} from '../../api/PackageJsonEditor'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; import { PnpmfileConfiguration } from './PnpmfileConfiguration'; import { PnpmProjectShrinkwrapFile } from './PnpmProjectShrinkwrapFile'; @@ -32,15 +37,14 @@ import { PnpmOptionsConfiguration } from './PnpmOptionsConfiguration'; import type { IPnpmfile, IPnpmfileContext } from './IPnpmfile'; import type { Subspace } from '../../api/Subspace'; import { CustomTipId, type CustomTipsConfiguration } from '../../api/CustomTipsConfiguration'; +import { objectsAreDeepEqual } from '../../utilities/objectUtilities'; const yamlModule: typeof import('js-yaml') = Import.lazy('js-yaml', require); export interface IPeerDependenciesMetaYaml { optional?: boolean; } -export interface IDependenciesMetaYaml { - injected?: boolean; -} +export type IDependenciesMetaYaml = IPackageJsonDependencyMetaSourceData; export type IPnpmV7VersionSpecifier = string; export interface IPnpmV8VersionSpecifier { @@ -1040,8 +1044,8 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { } } - for (const { name, injected } of dependencyMetaList) { - if (importer.dependenciesMeta?.[name]?.injected === injected) { + for (const { name, sourceData } of dependencyMetaList) { + if (objectsAreDeepEqual(importer.dependenciesMeta?.[name], sourceData)) { importerDependenciesMeta.delete(name); } }