diff --git a/apps/lockfile-explorer/package.json b/apps/lockfile-explorer/package.json index 737f8b3da24..d4b73a0e37b 100644 --- a/apps/lockfile-explorer/package.json +++ b/apps/lockfile-explorer/package.json @@ -66,7 +66,7 @@ "js-yaml": "~3.13.1", "open": "~8.4.0", "update-notifier": "~5.1.0", - "@pnpm/dependency-path": "~2.1.2", + "@pnpm/dependency-path-lockfile-pre-v9": "npm:@pnpm/dependency-path@~2.1.2", "semver": "~7.5.4", "@rushstack/rush-sdk": "workspace:*", "@rushstack/ts-command-line": "workspace:*" diff --git a/apps/lockfile-explorer/src/utils/shrinkwrap.ts b/apps/lockfile-explorer/src/utils/shrinkwrap.ts index 3d96e44b4e2..8cb289fc1e6 100644 --- a/apps/lockfile-explorer/src/utils/shrinkwrap.ts +++ b/apps/lockfile-explorer/src/utils/shrinkwrap.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as dp from '@pnpm/dependency-path'; +import * as dependencyPathLockfilePreV9 from '@pnpm/dependency-path-lockfile-pre-v9'; interface IPackageInfo { name: string; @@ -12,7 +12,7 @@ interface IPackageInfo { export function convertLockfileV6DepPathToV5DepPath(newDepPath: string): string { if (!newDepPath.includes('@', 2) || newDepPath.startsWith('file:')) return newDepPath; const index = newDepPath.indexOf('@', newDepPath.indexOf('/@') + 2); - if (newDepPath.includes('(') && index > dp.indexOfPeersSuffix(newDepPath)) return newDepPath; + if (newDepPath.includes('(') && index > dependencyPathLockfilePreV9.indexOfPeersSuffix(newDepPath)) return newDepPath; return `${newDepPath.substring(0, index)}/${newDepPath.substring(index + 1)}`; } @@ -21,7 +21,7 @@ export function parseDependencyPath(shrinkwrapFileMajorVersion: number, newDepPa if (shrinkwrapFileMajorVersion === 6) { dependencyPath = convertLockfileV6DepPathToV5DepPath(newDepPath); } - const packageInfo = dp.parse(dependencyPath); + const packageInfo = dependencyPathLockfilePreV9.parse(dependencyPath); return { name: packageInfo.name as string, peersSuffix: packageInfo.peersSuffix, diff --git a/common/changes/@microsoft/rush/feature-support_pnpmv9_2024-11-19-08-24.json b/common/changes/@microsoft/rush/feature-support_pnpmv9_2024-11-19-08-24.json new file mode 100644 index 00000000000..d60cf92c6c7 --- /dev/null +++ b/common/changes/@microsoft/rush/feature-support_pnpmv9_2024-11-19-08-24.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "Support pnpm lockfile v9, which is used by default starting in pnpm v9.", + "type": "none" + } + ], + "packageName": "@microsoft/rush" +} \ No newline at end of file diff --git a/common/changes/@rushstack/lockfile-explorer/feature-support_pnpmv9_2024-11-25-14-05.json b/common/changes/@rushstack/lockfile-explorer/feature-support_pnpmv9_2024-11-25-14-05.json new file mode 100644 index 00000000000..c82dd943edb --- /dev/null +++ b/common/changes/@rushstack/lockfile-explorer/feature-support_pnpmv9_2024-11-25-14-05.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/lockfile-explorer", + "comment": "", + "type": "" + } + ], + "packageName": "@rushstack/lockfile-explorer" +} \ No newline at end of file diff --git a/common/config/rush/nonbrowser-approved-packages.json b/common/config/rush/nonbrowser-approved-packages.json index 95b79496bec..d8ec0db6258 100644 --- a/common/config/rush/nonbrowser-approved-packages.json +++ b/common/config/rush/nonbrowser-approved-packages.json @@ -102,6 +102,10 @@ "name": "@pnpm/logger", "allowedCategories": [ "libraries" ] }, + { + "name": "@pnpm/lockfile.types", + "allowedCategories": [ "libraries" ] + }, { "name": "@redis/client", "allowedCategories": [ "libraries" ] diff --git a/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml b/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml index bb93c9f3ee9..828ff1e2b66 100644 --- a/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml +++ b/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml @@ -126,10 +126,10 @@ importers: version: file:../../../apps/heft(@types/node@18.17.15) '@rushstack/heft-lint-plugin': specifier: file:../../heft-plugins/heft-lint-plugin - version: file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.68.7)(@types/node@18.17.15) + version: file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.68.8)(@types/node@18.17.15) '@rushstack/heft-typescript-plugin': specifier: file:../../heft-plugins/heft-typescript-plugin - version: file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.68.7)(@types/node@18.17.15) + version: file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.68.8)(@types/node@18.17.15) eslint: specifier: ~8.57.0 version: 8.57.0 @@ -889,6 +889,17 @@ packages: dependencies: rfc4648: 1.5.3 + /@pnpm/crypto.base32-hash@3.0.1: + resolution: {integrity: sha512-DM4RR/tvB7tMb2FekL0Q97A5PCXNyEC+6ht8SaufAUFSJNxeozqHw9PHTZR03mzjziPzNQLOld0pNINBX3srtw==} + engines: {node: '>=18.12'} + dependencies: + '@pnpm/crypto.polyfill': 1.0.0 + rfc4648: 1.5.3 + + /@pnpm/crypto.polyfill@1.0.0: + resolution: {integrity: sha512-WbmsqqcUXKKaAF77ox1TQbpZiaQcr26myuMUu+WjUtoWYgD3VP6iKYEvSx35SZ6G2L316lu+pv+40A2GbWJc1w==} + engines: {node: '>=18.12'} + /@pnpm/dependency-path@2.1.8: resolution: {integrity: sha512-ywBaTjy0iSEF7lH3DlF8UXrdL2bw4AQFV2tTOeNeY7wc1W5CE+RHSJhf9MXBYcZPesqGRrPiU7Pimj3l05L9VA==} engines: {node: '>=16.14'} @@ -896,7 +907,15 @@ packages: '@pnpm/crypto.base32-hash': 2.0.0 '@pnpm/types': 9.4.2 encode-registry: 3.0.1 - semver: 7.5.4 + semver: 7.6.2 + + /@pnpm/dependency-path@5.1.7: + resolution: {integrity: sha512-MKCyaTy1r9fhBXAnhDZNBVgo6ThPnicwJEG203FDp7pGhD7NruS/FhBI+uMd7GNsK3D7aIFCDAgbWpNTXn/eWw==} + engines: {node: '>=18.12'} + dependencies: + '@pnpm/crypto.base32-hash': 3.0.1 + '@pnpm/types': 12.2.0 + semver: 7.6.2 /@pnpm/error@1.4.0: resolution: {integrity: sha512-vxkRrkneBPVmP23kyjnYwVOtipwlSl6UfL+h+Xa3TrABJTz5rYBXemlTsU5BzST8U4pD7YDkTb3SQu+MMuIDKA==} @@ -920,6 +939,14 @@ packages: p-settle: 4.1.1 ramda: 0.27.2 + /@pnpm/lockfile.types@1.0.3: + resolution: {integrity: sha512-A7vUWktnhDkrIs+WmXm7AdffJVyVYJpQUEouya/DYhB+Y+tQ3BXjZ6CV0KybqLgI/8AZErgCJqFxA0GJH6QDjA==} + engines: {node: '>=18.12'} + dependencies: + '@pnpm/patching.types': 1.0.0 + '@pnpm/types': 12.2.0 + dev: false + /@pnpm/package-bins@4.1.0: resolution: {integrity: sha512-57/ioGYLBbVRR80Ux9/q2i3y8Q+uQADc3c+Yse8jr/60YLOi3jcWz13e2Jy+ANYtZI258Qc5wk2X077rp0Ly/Q==} engines: {node: '>=10.16'} @@ -928,6 +955,11 @@ packages: fast-glob: 3.3.2 is-subdir: 1.2.0 + /@pnpm/patching.types@1.0.0: + resolution: {integrity: sha512-juCdQCC1USqLcOhVPl1tYReoTO9YH4fTullMnFXXcmpsDM7Dkn3tzuOQKC3oPoJ2ozv+0EeWWMtMGqn2+IM3pQ==} + engines: {node: '>=18.12'} + dev: false + /@pnpm/read-modules-dir@2.0.3: resolution: {integrity: sha512-i9OgRvSlxrTS9a2oXokhDxvQzDtfqtsooJ9jaGoHkznue5aFCTSrNZFQ6M18o8hC03QWfnxaKi0BtOvNkKu2+A==} engines: {node: '>=10.13'} @@ -960,6 +992,10 @@ packages: sort-keys: 4.2.0 strip-bom: 4.0.0 + /@pnpm/types@12.2.0: + resolution: {integrity: sha512-5RtwWhX39j89/Tmyv2QSlpiNjErA357T/8r1Dkg+2lD3P7RuS7Xi2tChvmOC3VlezEFNcWnEGCOeKoGRkDuqFA==} + engines: {node: '>=18.12'} + /@pnpm/types@6.4.0: resolution: {integrity: sha512-nco4+4sZqNHn60Y4VE/fbtlShCBqipyUO+nKRPvDHqLrecMW9pzHWMVRxk4nrMRoeowj3q0rX3GYRBa8lsHTAg==} engines: {node: '>=10.16'} @@ -5271,7 +5307,6 @@ packages: resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} engines: {node: '>=10'} hasBin: true - dev: true /set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} @@ -6265,7 +6300,7 @@ packages: - typescript dev: true - file:../../../heft-plugins/heft-api-extractor-plugin(@rushstack/heft@0.68.7)(@types/node@18.17.15): + file:../../../heft-plugins/heft-api-extractor-plugin(@rushstack/heft@0.68.8)(@types/node@18.17.15): resolution: {directory: ../../../heft-plugins/heft-api-extractor-plugin, type: directory} id: file:../../../heft-plugins/heft-api-extractor-plugin name: '@rushstack/heft-api-extractor-plugin' @@ -6280,7 +6315,7 @@ packages: - '@types/node' dev: true - file:../../../heft-plugins/heft-jest-plugin(@rushstack/heft@0.68.7)(@types/node@18.17.15)(jest-environment-node@29.5.0): + file:../../../heft-plugins/heft-jest-plugin(@rushstack/heft@0.68.8)(@types/node@18.17.15)(jest-environment-node@29.5.0): resolution: {directory: ../../../heft-plugins/heft-jest-plugin, type: directory} id: file:../../../heft-plugins/heft-jest-plugin name: '@rushstack/heft-jest-plugin' @@ -6314,7 +6349,7 @@ packages: - ts-node dev: true - file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.68.7)(@types/node@18.17.15): + file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.68.8)(@types/node@18.17.15): resolution: {directory: ../../../heft-plugins/heft-lint-plugin, type: directory} id: file:../../../heft-plugins/heft-lint-plugin name: '@rushstack/heft-lint-plugin' @@ -6328,7 +6363,7 @@ packages: - '@types/node' dev: true - file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.68.7)(@types/node@18.17.15): + file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.68.8)(@types/node@18.17.15): resolution: {directory: ../../../heft-plugins/heft-typescript-plugin, type: directory} id: file:../../../heft-plugins/heft-typescript-plugin name: '@rushstack/heft-typescript-plugin' @@ -6456,7 +6491,9 @@ packages: name: '@microsoft/rush-lib' engines: {node: '>=5.6.0'} dependencies: - '@pnpm/dependency-path': 2.1.8 + '@pnpm/dependency-path': 5.1.7 + '@pnpm/dependency-path-lockfile-pre-v9': /@pnpm/dependency-path@2.1.8 + '@pnpm/dependency-path-pre-v9': /@pnpm/dependency-path@2.1.8 '@pnpm/link-bins': 5.3.25 '@rushstack/heft-config-file': file:../../../libraries/heft-config-file(@types/node@18.17.15) '@rushstack/lookup-by-path': file:../../../libraries/lookup-by-path(@types/node@18.17.15) @@ -6503,6 +6540,7 @@ packages: id: file:../../../libraries/rush-sdk name: '@rushstack/rush-sdk' dependencies: + '@pnpm/lockfile.types': 1.0.3 '@rushstack/lookup-by-path': file:../../../libraries/lookup-by-path(@types/node@18.17.15) '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) '@rushstack/package-deps-hash': file:../../../libraries/package-deps-hash(@types/node@18.17.15) @@ -6554,7 +6592,7 @@ packages: transitivePeerDependencies: - '@types/node' - file:../../../rigs/heft-node-rig(@rushstack/heft@0.68.7)(@types/node@18.17.15): + file:../../../rigs/heft-node-rig(@rushstack/heft@0.68.8)(@types/node@18.17.15): resolution: {directory: ../../../rigs/heft-node-rig, type: directory} id: file:../../../rigs/heft-node-rig name: '@rushstack/heft-node-rig' @@ -6564,10 +6602,10 @@ packages: '@microsoft/api-extractor': file:../../../apps/api-extractor(@types/node@18.17.15) '@rushstack/eslint-config': file:../../../eslint/eslint-config(eslint@8.57.0)(typescript@5.4.5) '@rushstack/heft': file:../../../apps/heft(@types/node@18.17.15) - '@rushstack/heft-api-extractor-plugin': file:../../../heft-plugins/heft-api-extractor-plugin(@rushstack/heft@0.68.7)(@types/node@18.17.15) - '@rushstack/heft-jest-plugin': file:../../../heft-plugins/heft-jest-plugin(@rushstack/heft@0.68.7)(@types/node@18.17.15)(jest-environment-node@29.5.0) - '@rushstack/heft-lint-plugin': file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.68.7)(@types/node@18.17.15) - '@rushstack/heft-typescript-plugin': file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.68.7)(@types/node@18.17.15) + '@rushstack/heft-api-extractor-plugin': file:../../../heft-plugins/heft-api-extractor-plugin(@rushstack/heft@0.68.8)(@types/node@18.17.15) + '@rushstack/heft-jest-plugin': file:../../../heft-plugins/heft-jest-plugin(@rushstack/heft@0.68.8)(@types/node@18.17.15)(jest-environment-node@29.5.0) + '@rushstack/heft-lint-plugin': file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.68.8)(@types/node@18.17.15) + '@rushstack/heft-typescript-plugin': file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.68.8)(@types/node@18.17.15) '@types/heft-jest': 1.0.1 eslint: 8.57.0 jest-environment-node: 29.5.0 @@ -6587,7 +6625,7 @@ packages: dependencies: '@microsoft/api-extractor': file:../../../apps/api-extractor(@types/node@18.17.15) '@rushstack/heft': file:../../../apps/heft(@types/node@18.17.15) - '@rushstack/heft-node-rig': file:../../../rigs/heft-node-rig(@rushstack/heft@0.68.7)(@types/node@18.17.15) + '@rushstack/heft-node-rig': file:../../../rigs/heft-node-rig(@rushstack/heft@0.68.8)(@types/node@18.17.15) '@types/heft-jest': 1.0.1 '@types/node': 18.17.15 eslint: 8.57.0 diff --git a/common/config/subspaces/build-tests-subspace/repo-state.json b/common/config/subspaces/build-tests-subspace/repo-state.json index 7d67383645c..125abc7d040 100644 --- a/common/config/subspaces/build-tests-subspace/repo-state.json +++ b/common/config/subspaces/build-tests-subspace/repo-state.json @@ -1,6 +1,6 @@ // DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. { - "pnpmShrinkwrapHash": "0f47782f3b6360aa0f60fe19db3d1a0b4ce4f50b", + "pnpmShrinkwrapHash": "77dc2b5589007427c922dc7e49a2617ab00b1075", "preferredVersionsHash": "ce857ea0536b894ec8f346aaea08cfd85a5af648", - "packageJsonInjectedDependenciesHash": "005dd07c7693259c12de49ac20abda7c14ee0c26" + "packageJsonInjectedDependenciesHash": "8271db192b58e2d0b5f0645a9d04594c81b91410" } diff --git a/common/config/subspaces/default/pnpm-lock.yaml b/common/config/subspaces/default/pnpm-lock.yaml index cbcb488fca5..4df64753556 100644 --- a/common/config/subspaces/default/pnpm-lock.yaml +++ b/common/config/subspaces/default/pnpm-lock.yaml @@ -189,9 +189,9 @@ importers: '@microsoft/rush-lib': specifier: workspace:* version: link:../../libraries/rush-lib - '@pnpm/dependency-path': - specifier: ~2.1.2 - version: 2.1.8 + '@pnpm/dependency-path-lockfile-pre-v9': + specifier: npm:@pnpm/dependency-path@~2.1.2 + version: /@pnpm/dependency-path@2.1.8 '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library @@ -3331,8 +3331,11 @@ importers: ../../../libraries/rush-lib: dependencies: '@pnpm/dependency-path': - specifier: ~2.1.2 - version: 2.1.8 + specifier: ~5.1.7 + version: 5.1.7 + '@pnpm/dependency-path-lockfile-pre-v9': + specifier: npm:@pnpm/dependency-path@~2.1.2 + version: /@pnpm/dependency-path@2.1.8 '@pnpm/link-bins': specifier: ~5.3.7 version: 5.3.25 @@ -3442,6 +3445,9 @@ importers: specifier: ~8.3.2 version: 8.3.2 devDependencies: + '@pnpm/lockfile.types': + specifier: ~1.0.3 + version: 1.0.3 '@pnpm/logger': specifier: 4.0.0 version: 4.0.0 @@ -3502,6 +3508,9 @@ importers: ../../../libraries/rush-sdk: dependencies: + '@pnpm/lockfile.types': + specifier: ~1.0.3 + version: 1.0.3 '@rushstack/lookup-by-path': specifier: workspace:* version: link:../lookup-by-path @@ -9735,6 +9744,19 @@ packages: rfc4648: 1.5.3 dev: false + /@pnpm/crypto.base32-hash@3.0.1: + resolution: {integrity: sha512-DM4RR/tvB7tMb2FekL0Q97A5PCXNyEC+6ht8SaufAUFSJNxeozqHw9PHTZR03mzjziPzNQLOld0pNINBX3srtw==} + engines: {node: '>=18.12'} + dependencies: + '@pnpm/crypto.polyfill': 1.0.0 + rfc4648: 1.5.3 + dev: false + + /@pnpm/crypto.polyfill@1.0.0: + resolution: {integrity: sha512-WbmsqqcUXKKaAF77ox1TQbpZiaQcr26myuMUu+WjUtoWYgD3VP6iKYEvSx35SZ6G2L316lu+pv+40A2GbWJc1w==} + engines: {node: '>=18.12'} + dev: false + /@pnpm/dependency-path@2.1.8: resolution: {integrity: sha512-ywBaTjy0iSEF7lH3DlF8UXrdL2bw4AQFV2tTOeNeY7wc1W5CE+RHSJhf9MXBYcZPesqGRrPiU7Pimj3l05L9VA==} engines: {node: '>=16.14'} @@ -9745,6 +9767,15 @@ packages: semver: 7.5.4 dev: false + /@pnpm/dependency-path@5.1.7: + resolution: {integrity: sha512-MKCyaTy1r9fhBXAnhDZNBVgo6ThPnicwJEG203FDp7pGhD7NruS/FhBI+uMd7GNsK3D7aIFCDAgbWpNTXn/eWw==} + engines: {node: '>=18.12'} + dependencies: + '@pnpm/crypto.base32-hash': 3.0.1 + '@pnpm/types': 12.2.0 + semver: 7.6.3 + dev: false + /@pnpm/error@1.4.0: resolution: {integrity: sha512-vxkRrkneBPVmP23kyjnYwVOtipwlSl6UfL+h+Xa3TrABJTz5rYBXemlTsU5BzST8U4pD7YDkTb3SQu+MMuIDKA==} engines: {node: '>=10.16'} @@ -9776,6 +9807,13 @@ packages: '@pnpm/types': 9.4.2 dev: true + /@pnpm/lockfile.types@1.0.3: + resolution: {integrity: sha512-A7vUWktnhDkrIs+WmXm7AdffJVyVYJpQUEouya/DYhB+Y+tQ3BXjZ6CV0KybqLgI/8AZErgCJqFxA0GJH6QDjA==} + engines: {node: '>=18.12'} + dependencies: + '@pnpm/patching.types': 1.0.0 + '@pnpm/types': 12.2.0 + /@pnpm/logger@4.0.0: resolution: {integrity: sha512-SIShw+k556e7S7tLZFVSIHjCdiVog1qWzcKW2RbLEHPItdisAFVNIe34kYd9fMSswTlSRLS/qRjw3ZblzWmJ9Q==} engines: {node: '>=12.17'} @@ -9793,6 +9831,10 @@ packages: is-subdir: 1.2.0 dev: false + /@pnpm/patching.types@1.0.0: + resolution: {integrity: sha512-juCdQCC1USqLcOhVPl1tYReoTO9YH4fTullMnFXXcmpsDM7Dkn3tzuOQKC3oPoJ2ozv+0EeWWMtMGqn2+IM3pQ==} + engines: {node: '>=18.12'} + /@pnpm/read-modules-dir@2.0.3: resolution: {integrity: sha512-i9OgRvSlxrTS9a2oXokhDxvQzDtfqtsooJ9jaGoHkznue5aFCTSrNZFQ6M18o8hC03QWfnxaKi0BtOvNkKu2+A==} engines: {node: '>=10.13'} @@ -9828,6 +9870,10 @@ packages: strip-bom: 4.0.0 dev: false + /@pnpm/types@12.2.0: + resolution: {integrity: sha512-5RtwWhX39j89/Tmyv2QSlpiNjErA357T/8r1Dkg+2lD3P7RuS7Xi2tChvmOC3VlezEFNcWnEGCOeKoGRkDuqFA==} + engines: {node: '>=18.12'} + /@pnpm/types@6.4.0: resolution: {integrity: sha512-nco4+4sZqNHn60Y4VE/fbtlShCBqipyUO+nKRPvDHqLrecMW9pzHWMVRxk4nrMRoeowj3q0rX3GYRBa8lsHTAg==} engines: {node: '>=10.16'} diff --git a/common/config/subspaces/default/repo-state.json b/common/config/subspaces/default/repo-state.json index 23b370c9255..ad71d9b48fd 100644 --- a/common/config/subspaces/default/repo-state.json +++ b/common/config/subspaces/default/repo-state.json @@ -1,5 +1,5 @@ // DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. { - "pnpmShrinkwrapHash": "42f4667a7609b88a8a9a9b87c73c9c806a2071b9", + "pnpmShrinkwrapHash": "c7b3cd82826da4f30f8a13538d7c3eb501949160", "preferredVersionsHash": "ce857ea0536b894ec8f346aaea08cfd85a5af648" } diff --git a/libraries/rush-lib/package.json b/libraries/rush-lib/package.json index 9a00db38b85..bfd07e17b90 100644 --- a/libraries/rush-lib/package.json +++ b/libraries/rush-lib/package.json @@ -29,7 +29,8 @@ }, "license": "MIT", "dependencies": { - "@pnpm/dependency-path": "~2.1.2", + "@pnpm/dependency-path-lockfile-pre-v9": "npm:@pnpm/dependency-path@~2.1.2", + "@pnpm/dependency-path": "~5.1.7", "@pnpm/link-bins": "~5.3.7", "@rushstack/heft-config-file": "workspace:*", "@rushstack/lookup-by-path": "workspace:*", @@ -68,6 +69,7 @@ "pnpm-sync-lib": "0.2.9" }, "devDependencies": { + "@pnpm/lockfile.types": "~1.0.3", "@pnpm/logger": "4.0.0", "local-node-rig": "workspace:*", "@rushstack/heft-webpack5-plugin": "workspace:*", diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmLinkManager.ts b/libraries/rush-lib/src/logic/pnpm/PnpmLinkManager.ts index 3b627490037..01d477f0c64 100644 --- a/libraries/rush-lib/src/logic/pnpm/PnpmLinkManager.ts +++ b/libraries/rush-lib/src/logic/pnpm/PnpmLinkManager.ts @@ -320,7 +320,7 @@ export class PnpmLinkManager extends BaseLinkManager { RushConstants.nodeModulesFolderName ); } else if (this._pnpmVersion.major >= 8) { - const { depPathToFilename } = await import('@pnpm/dependency-path'); + const { depPathToFilename } = await import('@pnpm/dependency-path-lockfile-pre-v9'); // PNPM 8 changed the local path format again and the hashing algorithm, and // is now using the scoped '@pnpm/dependency-path' package // See https://github.com/pnpm/pnpm/releases/tag/v8.0.0 diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmShrinkWrapFileConverters.ts b/libraries/rush-lib/src/logic/pnpm/PnpmShrinkWrapFileConverters.ts new file mode 100644 index 00000000000..236afa90610 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/PnpmShrinkWrapFileConverters.ts @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Fork https://github.com/pnpm/pnpm/blob/main/lockfile/fs/src/lockfileFormatConverters.ts + * + * Pnpm lockfile v9 have some breaking changes on the lockfile format. For Example, the "packages" field has been split into "packages" and "snapshots" two parts. + * Rush should not parse the lockfile by itself, but should rely on pnpm to parse the lockfile. + * To ensure consistency with pnpm's parsing logic, I copied the relevant logic from @pnpm/lockfile.fs to this file. + * + * There are some reasons for copying the relevant logic instead of depending on @pnpm/lockfile.fs directly: + * 1. @pnpm/lockfile.fs has a exports filed in package.json, which will cause convertLockfileV9ToLockfileObject cannot be imported directly. + * 2. @pnpm/lockfile.fs only provides asynchronous read methods, while rush requires synchronous reading of the lockfile file. + * Perhaps this file will be deleted in the future and instead depend on @pnpm/lockfile.fs directly. + */ +import { removeSuffix } from '@pnpm/dependency-path'; +import type { + InlineSpecifiersProjectSnapshot, + InlineSpecifiersResolvedDependencies, + Lockfile, + LockfileFile, + LockfileFileV9, + PackageSnapshots, + ProjectSnapshot, + ResolvedDependencies +} from '@pnpm/lockfile.types'; + +type DepPath = string & { __brand: 'DepPath' }; +// eslint-disable-next-line @typescript-eslint/typedef +const DEPENDENCIES_FIELDS = ['optionalDependencies', 'dependencies', 'devDependencies'] as const; + +function revertProjectSnapshot(from: InlineSpecifiersProjectSnapshot): ProjectSnapshot { + const specifiers: ResolvedDependencies = {}; + + function moveSpecifiers(fromDep: InlineSpecifiersResolvedDependencies): ResolvedDependencies { + const resolvedDependencies: ResolvedDependencies = {}; + for (const [depName, { specifier, version }] of Object.entries(fromDep)) { + const existingValue: string = specifiers[depName]; + if (existingValue != null && existingValue !== specifier) { + throw new Error( + `Project snapshot lists the same dependency more than once with conflicting versions: ${depName}` + ); + } + + specifiers[depName] = specifier; + resolvedDependencies[depName] = version; + } + return resolvedDependencies; + } + + const dependencies: ResolvedDependencies | undefined = + from.dependencies == null ? from.dependencies : moveSpecifiers(from.dependencies); + const devDependencies: ResolvedDependencies | undefined = + from.devDependencies == null ? from.devDependencies : moveSpecifiers(from.devDependencies); + const optionalDependencies: ResolvedDependencies | undefined = + from.optionalDependencies == null ? from.optionalDependencies : moveSpecifiers(from.optionalDependencies); + + return { + ...from, + specifiers, + dependencies, + devDependencies, + optionalDependencies + }; +} + +function convertFromLockfileFileMutable(lockfileFile: LockfileFile): LockfileFileV9 { + if (typeof lockfileFile?.importers === 'undefined') { + lockfileFile.importers = { + '.': { + dependenciesMeta: lockfileFile.dependenciesMeta, + publishDirectory: lockfileFile.publishDirectory + } + }; + for (const depType of DEPENDENCIES_FIELDS) { + if (lockfileFile[depType] != null) { + lockfileFile.importers['.'][depType] = lockfileFile[depType]; + delete lockfileFile[depType]; + } + } + } + return lockfileFile as LockfileFileV9; +} + +function mapValues(obj: Record, mapper: (val: T, key: string) => U): Record { + const result: Record = {}; + for (const [key, value] of Object.entries(obj)) { + result[key] = mapper(value, key); + } + return result; +} + +/** + * Convert lockfile v9 object to standard lockfile object. + * + * This function will mutate the lockfile object. It will: + * 1. Ensure importers['.'] exists. + * 2. Merge snapshots and packages into packages. + * 3. Extract specifier from importers['xxx'] into the specifiers field. + */ +export function convertLockfileV9ToLockfileObject(lockfile: LockfileFileV9): Lockfile { + const { importers, ...rest } = convertFromLockfileFileMutable(lockfile); + + const packages: PackageSnapshots = {}; + for (const [depPath, pkg] of Object.entries(lockfile.snapshots ?? {})) { + const pkgId: string = removeSuffix(depPath); + packages[depPath as DepPath] = Object.assign(pkg, lockfile.packages?.[pkgId]); + } + return { + ...rest, + packages, + importers: mapValues(importers ?? {}, revertProjectSnapshot) + }; +} diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts b/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts index 5801d1dc1cc..d49961899bf 100644 --- a/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts +++ b/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts @@ -14,6 +14,7 @@ import { InternalError } from '@rushstack/node-core-library'; import { Colorize, type ITerminal } from '@rushstack/terminal'; +import * as dependencyPathLockfilePreV9 from '@pnpm/dependency-path-lockfile-pre-v9'; import * as dependencyPath from '@pnpm/dependency-path'; import { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; @@ -32,9 +33,22 @@ import { PnpmOptionsConfiguration } from './PnpmOptionsConfiguration'; import type { IPnpmfile, IPnpmfileContext } from './IPnpmfile'; import type { Subspace } from '../../api/Subspace'; import { CustomTipId, type CustomTipsConfiguration } from '../../api/CustomTipsConfiguration'; +import type { + ProjectId, + Lockfile, + PackageSnapshot, + ProjectSnapshot, + LockfileFileV9 +} from '@pnpm/lockfile.types'; +import { convertLockfileV9ToLockfileObject } from './PnpmShrinkWrapFileConverters'; const yamlModule: typeof import('js-yaml') = Import.lazy('js-yaml', require); +export enum ShrinkwrapFileMajorVersion { + V6 = 6, + V9 = 9 +} + export interface IPeerDependenciesMetaYaml { optional?: boolean; } @@ -47,11 +61,14 @@ export interface IPnpmV8VersionSpecifier { version: string; specifier: string; } -export type IPnpmVersionSpecifier = IPnpmV7VersionSpecifier | IPnpmV8VersionSpecifier; - -export interface IPnpmShrinkwrapDependencyYaml { - /** Information about the resolved package */ - resolution?: { +export type IPnpmV9VersionSpecifier = string; +export type IPnpmVersionSpecifier = + | IPnpmV7VersionSpecifier + | IPnpmV8VersionSpecifier + | IPnpmV9VersionSpecifier; + +export interface IPnpmShrinkwrapDependencyYaml extends Omit { + resolution: { /** The directory this package should clone, for injected dependencies */ directory?: string; /** The hash of the tarball, to ensure archive integrity */ @@ -59,103 +76,110 @@ export interface IPnpmShrinkwrapDependencyYaml { /** The name of the tarball, if this was from a TGZ file */ tarball?: string; }; - /** The list of bundled dependencies in this package */ - bundledDependencies?: ReadonlyArray; - /** The list of dependencies and the resolved version */ - dependencies?: Record; - /** The list of optional dependencies and the resolved version */ - optionalDependencies?: Record; - /** The list of peer dependencies and the resolved version */ - peerDependencies?: Record; - /** - * Used to indicate optional peer dependencies, as described in this RFC: - * https://github.com/yarnpkg/rfcs/blob/master/accepted/0000-optional-peer-dependencies.md - */ - peerDependenciesMeta?: Record; - /** The name of the package, if the package is a local tarball */ - name?: string; - /** If this is an optional dependency */ - optional?: boolean; - /** The values of process.platform supported by this package */ - os?: readonly string[]; - /** The values of process.arch supported by this package */ - cpu?: readonly string[]; - /** The libc runtimes supported by this package */ - libc?: readonly string[]; } -export interface IPnpmShrinkwrapImporterYaml { - /** The list of resolved version numbers for direct dependencies */ - dependencies?: Record; - /** The list of resolved version numbers for dev dependencies */ - devDependencies?: Record; - /** The list of resolved version numbers for optional dependencies */ - optionalDependencies?: Record; - /** The list of metadata for dependencies declared inside dependencies, optionalDependencies, and devDependencies. */ - dependenciesMeta?: Record; +export type IPnpmShrinkwrapImporterYaml = ProjectSnapshot; + +export interface IPnpmShrinkwrapYaml extends Lockfile { /** - * The list of specifiers used to resolve dependency versions - * - * @remarks - * This has been removed in PNPM v8 + * This interface represents the raw pnpm-lock.YAML file + * Example: + * { + * "dependencies": { + * "@rush-temp/project1": "file:./projects/project1.tgz" + * }, + * "packages": { + * "file:projects/library1.tgz": { + * "dependencies: { + * "markdown": "0.5.0" + * }, + * "name": "@rush-temp/library1", + * "resolution": { + * "tarball": "file:projects/library1.tgz" + * }, + * "version": "0.0.0" + * }, + * "markdown/0.5.0": { + * "resolution": { + * "integrity": "sha1-KCBbVlqK51kt4gdGPWY33BgnIrI=" + * } + * } + * }, + * "registry": "http://localhost:4873/", + * "shrinkwrapVersion": 3, + * "specifiers": { + * "@rush-temp/project1": "file:./projects/project1.tgz" + * } + * } */ - specifiers?: Record; -} - -/** - * This interface represents the raw pnpm-lock.YAML file - * Example: - * { - * "dependencies": { - * "@rush-temp/project1": "file:./projects/project1.tgz" - * }, - * "packages": { - * "file:projects/library1.tgz": { - * "dependencies: { - * "markdown": "0.5.0" - * }, - * "name": "@rush-temp/library1", - * "resolution": { - * "tarball": "file:projects/library1.tgz" - * }, - * "version": "0.0.0" - * }, - * "markdown/0.5.0": { - * "resolution": { - * "integrity": "sha1-KCBbVlqK51kt4gdGPWY33BgnIrI=" - * } - * } - * }, - * "registry": "http://localhost:4873/", - * "shrinkwrapVersion": 3, - * "specifiers": { - * "@rush-temp/project1": "file:./projects/project1.tgz" - * } - * } - */ -export interface IPnpmShrinkwrapYaml { - /** The version of the lockfile format */ - lockfileVersion?: string | number; /** The list of resolved version numbers for direct dependencies */ - dependencies: Record; - /** The list of importers for local workspace projects */ - importers: Record; - /** The description of the solved graph */ - packages: Record; - /** URL of the registry which was used */ - registry: string; + dependencies?: Record; /** The list of specifiers used to resolve direct dependency versions */ - specifiers: Record; - /** The list of override version number for dependencies */ - overrides?: { [dependency: string]: string }; - /** The checksum of package extensions fields for extending dependencies */ - packageExtensionsChecksum?: string; + specifiers?: Record; + /** URL of the registry which was used */ + registry?: string; } export interface ILoadFromFileOptions { withCaching?: boolean; } +export function parsePnpm9DependencyKey( + dependencyName: string, + versionSpecifier: IPnpmVersionSpecifier +): DependencySpecifier | undefined { + if (!versionSpecifier) { + return undefined; + } + + const dependencyKey: string = normalizePnpmVersionSpecifier(versionSpecifier); + + // Example: file:projects/project2 + // Example: project-2@file:projects/project2 + // Example: link:../projects/project1 + if (/(file|link):/.test(dependencyKey)) { + // If it starts with an NPM scheme such as "file:projects/my-app.tgz", we don't support that + return undefined; + } + + const { peersIndex } = dependencyPath.indexOfPeersSuffix(dependencyKey); + if (peersIndex !== -1) { + // Remove peer suffix + const key: string = dependencyKey.slice(0, peersIndex); + + // Example: 7.26.0 + if (semver.valid(key)) { + return new DependencySpecifier(dependencyName, key); + } + } + + // Example: @babel/preset-env@7.26.0 -> name=@babel/preset-env version=7.26.0 + // Example: @babel/preset-env@7.26.0(peer@1.2.3) -> name=@babel/preset-env version=7.26.0 + // Example: https://github.com/jonschlinkert/pad-left/tarball/2.1.0 -> name=undefined version=undefined + // Example: pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0 -> name=pad-left nonSemverVersion=https://xxxx + // Example: pad-left@https://codeload.github.com/jonschlinkert/pad-left/tar.gz/7798d648225aa5 -> name=pad-left nonSemverVersion=https://xxxx + const dependency: dependencyPath.DependencyPath = dependencyPath.parse(dependencyKey); + + const name: string = dependency.name ?? dependencyName; + const version: string = dependency.version ?? dependency.nonSemverVersion ?? dependencyKey; + + // Example: https://xxxx/pad-left/tarball/2.1.0 + // Example: https://github.com/jonschlinkert/pad-left/tarball/2.1.0 + // Example: https://codeload.github.com/jonschlinkert/pad-left/tar.gz/7798d648225aa5d879660a37c408ab4675b65ac7 + if (/^https?:/.test(version)) { + return new DependencySpecifier(name, version); + } + + // Is it an alias for a different package? + if (name === dependencyName) { + // No, it's a regular dependency + return new DependencySpecifier(name, version); + } else { + // If the parsed package name is different from the dependencyName, then this is an NPM package alias + return new DependencySpecifier(dependencyName, `npm:${name}@${version}`); + } +} + /** * Given an encoded "dependency key" from the PNPM shrinkwrap file, this parses it into an equivalent * DependencySpecifier. @@ -309,8 +333,11 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { this.overrides = new Map(Object.entries(shrinkwrapJson.overrides || {})); this.packageExtensionsChecksum = shrinkwrapJson.packageExtensionsChecksum; - // Importers only exist in workspaces - this.isWorkspaceCompatible = this.importers.size > 0; + // Lockfile v9 always has "." in importers filed. + this.isWorkspaceCompatible = + this.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V9 + ? this.importers.size > 1 + : this.importers.size > 0; this._integrities = new Map(); } @@ -342,8 +369,18 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { } public static loadFromString(shrinkwrapContent: string): PnpmShrinkwrapFile { - const parsedData: IPnpmShrinkwrapYaml = yamlModule.safeLoad(shrinkwrapContent); - return new PnpmShrinkwrapFile(parsedData); + const shrinkwrapJson: IPnpmShrinkwrapYaml = yamlModule.safeLoad(shrinkwrapContent); + if ((shrinkwrapJson as LockfileFileV9).snapshots) { + const lockfile: IPnpmShrinkwrapYaml | null = convertLockfileV9ToLockfileObject( + shrinkwrapJson as LockfileFileV9 + ); + if (lockfile) { + lockfile.dependencies = lockfile.importers['.' as ProjectId]?.dependencies; + } + return new PnpmShrinkwrapFile(lockfile); + } + + return new PnpmShrinkwrapFile(shrinkwrapJson); } public getShrinkwrapHash(experimentsConfig?: IExperimentsJson): string { @@ -479,7 +516,7 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { private _convertLockfileV6DepPathToV5DepPath(newDepPath: string): string { if (!newDepPath.includes('@', 2) || newDepPath.startsWith('file:')) return newDepPath; const index: number = newDepPath.indexOf('@', newDepPath.indexOf('/@') + 2); - if (newDepPath.includes('(') && index > dependencyPath.indexOfPeersSuffix(newDepPath)) return newDepPath; + if (newDepPath.includes('(') && index > dependencyPathLockfilePreV9.indexOfPeersSuffix(newDepPath)) return newDepPath; return `${newDepPath.substring(0, index)}/${newDepPath.substring(index + 1)}`; } @@ -493,7 +530,7 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { if (this.shrinkwrapFileMajorVersion >= 6) { depPath = this._convertLockfileV6DepPathToV5DepPath(packagePath); } - const pkgInfo: ReturnType = dependencyPath.parse(depPath); + const pkgInfo: ReturnType = dependencyPathLockfilePreV9.parse(depPath); return this._getPackageId(pkgInfo.name as string, pkgInfo.version as string); } @@ -974,7 +1011,7 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { } } } else { - // PNPM v8 + // >= PNPM v8 const importerOptionalDependencies: Set = new Set( Object.keys(importer.optionalDependencies ?? {}) ); @@ -1022,20 +1059,32 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { return true; } } else { - if (typeof specifierFromLockfile === 'string') { - throw new Error( - `The PNPM lockfile is in an unexpected format. The "${name}" package is specified as ` + - `"${specifierFromLockfile}" instead of an object.` - ); - } else { + if (this.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V9) { // TODO: Emit an error message when someone tries to override a version of something in one of their // local repo packages. let resolvedVersion: string = this.overrides.get(name) ?? version; // convert path in posix style, otherwise pnpm install will fail in subspace case resolvedVersion = Path.convertToSlashes(resolvedVersion); - if (specifierFromLockfile.specifier !== resolvedVersion && !isDevDepFallThrough && !isOptional) { + const specifier: string = importer.specifiers[name]; + if (specifier !== resolvedVersion && !isDevDepFallThrough && !isOptional) { return true; } + } else { + if (typeof specifierFromLockfile === 'string') { + throw new Error( + `The PNPM lockfile is in an unexpected format. The "${name}" package is specified as ` + + `"${specifierFromLockfile}" instead of an object.` + ); + } else { + // TODO: Emit an error message when someone tries to override a version of something in one of their + // local repo packages. + let resolvedVersion: string = this.overrides.get(name) ?? version; + // convert path in posix style, otherwise pnpm install will fail in subspace case + resolvedVersion = Path.convertToSlashes(resolvedVersion); + if (specifierFromLockfile.specifier !== resolvedVersion && !isDevDepFallThrough && !isOptional) { + return true; + } + } } } } @@ -1151,7 +1200,18 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { private _getPackageId(name: string, versionSpecifier: IPnpmVersionSpecifier): string { const version: string = normalizePnpmVersionSpecifier(versionSpecifier); - if (this.shrinkwrapFileMajorVersion >= 6) { + if (this.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V9) { + if (/https?:/.test(version)) { + return version; + } else { + const { peersIndex } = dependencyPath.indexOfPeersSuffix(version) + // name@1.2.3(peer@1.2.3) -> name@123 + const versionWithoutPeers: string = peersIndex !== -1 ? version.substring(0, peersIndex) : version; + // name@1.2.3 -> name@1.2.3 + // 1.2.3 -> name@1.2.3 + return versionWithoutPeers.includes("@", 1) ? version : `${name}@${version}`; + } + } else if (this.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V6) { if (version.startsWith('@github')) { // This is a github repo reference return version; @@ -1169,10 +1229,10 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { pnpmDependencyKey: IPnpmVersionSpecifier ): DependencySpecifier | undefined { if (pnpmDependencyKey) { - const result: DependencySpecifier | undefined = parsePnpmDependencyKey( - dependencyName, - pnpmDependencyKey - ); + const result: DependencySpecifier | undefined = + this.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V9 + ? parsePnpm9DependencyKey(dependencyName, pnpmDependencyKey) + : parsePnpmDependencyKey(dependencyName, pnpmDependencyKey); if (!result) { throw new Error( diff --git a/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapConverters.test.ts b/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapConverters.test.ts new file mode 100644 index 00000000000..7234f7721fc --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapConverters.test.ts @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { LockfileFileV9, PackageSnapshot, ProjectSnapshot } from '@pnpm/lockfile.types'; +import { convertLockfileV9ToLockfileObject } from '../PnpmShrinkWrapFileConverters'; +import { FileSystem } from '@rushstack/node-core-library'; +import yamlModule from 'js-yaml'; + +describe(convertLockfileV9ToLockfileObject.name, () => { + const lockfileContent: string = FileSystem.readFile( + `${__dirname}/yamlFiles/pnpm-lock-v9/pnpm-lock-v9.yaml` + ); + const lockfileJson: LockfileFileV9 = yamlModule.safeLoad(lockfileContent); + const lockfile = convertLockfileV9ToLockfileObject(lockfileJson); + + it('merge packages and snapshots', () => { + const packages = new Map(Object.entries(lockfile.packages || {})); + const padLeftPackage = packages.get('pad-left@2.1.0'); + expect(padLeftPackage).toBeDefined(); + expect(padLeftPackage?.dependencies).toEqual({ + 'repeat-string': '1.6.1' + }); + }); + + it("importers['.']", () => { + const importers = new Map(Object.entries(lockfile.importers || {})); + + const currentPackage = importers.get('.'); + expect(currentPackage).toBeDefined(); + + expect(currentPackage?.dependencies).toEqual({ + jquery: '3.7.1', + 'pad-left': '2.1.0' + }); + + expect(currentPackage?.specifiers).toEqual({ + jquery: '^3.7.1', + 'pad-left': '^2.1.0' + }); + }); +}); diff --git a/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapFile.test.ts b/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapFile.test.ts index 91f787e57b5..aa1170e999b 100644 --- a/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapFile.test.ts +++ b/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapFile.test.ts @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. import { type DependencySpecifier, DependencySpecifierType } from '../../DependencySpecifier'; -import { PnpmShrinkwrapFile, parsePnpmDependencyKey } from '../PnpmShrinkwrapFile'; +import { PnpmShrinkwrapFile, parsePnpm9DependencyKey, parsePnpmDependencyKey } from '../PnpmShrinkwrapFile'; import { RushConfiguration } from '../../../api/RushConfiguration'; import type { RushConfigurationProject } from '../../../api/RushConfigurationProject'; @@ -126,6 +126,99 @@ describe(PnpmShrinkwrapFile.name, () => { }); }); + describe(parsePnpm9DependencyKey.name, () => { + it('Does not support file:// specifiers', () => { + expect(parsePnpm9DependencyKey(DEPENDENCY_NAME, 'file:///path/to/file')).toBeUndefined(); + expect(parsePnpm9DependencyKey(DEPENDENCY_NAME, 'pad-left@file:///path/to/file')).toBeUndefined(); + expect(parsePnpm9DependencyKey(DEPENDENCY_NAME, 'link:///path/to/file')).toBeUndefined(); + }); + + it('Supports a variety of non-aliased package specifiers', () => { + function testSpecifiers(specifiers: string[], expectedName: string, expectedVersion: string): void { + for (const specifier of specifiers) { + const parsedSpecifier: DependencySpecifier | undefined = parsePnpm9DependencyKey( + expectedName, + specifier + ); + expect(parsedSpecifier).toBeDefined(); + expect(parsedSpecifier!.specifierType).toBe(DependencySpecifierType.Version); + expect(parsedSpecifier!.packageName).toBe(expectedName); + expect(parsedSpecifier!.versionSpecifier).toBe(expectedVersion); + } + } + + // non-scoped, non-prerelease + testSpecifiers( + [`${DEPENDENCY_NAME}@${VERSION}`, `${DEPENDENCY_NAME}@${VERSION}(peer@3.5.0+peer2@1.17.7)`], + DEPENDENCY_NAME, + VERSION + ); + + // scoped, non-prerelease + testSpecifiers( + [ + `${SCOPED_DEPENDENCY_NAME}@${VERSION}`, + `${SCOPED_DEPENDENCY_NAME}@${VERSION}(peer@3.5.0+peer2@1.17.7)` + ], + SCOPED_DEPENDENCY_NAME, + VERSION + ); + + // non-scoped, prerelease + testSpecifiers( + [ + `${DEPENDENCY_NAME}@${PRERELEASE_VERSION}`, + `${DEPENDENCY_NAME}@${PRERELEASE_VERSION}(peer@3.5.0+peer2@1.17.7)` + ], + DEPENDENCY_NAME, + PRERELEASE_VERSION + ); + + // scoped, prerelease + testSpecifiers( + [ + `${SCOPED_DEPENDENCY_NAME}@${PRERELEASE_VERSION}`, + `${SCOPED_DEPENDENCY_NAME}@${PRERELEASE_VERSION}(peer@3.5.0+peer2@1.17.7)` + ], + SCOPED_DEPENDENCY_NAME, + PRERELEASE_VERSION + ); + }); + + it('Supports aliased package specifiers (v9)', () => { + const parsedSpecifier: DependencySpecifier | undefined = parsePnpm9DependencyKey( + SCOPED_DEPENDENCY_NAME, + `${DEPENDENCY_NAME}@${VERSION}` + ); + expect(parsedSpecifier).toBeDefined(); + expect(parsedSpecifier!.specifierType).toBe(DependencySpecifierType.Alias); + expect(parsedSpecifier!.packageName).toBe(SCOPED_DEPENDENCY_NAME); + expect(parsedSpecifier!.versionSpecifier).toMatchInlineSnapshot(`"npm:${DEPENDENCY_NAME}@${VERSION}"`); + }); + + it('Supports URL package specifiers', () => { + const specifiers: string[] = [ + 'https://github.com/jonschlinkert/pad-left/tarball/2.1.0', + 'https://xxx.xxxx.org/pad-left/-/pad-left-2.1.0.tgz', + 'https://codeload.github.com/jonschlinkert/pad-left/tar.gz/7798d648225aa5d879660a37c408ab4675b65ac7', + `${SCOPED_DEPENDENCY_NAME}@http://abc.com/jonschlinkert/pad-left/tarball/2.1.0`, + `${SCOPED_DEPENDENCY_NAME}@https://xxx.xxxx.org/pad-left/-/pad-left-2.1.0.tgz`, + `${SCOPED_DEPENDENCY_NAME}@https://codeload.github.com/jonschlinkert/pad-left/tar.gz/7798d648225aa5d879660a37c408ab4675b65ac7` + ]; + + for (const specifier of specifiers) { + const parsedSpecifier: DependencySpecifier | undefined = parsePnpm9DependencyKey( + SCOPED_DEPENDENCY_NAME, + specifier + ); + expect(parsedSpecifier).toBeDefined(); + expect(parsedSpecifier!.specifierType).toBe(DependencySpecifierType.Remote); + expect(parsedSpecifier!.packageName).toBe(SCOPED_DEPENDENCY_NAME); + expect(parsedSpecifier!.versionSpecifier).toBe(specifier.replace(`${SCOPED_DEPENDENCY_NAME}@`, '')); + } + }); + }); + describe('Check is workspace project modified', () => { describe('pnpm lockfile major version 5', () => { it('can detect not modified', async () => { @@ -228,6 +321,64 @@ describe(PnpmShrinkwrapFile.name, () => { ).resolves.toBe(false); }); }); + + describe('pnpm lockfile major version 9', () => { + it('can detect not modified', async () => { + const project = getMockRushProject(); + const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( + `${__dirname}/yamlFiles/pnpm-lock-v9/not-modified.yaml` + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(false); + }); + + it('can detect modified', async () => { + const project = getMockRushProject(); + const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( + `${__dirname}/yamlFiles/pnpm-lock-v9/modified.yaml` + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(true); + }); + + it('can detect overrides', async () => { + const project = getMockRushProject(); + const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( + `${__dirname}/yamlFiles/pnpm-lock-v9/overrides-not-modified.yaml` + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(false); + }); + + it('can handle the inconsistent version of a package declared in dependencies and devDependencies', async () => { + const project = getMockRushProject2(); + const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( + `${__dirname}/yamlFiles/pnpm-lock-v9/inconsistent-dep-devDep.yaml` + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(false); + }); + }); }); }); diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/inconsistent-dep-devDep.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/inconsistent-dep-devDep.yaml new file mode 100644 index 00000000000..7f26989631c --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/inconsistent-dep-devDep.yaml @@ -0,0 +1,26 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: {} + + ../../apps/bar: + dependencies: + prettier: + specifier: ~2.3.0 + version: 2.3.2 + +packages: + + prettier@2.3.2: + resolution: {integrity: sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==} + engines: {node: '>=10.13.0'} + hasBin: true + +snapshots: + + prettier@2.3.2: {} diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/modified.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/modified.yaml new file mode 100644 index 00000000000..71509e89efe --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/modified.yaml @@ -0,0 +1,35 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: {} + + ../../apps/foo: + dependencies: + tslib: + specifier: ~2.3.0 + version: 2.3.1 + devDependencies: + typescript: + specifier: ~5.0.4 + version: 5.0.4 + +packages: + + tslib@2.3.1: + resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} + + typescript@5.0.4: + resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} + engines: {node: '>=12.20'} + hasBin: true + +snapshots: + + tslib@2.3.1: {} + + typescript@5.0.4: {} diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/not-modified.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/not-modified.yaml new file mode 100644 index 00000000000..47ef29262c3 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/not-modified.yaml @@ -0,0 +1,35 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: {} + + ../../apps/foo: + dependencies: + tslib: + specifier: ~2.3.1 + version: 2.3.1 + devDependencies: + typescript: + specifier: ~5.0.4 + version: 5.0.4 + +packages: + + tslib@2.3.1: + resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} + + typescript@5.0.4: + resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} + engines: {node: '>=12.20'} + hasBin: true + +snapshots: + + tslib@2.3.1: {} + + typescript@5.0.4: {} diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/overrides-not-modified.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/overrides-not-modified.yaml new file mode 100644 index 00000000000..d21630b1d81 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/overrides-not-modified.yaml @@ -0,0 +1,38 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +overrides: + typescript: 5.0.4 + +importers: + + .: {} + + ../../apps/foo: + dependencies: + tslib: + specifier: ~2.3.1 + version: 2.3.1 + devDependencies: + typescript: + specifier: 5.0.4 + version: 5.0.4 + +packages: + + tslib@2.3.1: + resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} + + typescript@5.0.4: + resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} + engines: {node: '>=12.20'} + hasBin: true + +snapshots: + + tslib@2.3.1: {} + + typescript@5.0.4: {} diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/pnpm-lock-v9.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/pnpm-lock-v9.yaml new file mode 100644 index 00000000000..9fe144e1b91 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/pnpm-lock-v9.yaml @@ -0,0 +1,39 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + jquery: + specifier: ^3.7.1 + version: 3.7.1 + pad-left: + specifier: ^2.1.0 + version: 2.1.0 + +packages: + + jquery@3.7.1: + resolution: {integrity: sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==} + + pad-left@2.1.0: + resolution: {integrity: sha512-HJxs9K9AztdIQIAIa/OIazRAUW/L6B9hbQDxO4X07roW3eo9XqZc2ur9bn1StH9CnbbI9EgvejHQX7CBpCF1QA==} + engines: {node: '>=0.10.0'} + + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + +snapshots: + + jquery@3.7.1: {} + + pad-left@2.1.0: + dependencies: + repeat-string: 1.6.1 + + repeat-string@1.6.1: {} diff --git a/libraries/rush-lib/src/logic/test/ShrinkwrapFile.test.ts b/libraries/rush-lib/src/logic/test/ShrinkwrapFile.test.ts index 1c4996a6fab..cfd986b947c 100644 --- a/libraries/rush-lib/src/logic/test/ShrinkwrapFile.test.ts +++ b/libraries/rush-lib/src/logic/test/ShrinkwrapFile.test.ts @@ -6,7 +6,11 @@ import { JsonFile } from '@rushstack/node-core-library'; import type { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; import { ShrinkwrapFileFactory } from '../ShrinkwrapFileFactory'; -import { parsePnpmDependencyKey, PnpmShrinkwrapFile } from '../pnpm/PnpmShrinkwrapFile'; +import { + parsePnpmDependencyKey, + PnpmShrinkwrapFile, + ShrinkwrapFileMajorVersion +} from '../pnpm/PnpmShrinkwrapFile'; import { DependencySpecifier } from '../DependencySpecifier'; import { NpmShrinkwrapFile } from '../npm/NpmShrinkwrapFile'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; @@ -73,12 +77,28 @@ describe(PnpmShrinkwrapFile.name, () => { '@rush-temp/project1' ) ).toEqual(false); - expect( - shrinkwrapFile.tryEnsureCompatibleDependency( - new DependencySpecifier('@scope/testDep', '>=2.0.0 <3.0.0'), - '@rush-temp/project3' - ) - ).toEqual(true); + + if ( + shrinkwrapFile instanceof PnpmShrinkwrapFile && + shrinkwrapFile.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V9 + ) { + expect( + shrinkwrapFile.tryEnsureCompatibleDependency( + new DependencySpecifier( + '@scope/testDep', + 'https://github.com/jonschlinkert/pad-left/tarball/2.1.0' + ), + '@rush-temp/project3' + ) + ).toEqual(true); + } else { + expect( + shrinkwrapFile.tryEnsureCompatibleDependency( + new DependencySpecifier('@scope/testDep', '>=2.0.0 <3.0.0'), + '@rush-temp/project3' + ) + ).toEqual(true); + } }); it('extracts temp projects successfully', () => { @@ -133,6 +153,19 @@ describe(PnpmShrinkwrapFile.name, () => { validateNonWorkspaceLockfile(shrinkwrapFile); }); + + describe('V9 lockfile', () => { + const filename: string = path.resolve( + __dirname, + '../../../src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v9.yaml' + ); + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile( + 'pnpm', + {}, + filename + )!; + validateNonWorkspaceLockfile(shrinkwrapFile); + }); }); describe('workspace', () => { @@ -201,6 +234,21 @@ describe(PnpmShrinkwrapFile.name, () => { validateWorkspaceLockfile(shrinkwrapFile); }); + + describe('V9 lockfile', () => { + const filename: string = path.resolve( + __dirname, + '../../../src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v9.yaml' + ); + + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile( + 'pnpm', + {}, + filename + )!; + + validateWorkspaceLockfile(shrinkwrapFile); + }); }); }); diff --git a/libraries/rush-lib/src/logic/test/__snapshots__/ShrinkwrapFile.test.ts.snap b/libraries/rush-lib/src/logic/test/__snapshots__/ShrinkwrapFile.test.ts.snap index 5192b36bf2f..c4f9d4453dd 100644 --- a/libraries/rush-lib/src/logic/test/__snapshots__/ShrinkwrapFile.test.ts.snap +++ b/libraries/rush-lib/src/logic/test/__snapshots__/ShrinkwrapFile.test.ts.snap @@ -99,3 +99,53 @@ Array [ ], ] `; + +exports[`PnpmShrinkwrapFile workspace V9 lockfile verifies project dependencies: project1 1`] = ` +Array [ + Array [ + Object { + "../../project1": "../../project1:6yFTI2g+Ny0Au80xpo6zIY61TCNDUuLUd6EgLlbOBtc=:", + "jquery@1.12.3": "sha512-FzM42/Ew+Hb8ha2OlhHRBLgWIZS32gZ0+NvWTf+ZvVvGaIlJkOiXQyb7VBjv4L6fJfmTrRf3EsAmbfsHDhfemw==", + "pad-left@1.0.2": "sha512-saxSV1EYAytuZDtQYEwi0DPzooG6aN18xyHrnJtzwjVwmMauzkEecd7hynVJGolNGk1Pl9tltmZqfze4TZTCxg==", + "repeat-string@1.6.1": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + }, + "project1/.rush/temp/shrinkwrap-deps.json", + Object { + "ensureFolderExists": true, + }, + ], +] +`; + +exports[`PnpmShrinkwrapFile workspace V9 lockfile verifies project dependencies: project2 1`] = ` +Array [ + Array [ + Object { + "../../project2": "../../project2:l6v/HWUhScMI0m4k6D5qHiCOFj3Z0GoIFJEcp4I63w0=:", + "jquery@2.2.4": "sha512-lBHj60ezci2u1v2FqnZIraShGgEXq35qCzMv4lITyHGppTnA13rwR0MgwyNJh9TnDs3aXUvd1xjAotfraMHX/Q==", + "q@1.5.0": "sha512-VVMcd+HnuWZalHPycK7CsbVJ+sSrrrnCvHcW38YJVK9Tywnb5DUWJjONi81bLUj7aqDjIXnePxBl5t1r/F/ncg==", + }, + "project2/.rush/temp/shrinkwrap-deps.json", + Object { + "ensureFolderExists": true, + }, + ], +] +`; + +exports[`PnpmShrinkwrapFile workspace V9 lockfile verifies project dependencies: project3 1`] = ` +Array [ + Array [ + Object { + "../../project3": "../../project3:vMoje8cXfsHYOc6EXbxEw/qyBGXGUL1RApmNfwl7oA8=:", + "pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0": "pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0:bKrL+SvVYubL0HwTq/GOOXq1d05LTQ+HGqlXabzGEAU=:", + "q@1.5.0": "sha512-VVMcd+HnuWZalHPycK7CsbVJ+sSrrrnCvHcW38YJVK9Tywnb5DUWJjONi81bLUj7aqDjIXnePxBl5t1r/F/ncg==", + "repeat-string@1.6.1": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + }, + "project3/.rush/temp/shrinkwrap-deps.json", + Object { + "ensureFolderExists": true, + }, + ], +] +`; diff --git a/libraries/rush-lib/src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v9.yaml b/libraries/rush-lib/src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v9.yaml new file mode 100644 index 00000000000..b74c0511f12 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v9.yaml @@ -0,0 +1,196 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@pnpm/dependency-path': + specifier: ^5.1.7 + version: 5.1.7 + '@pnpm/lockfile.utils': + specifier: ^1.0.4 + version: 1.0.4 + '@rush-temp/project1': + specifier: file:./projects/project1 + version: project1@file:projects/project1 + '@rush-temp/project2': + specifier: file:./projects/project2 + version: project2@file:projects/project2 + '@rush-temp/project3': + specifier: file:./projects/project3 + version: project3@file:projects/project3 + pad-left: + specifier: 1.0.0 + version: 1.0.0 + +packages: + + '@pnpm/crypto.base32-hash@3.0.1': + resolution: {integrity: sha512-DM4RR/tvB7tMb2FekL0Q97A5PCXNyEC+6ht8SaufAUFSJNxeozqHw9PHTZR03mzjziPzNQLOld0pNINBX3srtw==} + engines: {node: '>=18.12'} + + '@pnpm/crypto.polyfill@1.0.0': + resolution: {integrity: sha512-WbmsqqcUXKKaAF77ox1TQbpZiaQcr26myuMUu+WjUtoWYgD3VP6iKYEvSx35SZ6G2L316lu+pv+40A2GbWJc1w==} + engines: {node: '>=18.12'} + + '@pnpm/dependency-path@5.1.7': + resolution: {integrity: sha512-MKCyaTy1r9fhBXAnhDZNBVgo6ThPnicwJEG203FDp7pGhD7NruS/FhBI+uMd7GNsK3D7aIFCDAgbWpNTXn/eWw==} + engines: {node: '>=18.12'} + + '@pnpm/lockfile.types@1.0.3': + resolution: {integrity: sha512-A7vUWktnhDkrIs+WmXm7AdffJVyVYJpQUEouya/DYhB+Y+tQ3BXjZ6CV0KybqLgI/8AZErgCJqFxA0GJH6QDjA==} + engines: {node: '>=18.12'} + + '@pnpm/lockfile.utils@1.0.4': + resolution: {integrity: sha512-ptHO2muziYyNCwpsuaPtaRgKiHMrE/lkGI4nqbHnRWWgfdJbTeL1tq+b/EUsxjlKlJ/a9Q4z2C+t38g+9bhTJg==} + engines: {node: '>=18.12'} + + '@pnpm/patching.types@1.0.0': + resolution: {integrity: sha512-juCdQCC1USqLcOhVPl1tYReoTO9YH4fTullMnFXXcmpsDM7Dkn3tzuOQKC3oPoJ2ozv+0EeWWMtMGqn2+IM3pQ==} + engines: {node: '>=18.12'} + + '@pnpm/pick-fetcher@3.0.0': + resolution: {integrity: sha512-2eisylRAU/jeuxFEPnS1gjLZKJGbYc4QEtEW6MVUYjO4Xi+2ttkSm7825S0J5IPpUIvln8HYPCUS0eQWSfpOaQ==} + engines: {node: '>=18.12'} + + '@pnpm/ramda@0.28.1': + resolution: {integrity: sha512-zcAG+lvU0fMziNeGXpPyCyCJYp5ZVrPElEE4t14jAmViaihohocZ+dDkcRIyAomox8pQsuZnv1EyHR+pOhmUWw==} + + '@pnpm/resolver-base@13.0.4': + resolution: {integrity: sha512-d6GtsaXDN1VmVdeB6ohrhwGwQfvYpEX/XkBZyRT0Hp772WabWVfaulvicwdh/8o7Rpzy7IV/2hKnDpodUY00lw==} + engines: {node: '>=18.12'} + + '@pnpm/types@12.2.0': + resolution: {integrity: sha512-5RtwWhX39j89/Tmyv2QSlpiNjErA357T/8r1Dkg+2lD3P7RuS7Xi2tChvmOC3VlezEFNcWnEGCOeKoGRkDuqFA==} + engines: {node: '>=18.12'} + + get-npm-tarball-url@2.1.0: + resolution: {integrity: sha512-ro+DiMu5DXgRBabqXupW38h7WPZ9+Ad8UjwhvsmmN8w1sU7ab0nzAXvVZ4kqYg57OrqomRtJvepX5/xvFKNtjA==} + engines: {node: '>=12.17'} + + jquery@1.12.3: + resolution: {integrity: sha512-FzM42/Ew+Hb8ha2OlhHRBLgWIZS32gZ0+NvWTf+ZvVvGaIlJkOiXQyb7VBjv4L6fJfmTrRf3EsAmbfsHDhfemw==} + + jquery@2.2.4: + resolution: {integrity: sha512-lBHj60ezci2u1v2FqnZIraShGgEXq35qCzMv4lITyHGppTnA13rwR0MgwyNJh9TnDs3aXUvd1xjAotfraMHX/Q==} + + pad-left@1.0.0: + resolution: {integrity: sha512-VIgD7DviaDL6QCj+jEU1jpjXlu0z/sl4yzAmFLmM7YvM3ZRKLaxZAe+sZ1hKHeYUeI4zoZHfMetDpazu/uAwsw==} + engines: {node: '>=0.10.0'} + + pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0: + resolution: {tarball: https://github.com/jonschlinkert/pad-left/tarball/2.1.0} + version: 2.1.0 + engines: {node: '>=0.10.0'} + + project1@file:projects/project1: + resolution: {directory: projects/project1, type: directory} + + project2@file:projects/project2: + resolution: {directory: projects/project2, type: directory} + + project3@file:projects/project3: + resolution: {directory: projects/project3, type: directory} + + q@1.5.1: + resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + deprecated: |- + You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other. + + (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) + + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + + rfc4648@1.5.3: + resolution: {integrity: sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==} + + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + +snapshots: + + '@pnpm/crypto.base32-hash@3.0.1': + dependencies: + '@pnpm/crypto.polyfill': 1.0.0 + rfc4648: 1.5.3 + + '@pnpm/crypto.polyfill@1.0.0': {} + + '@pnpm/dependency-path@5.1.7': + dependencies: + '@pnpm/crypto.base32-hash': 3.0.1 + '@pnpm/types': 12.2.0 + semver: 7.6.3 + + '@pnpm/lockfile.types@1.0.3': + dependencies: + '@pnpm/patching.types': 1.0.0 + '@pnpm/types': 12.2.0 + + '@pnpm/lockfile.utils@1.0.4': + dependencies: + '@pnpm/dependency-path': 5.1.7 + '@pnpm/lockfile.types': 1.0.3 + '@pnpm/pick-fetcher': 3.0.0 + '@pnpm/resolver-base': 13.0.4 + '@pnpm/types': 12.2.0 + get-npm-tarball-url: 2.1.0 + ramda: '@pnpm/ramda@0.28.1' + + '@pnpm/patching.types@1.0.0': {} + + '@pnpm/pick-fetcher@3.0.0': {} + + '@pnpm/ramda@0.28.1': {} + + '@pnpm/resolver-base@13.0.4': + dependencies: + '@pnpm/types': 12.2.0 + + '@pnpm/types@12.2.0': {} + + get-npm-tarball-url@2.1.0: {} + + jquery@1.12.3: {} + + jquery@2.2.4: {} + + pad-left@1.0.0: + dependencies: + repeat-string: 1.6.1 + + pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0: + dependencies: + repeat-string: 1.6.1 + + project1@file:projects/project1: + dependencies: + jquery: 1.12.3 + pad-left: 1.0.0 + + project2@file:projects/project2: + dependencies: + jquery: 2.2.4 + q: 1.5.1 + + project3@file:projects/project3: + dependencies: + '@scope/testDep': pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0 + q: 1.5.1 + + q@1.5.1: {} + + repeat-string@1.6.1: {} + + rfc4648@1.5.3: {} + + semver@7.6.3: {} diff --git a/libraries/rush-lib/src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v9.yaml b/libraries/rush-lib/src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v9.yaml new file mode 100644 index 00000000000..ad160af09b8 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v9.yaml @@ -0,0 +1,83 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: {} + + ../../project1: + dependencies: + jquery: + specifier: 1.12.3 + version: 1.12.3 + pad-left: + specifier: ^1.0.0 + version: 1.0.2 + + ../../project2: + dependencies: + jquery: + specifier: 2.2.4 + version: 2.2.4 + q: + specifier: ~1.5.0 + version: 1.5.0 + + ../../project3: + dependencies: + '@scope/testDep': + specifier: https://github.com/jonschlinkert/pad-left/tarball/2.1.0 + version: pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0 + q: + specifier: 1.5.0 + version: 1.5.0 + +packages: + + jquery@1.12.3: + resolution: {integrity: sha512-FzM42/Ew+Hb8ha2OlhHRBLgWIZS32gZ0+NvWTf+ZvVvGaIlJkOiXQyb7VBjv4L6fJfmTrRf3EsAmbfsHDhfemw==} + + jquery@2.2.4: + resolution: {integrity: sha512-lBHj60ezci2u1v2FqnZIraShGgEXq35qCzMv4lITyHGppTnA13rwR0MgwyNJh9TnDs3aXUvd1xjAotfraMHX/Q==} + + pad-left@1.0.2: + resolution: {integrity: sha512-saxSV1EYAytuZDtQYEwi0DPzooG6aN18xyHrnJtzwjVwmMauzkEecd7hynVJGolNGk1Pl9tltmZqfze4TZTCxg==} + engines: {node: '>=0.10.0'} + + pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0: + resolution: {tarball: https://github.com/jonschlinkert/pad-left/tarball/2.1.0} + version: 2.1.0 + engines: {node: '>=0.10.0'} + + q@1.5.0: + resolution: {integrity: sha512-VVMcd+HnuWZalHPycK7CsbVJ+sSrrrnCvHcW38YJVK9Tywnb5DUWJjONi81bLUj7aqDjIXnePxBl5t1r/F/ncg==} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + deprecated: |- + You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other. + + (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) + + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + +snapshots: + + jquery@1.12.3: {} + + jquery@2.2.4: {} + + pad-left@1.0.2: + dependencies: + repeat-string: 1.6.1 + + pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0: + dependencies: + repeat-string: 1.6.1 + + q@1.5.0: {} + + repeat-string@1.6.1: {} diff --git a/libraries/rush-sdk/package.json b/libraries/rush-sdk/package.json index d827a11b3d1..e3b1a372252 100644 --- a/libraries/rush-sdk/package.json +++ b/libraries/rush-sdk/package.json @@ -38,6 +38,7 @@ }, "license": "MIT", "dependencies": { + "@pnpm/lockfile.types": "~1.0.3", "@rushstack/lookup-by-path": "workspace:*", "@rushstack/node-core-library": "workspace:*", "@rushstack/package-deps-hash": "workspace:*",