mirror of https://github.com/nodejs/corepack.git
Compare commits
70 Commits
Author | SHA1 | Date |
---|---|---|
|
15498ddb9a | |
|
9a1794a59f | |
|
783a42fbe3 | |
|
98fd966176 | |
|
5fc3691354 | |
|
b45b3a3244 | |
|
77fff3c1f3 | |
|
273237a110 | |
|
2b43f26135 | |
|
aefde28a63 | |
|
0b94797f96 | |
|
679bcefda5 | |
|
633764f7c4 | |
|
19e3c6861a | |
|
b83bb5ec15 | |
|
7deb39ead0 | |
|
9b95b46f05 | |
|
b456268851 | |
|
53b1fe75c4 | |
|
4be72f6941 | |
|
bb16184b7b | |
|
b0608d1a60 | |
|
351d86c202 | |
|
48ce89827c | |
|
da96687e69 | |
|
f8de7214e5 | |
|
7f7336b9bd | |
|
d26a552daa | |
|
7b193d8498 | |
|
91ea527475 | |
|
c388c64805 | |
|
12e77e5069 | |
|
b0c46078f1 | |
|
bae0839794 | |
|
d5e938795b | |
|
9317593dda | |
|
8163608e49 | |
|
721eeec8c3 | |
|
a7cb9f603c | |
|
c11891152c | |
|
ab38255f24 | |
|
34abfcaee8 | |
|
72a588c237 | |
|
8c90caab7f | |
|
9dfbe18003 | |
|
2a04e7c8da | |
|
8bebc0c0a5 | |
|
c7a9bde16d | |
|
0ae3c3c1f5 | |
|
afd939011f | |
|
256cf8aaa4 | |
|
1bb0fb5d67 | |
|
a286c8f553 | |
|
cba690575b | |
|
72ed05b775 | |
|
98d0e43cbc | |
|
d732259faf | |
|
095903b3a8 | |
|
8ba6e0b3ba | |
|
b819e404db | |
|
2c2005cc42 | |
|
cb2c063dd6 | |
|
4ca33d3974 | |
|
bc13d40037 | |
|
eb63873c6c | |
|
93a49c8b2b | |
|
67463b2a3b | |
|
6019d7b56e | |
|
06e5872189 | |
|
85e556a1a9 |
|
@ -39,22 +39,28 @@ jobs:
|
|||
run: corepack yarn typecheck
|
||||
|
||||
- name: "Check for linting errors"
|
||||
run: corepack yarn lint
|
||||
run: corepack yarn lint --max-warnings=0
|
||||
|
||||
build-and-test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node:
|
||||
- 18
|
||||
- 20
|
||||
- 21
|
||||
- 22
|
||||
- 24
|
||||
platform:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
- windows-latest
|
||||
|
||||
# Temporarily skipping Node.js 24 under Windows due to issue
|
||||
# https://github.com/nodejs/corepack/issues/715
|
||||
# vitest fails "handle integrity checks" on Windows with Node.js 24.x
|
||||
exclude:
|
||||
- node: 24
|
||||
platform: windows-latest
|
||||
|
||||
name: "${{matrix.platform}} w/ Node.js ${{matrix.node}}.x"
|
||||
runs-on: ${{matrix.platform}}
|
||||
|
||||
|
|
|
@ -7,14 +7,20 @@ on:
|
|||
env:
|
||||
YARN_ENABLE_GLOBAL_CACHE: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
outputs:
|
||||
release_created: ${{ steps.release.outputs.release_created }}
|
||||
release_tag: ${{ steps.release.outputs.tag_name }}
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
- uses: googleapis/release-please-action@v3
|
||||
id: release
|
||||
with:
|
||||
release-type: node
|
||||
|
@ -25,6 +31,9 @@ jobs:
|
|||
needs: release-please
|
||||
if: ${{ needs.release-please.outputs.release_created }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
@ -44,10 +53,10 @@ jobs:
|
|||
restore-keys: |
|
||||
${{runner.os}}-yarn-
|
||||
|
||||
- run: corepack yarn install --immutable
|
||||
|
||||
- name: Publish to the npm registry
|
||||
run: |
|
||||
corepack yarn install --immutable
|
||||
corepack yarn npm publish
|
||||
run: corepack yarn npm publish --provenance
|
||||
env:
|
||||
YARN_NPM_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@ on:
|
|||
|
||||
jobs:
|
||||
fetch-latest-versions:
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
|
|
@ -17,6 +17,8 @@ env:
|
|||
|
||||
jobs:
|
||||
build-and-update-nock-files:
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
|
|
@ -13,3 +13,5 @@
|
|||
|
||||
/shims
|
||||
/coverage
|
||||
|
||||
/node_modules
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"**/.yarn": true,
|
||||
"**/.pnp.*": true
|
||||
},
|
||||
"eslint.experimental.useFlatConfig": true,
|
||||
"eslint.useFlatConfig": true,
|
||||
"eslint.nodePath": ".yarn/sdks",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
diff --git a/lib/platform/package.json b/lib/platform/package.json
|
||||
index 5ea9d43740d1bdb509612376c0e9ce91d20f8b20..08d4f7327dee5e605107a343d73b2254ed08ddb9 100644
|
||||
--- a/lib/platform/package.json
|
||||
+++ b/lib/platform/package.json
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
- "main": "./node",
|
||||
+ "main": "./node.js",
|
||||
"browser": "./browser"
|
||||
}
|
|
@ -1,20 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require eslint/bin/eslint.js
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
// Defer to the real eslint/bin/eslint.js your application uses
|
||||
module.exports = absRequire(`eslint/bin/eslint.js`);
|
||||
module.exports = wrapWithUserWrapper(absRequire(`eslint/bin/eslint.js`));
|
||||
|
|
|
@ -1,20 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require eslint
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
// Defer to the real eslint your application uses
|
||||
module.exports = absRequire(`eslint`);
|
||||
module.exports = wrapWithUserWrapper(absRequire(`eslint`));
|
||||
|
|
|
@ -1,20 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require eslint/use-at-your-own-risk
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
// Defer to the real eslint/use-at-your-own-risk your application uses
|
||||
module.exports = absRequire(`eslint/use-at-your-own-risk`);
|
||||
module.exports = wrapWithUserWrapper(absRequire(`eslint/use-at-your-own-risk`));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "eslint",
|
||||
"version": "8.56.0-sdk",
|
||||
"version": "8.57.0-sdk",
|
||||
"main": "./lib/api.js",
|
||||
"type": "commonjs",
|
||||
"bin": {
|
||||
|
|
|
@ -1,20 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript/bin/tsc
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
// Defer to the real typescript/bin/tsc your application uses
|
||||
module.exports = absRequire(`typescript/bin/tsc`);
|
||||
module.exports = wrapWithUserWrapper(absRequire(`typescript/bin/tsc`));
|
||||
|
|
|
@ -1,20 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript/bin/tsserver
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
// Defer to the real typescript/bin/tsserver your application uses
|
||||
module.exports = absRequire(`typescript/bin/tsserver`);
|
||||
module.exports = wrapWithUserWrapper(absRequire(`typescript/bin/tsserver`));
|
||||
|
|
|
@ -1,20 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript/lib/tsc.js
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
// Defer to the real typescript/lib/tsc.js your application uses
|
||||
module.exports = absRequire(`typescript/lib/tsc.js`);
|
||||
module.exports = wrapWithUserWrapper(absRequire(`typescript/lib/tsc.js`));
|
||||
|
|
|
@ -1,15 +1,38 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const moduleWrapper = tsserver => {
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript/lib/tsserver.js
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
const moduleWrapper = exports => {
|
||||
return wrapWithUserWrapper(moduleWrapperFn(exports));
|
||||
};
|
||||
|
||||
const moduleWrapperFn = tsserver => {
|
||||
if (!process.versions.pnp) {
|
||||
return tsserver;
|
||||
}
|
||||
|
@ -214,11 +237,11 @@ const moduleWrapper = tsserver => {
|
|||
return tsserver;
|
||||
};
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript/lib/tsserver.js
|
||||
require(absPnpApiPath).setup();
|
||||
}
|
||||
const [major, minor] = absRequire(`typescript/package.json`).version.split(`.`, 2).map(value => parseInt(value, 10));
|
||||
// In TypeScript@>=5.5 the tsserver uses the public TypeScript API so that needs to be patched as well.
|
||||
// Ref https://github.com/microsoft/TypeScript/pull/55326
|
||||
if (major > 5 || (major === 5 && minor >= 5)) {
|
||||
moduleWrapper(absRequire(`typescript`));
|
||||
}
|
||||
|
||||
// Defer to the real typescript/lib/tsserver.js your application uses
|
||||
|
|
|
@ -1,15 +1,38 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const moduleWrapper = tsserver => {
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript/lib/tsserverlibrary.js
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
const moduleWrapper = exports => {
|
||||
return wrapWithUserWrapper(moduleWrapperFn(exports));
|
||||
};
|
||||
|
||||
const moduleWrapperFn = tsserver => {
|
||||
if (!process.versions.pnp) {
|
||||
return tsserver;
|
||||
}
|
||||
|
@ -214,11 +237,11 @@ const moduleWrapper = tsserver => {
|
|||
return tsserver;
|
||||
};
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript/lib/tsserverlibrary.js
|
||||
require(absPnpApiPath).setup();
|
||||
}
|
||||
const [major, minor] = absRequire(`typescript/package.json`).version.split(`.`, 2).map(value => parseInt(value, 10));
|
||||
// In TypeScript@>=5.5 the tsserver uses the public TypeScript API so that needs to be patched as well.
|
||||
// Ref https://github.com/microsoft/TypeScript/pull/55326
|
||||
if (major > 5 || (major === 5 && minor >= 5)) {
|
||||
moduleWrapper(absRequire(`typescript`));
|
||||
}
|
||||
|
||||
// Defer to the real typescript/lib/tsserverlibrary.js your application uses
|
||||
|
|
|
@ -1,20 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
// Defer to the real typescript your application uses
|
||||
module.exports = absRequire(`typescript`);
|
||||
module.exports = wrapWithUserWrapper(absRequire(`typescript`));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "typescript",
|
||||
"version": "5.3.3-sdk",
|
||||
"version": "5.7.3-sdk",
|
||||
"main": "./lib/typescript.js",
|
||||
"type": "commonjs",
|
||||
"bin": {
|
||||
|
|
80
CHANGELOG.md
80
CHANGELOG.md
|
@ -1,5 +1,85 @@
|
|||
# Changelog
|
||||
|
||||
## [0.33.0](https://github.com/nodejs/corepack/compare/v0.32.0...v0.33.0) (2025-06-02)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Adds guard to avoid stepping on Yarn's feet ([#714](https://github.com/nodejs/corepack/issues/714)) ([5fc3691](https://github.com/nodejs/corepack/commit/5fc3691354eb5bdeca17a9495b234584353f0151))
|
||||
* update package manager versions ([#671](https://github.com/nodejs/corepack/issues/671)) ([b45b3a3](https://github.com/nodejs/corepack/commit/b45b3a3244bacfbaf65188ae8c04209a1e98307d))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* debug text typo ([#698](https://github.com/nodejs/corepack/issues/698)) ([0b94797](https://github.com/nodejs/corepack/commit/0b94797f96e30e46e466873fe7d437d0471cd92c))
|
||||
|
||||
## [0.32.0](https://github.com/nodejs/corepack/compare/v0.31.0...v0.32.0) (2025-02-28)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add limited support for `devEngines` ([#643](https://github.com/nodejs/corepack/issues/643)) ([b456268](https://github.com/nodejs/corepack/commit/b4562688513f23e37e37b0d69a0daff33ca84c8d))
|
||||
* add more informative error when fetching latest stable fails ([#644](https://github.com/nodejs/corepack/issues/644)) ([53b1fe7](https://github.com/nodejs/corepack/commit/53b1fe75c47c06bd72a8b8f8bb699a47c9ca32fb))
|
||||
* add support for `.corepack.env` ([#642](https://github.com/nodejs/corepack/issues/642)) ([9b95b46](https://github.com/nodejs/corepack/commit/9b95b46f05e50fe1c60f05309c210ba8fe4e23c5))
|
||||
* update package manager versions ([#617](https://github.com/nodejs/corepack/issues/617)) ([b83bb5e](https://github.com/nodejs/corepack/commit/b83bb5ec150980c998b9c7053dff307d912cb508))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* do not resolve fallback descriptor when `packageManager` is defined ([#632](https://github.com/nodejs/corepack/issues/632)) ([12e77e5](https://github.com/nodejs/corepack/commit/12e77e506946d42a0de9ce8e68d75af8454d6776))
|
||||
* **doc:** fix link to proxy library ([#636](https://github.com/nodejs/corepack/issues/636)) ([bae0839](https://github.com/nodejs/corepack/commit/bae08397943d4b99437389b4286546361091f4b3))
|
||||
* replace explicit with specify as verb ([#665](https://github.com/nodejs/corepack/issues/665)) ([351d86c](https://github.com/nodejs/corepack/commit/351d86c20226a8c18bfe212be27401f2908b1595))
|
||||
* **use:** do not throw on invalid `packageManager` ([#663](https://github.com/nodejs/corepack/issues/663)) ([4be72f6](https://github.com/nodejs/corepack/commit/4be72f6941afa0c9b2b7d26635016bb7b560df8a))
|
||||
|
||||
## [0.31.0](https://github.com/nodejs/corepack/compare/v0.30.0...v0.31.0) (2025-01-27)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* drop support for Node.js 21.x ([#594](https://github.com/nodejs/corepack/issues/594))
|
||||
|
||||
### Features
|
||||
|
||||
* update package manager versions ([#595](https://github.com/nodejs/corepack/issues/595)) ([c7a9bde](https://github.com/nodejs/corepack/commit/c7a9bde16dcbbb7e6ef03fef740656cde7ade360))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* only print message for `UsageError`s ([#602](https://github.com/nodejs/corepack/issues/602)) ([72a588c](https://github.com/nodejs/corepack/commit/72a588c2370c17e415b24fe389efdafb3c84e90b))
|
||||
* update npm registry keys ([#614](https://github.com/nodejs/corepack/issues/614)) ([8c90caa](https://github.com/nodejs/corepack/commit/8c90caab7f1c5c9b89f1de113bc1dfc441bf25d2))
|
||||
|
||||
|
||||
### Miscellaneous Chores
|
||||
|
||||
* drop support for Node.js 21.x ([#594](https://github.com/nodejs/corepack/issues/594)) ([8bebc0c](https://github.com/nodejs/corepack/commit/8bebc0c0a5cbcdeec41673dcbaf581e6e1c1be11))
|
||||
|
||||
## [0.30.0](https://github.com/nodejs/corepack/compare/v0.29.4...v0.30.0) (2024-11-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* update package manager versions ([#578](https://github.com/nodejs/corepack/issues/578)) ([a286c8f](https://github.com/nodejs/corepack/commit/a286c8f5537ea9ecf9b6ff53c7bc3e8da4e3c8bb))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* prefer `module.enableCompileCache` over `v8-compile-cache` ([#574](https://github.com/nodejs/corepack/issues/574)) ([cba6905](https://github.com/nodejs/corepack/commit/cba690575bd606faeee54bd512ccb8797d49055f))
|
||||
|
||||
## [0.29.4](https://github.com/nodejs/corepack/compare/v0.29.3...v0.29.4) (2024-09-07)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* update package manager versions ([#543](https://github.com/nodejs/corepack/issues/543)) ([b819e40](https://github.com/nodejs/corepack/commit/b819e404dbb23c4ae3d5dbe55e21de74d714ee9c))
|
||||
|
||||
## [0.29.3](https://github.com/nodejs/corepack/compare/v0.29.2...v0.29.3) (2024-07-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fallback to `shasum` when `integrity` is not defined ([#542](https://github.com/nodejs/corepack/issues/542)) ([eb63873](https://github.com/nodejs/corepack/commit/eb63873c6c617a2f8ac7106e26ccfe8aa3ae1fb9))
|
||||
* make `DEBUG=corepack` more useful ([#538](https://github.com/nodejs/corepack/issues/538)) ([6019d7b](https://github.com/nodejs/corepack/commit/6019d7b56e85bd8b7b58a1a487922c707e70e30e))
|
||||
|
||||
## [0.29.2](https://github.com/nodejs/corepack/compare/v0.29.1...v0.29.2) (2024-07-13)
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
If you want to build Corepack yourself, you can build the project like this:
|
||||
|
||||
1. Clone this repository.
|
||||
1. Clone this repository. Some restrictions on the cloning location apply to Windows users, read [Contributing on Windows](#contributing-on-windows) for more information.
|
||||
2. Run `yarn install` (or `corepack yarn install` if the global version of
|
||||
`yarn` is not provided by Corepack).
|
||||
3. Run `yarn build` (or `corepack yarn build`).
|
||||
|
@ -11,6 +11,12 @@ The `dist/` directory now contains the corepack build and the shims.
|
|||
Call `node ./dist/corepack --help` and behold.
|
||||
You can also run the tests with `yarn test`.
|
||||
|
||||
## Contributing on Windows
|
||||
|
||||
If you are cloning the repo to a directory on a Microsoft Windows operating system, it is recommended to use the same drive as your Windows `HOMEDRIVE` to avoid build and other issues related to a current restriction with Yarn Plug'n'Play caching.
|
||||
|
||||
If you are unable to use your `HOMEDRIVE`, you may be able to work around the issue by setting the environment variable `YARN_ENABLE_GLOBAL_CACHE` to `false` before running `yarn install` (or `corepack yarn install`).
|
||||
|
||||
# Adding a new package manager
|
||||
|
||||
New package managers can be added by editing the following files:
|
||||
|
@ -18,7 +24,7 @@ New package managers can be added by editing the following files:
|
|||
- [`config.json`](./config.json),
|
||||
- [`.github/workflows/sync.yml`](./.github/workflows/sync.yml) that keeps pinned
|
||||
versions up-to-date,
|
||||
- [`package.json`](./package.json) to add to add the added shims to the list of
|
||||
- [`package.json`](./package.json) to add the new shims to the list of
|
||||
`"publishConfig/bin"` and `"executableFiles"`,
|
||||
- [`sources/types.ts`](./sources/types.ts) to add the package manager to the
|
||||
`SupportedPackageManagers` enum,
|
||||
|
|
68
README.md
68
README.md
|
@ -11,7 +11,7 @@ and pnpm without having to install them**.
|
|||
|
||||
### Default Installs
|
||||
|
||||
Corepack is [distributed by default with all recent Node.js versions](https://nodejs.org/api/corepack.html).
|
||||
Corepack is distributed with Node.js from version 14.19.0 up to (but not including) 25.0.0.
|
||||
Run `corepack enable` to install the required Yarn and pnpm binaries on your path.
|
||||
|
||||
### Manual Installs
|
||||
|
@ -41,6 +41,25 @@ is distributed along with Node.js itself.
|
|||
|
||||
</details>
|
||||
|
||||
<details><summary>Update Corepack using npm</summary>
|
||||
|
||||
To install the latest version of Corepack, use:
|
||||
|
||||
```shell
|
||||
npm install -g corepack@latest
|
||||
```
|
||||
|
||||
If Corepack was installed on your system using a Node.js Windows Installer
|
||||
`.msi` package then you might need to remove it before attempting to install a
|
||||
different version of Corepack using npm. You can select the Modify option of the
|
||||
Node.js app settings to access the Windows Installer feature selection, and on
|
||||
the "corepack manager" feature of the Node.js `.msi` package by selecting
|
||||
"Entire feature will be unavailable". See
|
||||
[Repair apps and programs in Windows](https://support.microsoft.com/en-us/windows/repair-apps-and-programs-in-windows-e90eefe4-d0a2-7c1b-dd59-949a9030f317)
|
||||
for instructions on accessing the Windows apps page to modify settings.
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>Install Corepack from source</summary>
|
||||
|
||||
See [`CONTRIBUTING.md`](./CONTRIBUTING.md).
|
||||
|
@ -94,6 +113,35 @@ use in the archive).
|
|||
}
|
||||
```
|
||||
|
||||
#### `devEngines.packageManager`
|
||||
|
||||
When a `devEngines.packageManager` field is defined, and is an object containing
|
||||
a `"name"` field (can also optionally contain `version` and `onFail` fields),
|
||||
Corepack will use it to validate you're using a compatible package manager.
|
||||
|
||||
Depending on the value of `devEngines.packageManager.onFail`:
|
||||
|
||||
- if set to `ignore`, Corepack won't print any warning or error.
|
||||
- if unset or set to `error`, Corepack will throw an error in case of a mismatch.
|
||||
- if set to `warn` or some other value, Corepack will print a warning in case
|
||||
of mismatch.
|
||||
|
||||
If the top-level `packageManager` field is missing, Corepack will use the
|
||||
package manager defined in `devEngines.packageManager` – in which case you must
|
||||
provide a specific version in `devEngines.packageManager.version`, ideally with
|
||||
a hash, as explained in the previous section:
|
||||
|
||||
```json
|
||||
{
|
||||
"devEngines":{
|
||||
"packageManager": {
|
||||
"name": "yarn",
|
||||
"version": "3.2.3+sha224.953c8233f7a92884eee2de69a1b92d1f2ec1655e66d08071ba9a02fa"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Known Good Releases
|
||||
|
||||
When running Corepack within projects that don't list a supported package
|
||||
|
@ -227,6 +275,7 @@ it.
|
|||
|
||||
Unlike `corepack use` this command doesn't take a package manager name nor a
|
||||
version range, as it will always select the latest available version from the
|
||||
range specified in `devEngines.packageManager.version`, or fallback to the
|
||||
same major line. Should you need to upgrade to a new major, use an explicit
|
||||
`corepack use {name}@latest` call (or simply `corepack use {name}`).
|
||||
|
||||
|
@ -237,8 +286,8 @@ same major line. Should you need to upgrade to a new major, use an explicit
|
|||
package manager, and to not update the Last Known Good version when it
|
||||
downloads a new version of the same major line.
|
||||
|
||||
- `COREPACK_ENABLE_AUTO_PIN` can be set to `0` to prevent Corepack from
|
||||
updating the `packageManager` field when it detects that the local package
|
||||
- `COREPACK_ENABLE_AUTO_PIN` can be set to `1` to instruct Corepack to
|
||||
update the `packageManager` field when it detects that the local package
|
||||
doesn't list it. In general we recommend to always list a `packageManager`
|
||||
field (which you can easily set through `corepack use [name]@[version]`), as
|
||||
it ensures that your project installs are always deterministic.
|
||||
|
@ -248,6 +297,7 @@ same major line. Should you need to upgrade to a new major, use an explicit
|
|||
set to `1` to have the URL shown. By default, when Corepack is called
|
||||
explicitly (e.g. `corepack pnpm …`), it is set to `0`; when Corepack is called
|
||||
implicitly (e.g. `pnpm …`), it is set to `1`.
|
||||
The default value cannot be overridden in a `.corepack.env` file.
|
||||
When standard input is a TTY and no CI environment is detected, Corepack will
|
||||
ask for user input before starting the download.
|
||||
|
||||
|
@ -273,6 +323,14 @@ same major line. Should you need to upgrade to a new major, use an explicit
|
|||
project. This means that it will always use the system-wide package manager
|
||||
regardless of what is being specified in the project's `packageManager` field.
|
||||
|
||||
- `COREPACK_ENV_FILE` can be set to `0` to request Corepack to not attempt to
|
||||
load `.corepack.env`; it can be set to a path to specify a different env file.
|
||||
Only keys that start with `COREPACK_` and are not in the exception list
|
||||
(`COREPACK_ENABLE_DOWNLOAD_PROMPT` and `COREPACK_ENV_FILE` are ignored)
|
||||
will be taken into account.
|
||||
For Node.js 18.x users, this setting has no effect as that version doesn't
|
||||
support parsing of `.env` files.
|
||||
|
||||
- `COREPACK_HOME` can be set in order to define where Corepack should install
|
||||
the package managers. By default it is set to `%LOCALAPPDATA%\node\corepack`
|
||||
on Windows, and to `$HOME/.cache/node/corepack` everywhere else.
|
||||
|
@ -294,7 +352,7 @@ same major line. Should you need to upgrade to a new major, use an explicit
|
|||
empty password, explicitly set `COREPACK_NPM_PASSWORD` to an empty string.
|
||||
|
||||
- `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` are supported through
|
||||
[`node-proxy-agent`](https://github.com/TooTallNate/node-proxy-agent).
|
||||
[`proxy-from-env`](https://github.com/Rob--W/proxy-from-env).
|
||||
|
||||
- `COREPACK_INTEGRITY_KEYS` can be set to an empty string or `0` to
|
||||
instruct Corepack to skip integrity checks, or to a JSON string containing
|
||||
|
@ -302,6 +360,8 @@ same major line. Should you need to upgrade to a new major, use an explicit
|
|||
|
||||
## Troubleshooting
|
||||
|
||||
The environment variable `DEBUG` can be set to `corepack` to enable additional debug logging.
|
||||
|
||||
### Networking
|
||||
|
||||
There are a wide variety of networking issues that can occur while running
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
module.exports = {
|
||||
presets: [
|
||||
`@babel/preset-typescript`,
|
||||
],
|
||||
plugins: [
|
||||
[`@babel/plugin-transform-modules-commonjs`],
|
||||
[`babel-plugin-dynamic-import-node`],
|
||||
],
|
||||
};
|
15
config.json
15
config.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"definitions": {
|
||||
"npm": {
|
||||
"default": "10.8.2+sha1.3c123c7f14409dc0395478e7269fdbc32ae179d8",
|
||||
"default": "11.4.1+sha1.80350af543069991de20657ebcd07d9624cfad06",
|
||||
"fetchLatestFrom": {
|
||||
"type": "npm",
|
||||
"package": "npm"
|
||||
|
@ -38,7 +38,7 @@
|
|||
}
|
||||
},
|
||||
"pnpm": {
|
||||
"default": "9.5.0+sha1.8c155dc114e1689d18937974f6571e0ceee66f1d",
|
||||
"default": "10.11.0+sha1.4048eeefd564ff1ab248fac3e2854d38245fe2f1",
|
||||
"fetchLatestFrom": {
|
||||
"type": "npm",
|
||||
"package": "pnpm"
|
||||
|
@ -102,7 +102,7 @@
|
|||
"package": "yarn"
|
||||
},
|
||||
"transparent": {
|
||||
"default": "4.3.1+sha224.934d21773e22af4b69a7032a2d3b4cb38c1f7c019624777cc9916b23",
|
||||
"default": "4.9.1+sha224.4285002185abb91fe2b781f27fd1e078086c37a7b095f6ea4ee25971",
|
||||
"commands": [
|
||||
[
|
||||
"yarn",
|
||||
|
@ -165,11 +165,18 @@
|
|||
"keys": {
|
||||
"npm": [
|
||||
{
|
||||
"expires": null,
|
||||
"expires": "2025-01-29T00:00:00.000Z",
|
||||
"keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA",
|
||||
"keytype": "ecdsa-sha2-nistp256",
|
||||
"scheme": "ecdsa-sha2-nistp256",
|
||||
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg=="
|
||||
},
|
||||
{
|
||||
"expires": null,
|
||||
"keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U",
|
||||
"keytype": "ecdsa-sha2-nistp256",
|
||||
"scheme": "ecdsa-sha2-nistp256",
|
||||
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEY6Ya7W++7aUPzvMTrezH6Ycx3c+HOKYCcNGybJZSCJq/fd7Qa8uuAKtdIkUQtQiEKERhAmE5lMMJhP8OkDOa2g=="
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -13,11 +13,13 @@ export default [
|
|||
...yarnpkg,
|
||||
{
|
||||
rules: {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
'no-restricted-globals': [`error`, {
|
||||
name: `fetch`,
|
||||
message: `Use fetch from sources/httpUtils.ts`,
|
||||
}],
|
||||
'@typescript-eslint/no-unused-vars': [`error`, {
|
||||
caughtErrors: `none`,
|
||||
}],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
module.exports = {
|
||||
setupFilesAfterEnv: [`./tests/setupTests.js`],
|
||||
testTimeout: 120000,
|
||||
};
|
|
@ -22,6 +22,7 @@ async function main() {
|
|||
fs.writeFileSync(corepackPath, [
|
||||
`#!/usr/bin/env node`,
|
||||
`process.env.COREPACK_ENABLE_DOWNLOAD_PROMPT??='0';`,
|
||||
`require('module').enableCompileCache?.();`,
|
||||
`require('./lib/corepack.cjs').runMain(process.argv.slice(2));`,
|
||||
].join(`\n`));
|
||||
fs.chmodSync(corepackPath, 0o755);
|
||||
|
@ -34,6 +35,7 @@ async function main() {
|
|||
const entryScript = [
|
||||
`#!/usr/bin/env node`,
|
||||
`process.env.COREPACK_ENABLE_DOWNLOAD_PROMPT??='1'`,
|
||||
`require('module').enableCompileCache?.();`,
|
||||
`require('./lib/corepack.cjs').runMain(['${binaryName}', ...process.argv.slice(2)]);`,
|
||||
].join(`\n`);
|
||||
|
||||
|
|
37
package.json
37
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "corepack",
|
||||
"version": "0.29.2",
|
||||
"version": "0.33.0",
|
||||
"homepage": "https://github.com/nodejs/corepack#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nodejs/corepack/issues"
|
||||
|
@ -10,44 +10,37 @@
|
|||
"url": "https://github.com/nodejs/corepack.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.1 || >=20.10.0"
|
||||
"node": "^20.10.0 || ^22.11.0 || >=24.0.0"
|
||||
},
|
||||
"exports": {
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"license": "MIT",
|
||||
"packageManager": "yarn@4.3.1+sha224.934d21773e22af4b69a7032a2d3b4cb38c1f7c019624777cc9916b23",
|
||||
"packageManager": "yarn@4.9.0+sha224.dce6c5df199861784bd9b0eecb2a228df97e3f18a02b1bb75ff98383",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.14.3",
|
||||
"@babel/plugin-transform-modules-commonjs": "^7.14.0",
|
||||
"@babel/preset-typescript": "^7.13.0",
|
||||
"@jest/globals": "^29.0.0",
|
||||
"@types/debug": "^4.1.5",
|
||||
"@types/jest": "^29.0.0",
|
||||
"@types/node": "^20.4.6",
|
||||
"@types/proxy-from-env": "^1",
|
||||
"@types/semver": "^7.1.0",
|
||||
"@types/tar": "^6.0.0",
|
||||
"@types/which": "^3.0.0",
|
||||
"@yarnpkg/eslint-config": "^2.0.0",
|
||||
"@yarnpkg/eslint-config": "^3.0.0",
|
||||
"@yarnpkg/fslib": "^3.0.0-rc.48",
|
||||
"@zkochan/cmd-shim": "^6.0.0",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||
"better-sqlite3": "^10.0.0",
|
||||
"clipanion": "^3.0.1",
|
||||
"better-sqlite3": "^11.7.2",
|
||||
"clipanion": "patch:clipanion@npm%3A3.2.1#~/.yarn/patches/clipanion-npm-3.2.1-fc9187f56c.patch",
|
||||
"debug": "^4.1.1",
|
||||
"esbuild": "^0.21.0",
|
||||
"eslint": "^8.57.0",
|
||||
"jest": "^29.0.0",
|
||||
"esbuild": "^0.25.0",
|
||||
"eslint": "^9.22.0",
|
||||
"proxy-from-env": "^1.1.0",
|
||||
"semver": "^7.5.2",
|
||||
"supports-color": "^9.0.0",
|
||||
"tar": "^6.2.1",
|
||||
"semver": "^7.6.3",
|
||||
"supports-color": "^10.0.0",
|
||||
"tar": "^7.4.0",
|
||||
"tsx": "^4.16.2",
|
||||
"typescript": "^5.3.3",
|
||||
"typescript": "^5.7.3",
|
||||
"undici": "^6.19.2",
|
||||
"v8-compile-cache": "^2.3.0",
|
||||
"which": "^4.0.0"
|
||||
"vitest": "^3.0.5",
|
||||
"which": "^5.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"undici-types": "6.x"
|
||||
|
@ -62,7 +55,7 @@
|
|||
"postpack": "run clean",
|
||||
"rimraf": "node -e 'for(let i=2;i<process.argv.length;i++)fs.rmSync(process.argv[i],{recursive:true,force:true});'",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "jest"
|
||||
"test": "vitest"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
|
|
@ -14,9 +14,9 @@ import * as folderUtils from './folderUtil
|
|||
import type {NodeError} from './nodeUtils';
|
||||
import * as semverUtils from './semverUtils';
|
||||
import * as specUtils from './specUtils';
|
||||
import {Config, Descriptor, Locator, PackageManagerSpec} from './types';
|
||||
import {Config, Descriptor, LazyLocator, Locator} from './types';
|
||||
import {SupportedPackageManagers, SupportedPackageManagerSet} from './types';
|
||||
import {isSupportedPackageManager} from './types';
|
||||
import {isSupportedPackageManager, PackageManagerSpec} from './types';
|
||||
|
||||
export type PreparedPackageManagerInfo = Awaited<ReturnType<Engine[`ensurePackageManager`]>>;
|
||||
|
||||
|
@ -27,7 +27,9 @@ export type PackageManagerRequest = {
|
|||
};
|
||||
|
||||
function getLastKnownGoodFilePath() {
|
||||
return path.join(folderUtils.getCorepackHomeFolder(), `lastKnownGood.json`);
|
||||
const lkg = path.join(folderUtils.getCorepackHomeFolder(), `lastKnownGood.json`);
|
||||
debugUtils.log(`LastKnownGood file would be located at ${lkg}`);
|
||||
return lkg;
|
||||
}
|
||||
|
||||
export async function getLastKnownGood(): Promise<Record<string, string>> {
|
||||
|
@ -35,23 +37,34 @@ export async function getLastKnownGood(): Promise<Record<string, string>> {
|
|||
try {
|
||||
raw = await fs.promises.readFile(getLastKnownGoodFilePath(), `utf8`);
|
||||
} catch (err) {
|
||||
if ((err as NodeError)?.code === `ENOENT`) return {};
|
||||
if ((err as NodeError)?.code === `ENOENT`) {
|
||||
debugUtils.log(`No LastKnownGood version found in Corepack home.`);
|
||||
return {};
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(raw);
|
||||
if (!parsed) return {};
|
||||
if (typeof parsed !== `object`) return {};
|
||||
if (!parsed) {
|
||||
debugUtils.log(`Invalid LastKnowGood file in Corepack home (JSON parsable, but falsy)`);
|
||||
return {};
|
||||
}
|
||||
if (typeof parsed !== `object`) {
|
||||
debugUtils.log(`Invalid LastKnowGood file in Corepack home (JSON parsable, but non-object)`);
|
||||
return {};
|
||||
}
|
||||
Object.entries(parsed).forEach(([key, value]) => {
|
||||
if (typeof value !== `string`) {
|
||||
// Ensure that all entries are strings.
|
||||
debugUtils.log(`Ignoring key ${key} in LastKnownGood file as its value is not a string`);
|
||||
delete parsed[key];
|
||||
}
|
||||
});
|
||||
return parsed;
|
||||
} catch {
|
||||
// Ignore errors; too bad
|
||||
debugUtils.log(`Invalid LastKnowGood file in Corepack home (maybe not JSON parsable)`);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
@ -161,13 +174,18 @@ export class Engine {
|
|||
|
||||
const lastKnownGood = await getLastKnownGood();
|
||||
const lastKnownGoodForThisPackageManager = getLastKnownGoodFromFileContent(lastKnownGood, packageManager);
|
||||
if (lastKnownGoodForThisPackageManager)
|
||||
if (lastKnownGoodForThisPackageManager) {
|
||||
debugUtils.log(`Search for default version: Found ${packageManager}@${lastKnownGoodForThisPackageManager} in LastKnownGood file`);
|
||||
return lastKnownGoodForThisPackageManager;
|
||||
}
|
||||
|
||||
if (process.env.COREPACK_DEFAULT_TO_LATEST === `0`)
|
||||
if (process.env.COREPACK_DEFAULT_TO_LATEST === `0`) {
|
||||
debugUtils.log(`Search for default version: As defined in environment, defaulting to internal config ${packageManager}@${definition.default}`);
|
||||
return definition.default;
|
||||
}
|
||||
|
||||
const reference = await corepackUtils.fetchLatestStableVersion(definition.fetchLatestFrom);
|
||||
debugUtils.log(`Search for default version: found in remote registry ${packageManager}@${reference}`);
|
||||
|
||||
try {
|
||||
await activatePackageManager(lastKnownGood, {
|
||||
|
@ -175,6 +193,7 @@ export class Engine {
|
|||
reference,
|
||||
});
|
||||
} catch {
|
||||
debugUtils.log(`Search for default version: could not activate registry version`);
|
||||
// If for some reason, we cannot update the last known good file, we
|
||||
// ignore the error.
|
||||
}
|
||||
|
@ -218,19 +237,23 @@ export class Engine {
|
|||
*
|
||||
* If the project doesn't include a specification file, we just assume that
|
||||
* whatever the user uses is exactly what they want to use. Since the version
|
||||
* isn't explicited, we fallback on known good versions.
|
||||
* isn't specified, we fallback on known good versions.
|
||||
*
|
||||
* Finally, if the project doesn't exist at all, we ask the user whether they
|
||||
* want to create one in the current project. If they do, we initialize a new
|
||||
* project using the default package managers, and configure it so that we
|
||||
* don't need to ask again in the future.
|
||||
*/
|
||||
async findProjectSpec(initialCwd: string, locator: Locator, {transparent = false}: {transparent?: boolean} = {}): Promise<Descriptor> {
|
||||
async findProjectSpec(initialCwd: string, locator: Locator | LazyLocator, {transparent = false}: {transparent?: boolean} = {}): Promise<Descriptor> {
|
||||
// A locator is a valid descriptor (but not the other way around)
|
||||
const fallbackDescriptor = {name: locator.name, range: `${locator.reference}`};
|
||||
|
||||
if (process.env.COREPACK_ENABLE_PROJECT_SPEC === `0`)
|
||||
if (process.env.COREPACK_ENABLE_PROJECT_SPEC === `0`) {
|
||||
if (typeof locator.reference === `function`)
|
||||
fallbackDescriptor.range = await locator.reference();
|
||||
|
||||
return fallbackDescriptor;
|
||||
}
|
||||
|
||||
if (process.env.COREPACK_ENABLE_STRICT === `0`)
|
||||
transparent = true;
|
||||
|
@ -239,11 +262,19 @@ export class Engine {
|
|||
const result = await specUtils.loadSpec(initialCwd);
|
||||
|
||||
switch (result.type) {
|
||||
case `NoProject`:
|
||||
case `NoProject`: {
|
||||
if (typeof locator.reference === `function`)
|
||||
fallbackDescriptor.range = await locator.reference();
|
||||
|
||||
debugUtils.log(`Falling back to ${fallbackDescriptor.name}@${fallbackDescriptor.range} as no project manifest were found`);
|
||||
return fallbackDescriptor;
|
||||
}
|
||||
|
||||
case `NoSpec`: {
|
||||
if (process.env.COREPACK_ENABLE_AUTO_PIN !== `0`) {
|
||||
if (typeof locator.reference === `function`)
|
||||
fallbackDescriptor.range = await locator.reference();
|
||||
|
||||
if (process.env.COREPACK_ENABLE_AUTO_PIN === `1`) {
|
||||
const resolved = await this.resolveDescriptor(fallbackDescriptor, {allowTags: true});
|
||||
if (resolved === null)
|
||||
throw new UsageError(`Failed to successfully resolve '${fallbackDescriptor.range}' to a valid ${fallbackDescriptor.name} release`);
|
||||
|
@ -257,18 +288,25 @@ export class Engine {
|
|||
await specUtils.setLocalPackageManager(path.dirname(result.target), installSpec);
|
||||
}
|
||||
|
||||
debugUtils.log(`Falling back to ${fallbackDescriptor.name}@${fallbackDescriptor.range} in the absence of "packageManager" field in ${result.target}`);
|
||||
return fallbackDescriptor;
|
||||
}
|
||||
|
||||
case `Found`: {
|
||||
if (result.spec.name !== locator.name) {
|
||||
const spec = result.getSpec();
|
||||
if (spec.name !== locator.name) {
|
||||
if (transparent) {
|
||||
if (typeof locator.reference === `function`)
|
||||
fallbackDescriptor.range = await locator.reference();
|
||||
|
||||
debugUtils.log(`Falling back to ${fallbackDescriptor.name}@${fallbackDescriptor.range} in a ${spec.name}@${spec.range} project`);
|
||||
return fallbackDescriptor;
|
||||
} else {
|
||||
throw new UsageError(`This project is configured to use ${result.spec.name} because ${result.target} has a "packageManager" field`);
|
||||
throw new UsageError(`This project is configured to use ${spec.name} because ${result.target} has a "packageManager" field`);
|
||||
}
|
||||
} else {
|
||||
return result.spec;
|
||||
debugUtils.log(`Using ${spec.name}@${spec.range} as defined in project manifest ${result.target}`);
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -276,14 +314,14 @@ export class Engine {
|
|||
}
|
||||
|
||||
async executePackageManagerRequest({packageManager, binaryName, binaryVersion}: PackageManagerRequest, {cwd, args}: {cwd: string, args: Array<string>}): Promise<void> {
|
||||
let fallbackLocator: Locator = {
|
||||
let fallbackLocator: Locator | LazyLocator = {
|
||||
name: binaryName as SupportedPackageManagers,
|
||||
reference: undefined as any,
|
||||
};
|
||||
|
||||
let isTransparentCommand = false;
|
||||
if (packageManager != null) {
|
||||
const defaultVersion = binaryVersion || await this.getDefaultVersion(packageManager);
|
||||
const defaultVersion = binaryVersion || (() => this.getDefaultVersion(packageManager));
|
||||
const definition = this.config.definitions[packageManager]!;
|
||||
|
||||
// If all leading segments match one of the patterns defined in the `transparent`
|
||||
|
@ -302,7 +340,7 @@ export class Engine {
|
|||
|
||||
fallbackLocator = {
|
||||
name: packageManager,
|
||||
reference: fallbackReference,
|
||||
reference: fallbackReference as string,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -13,13 +13,13 @@ export abstract class BaseCommand extends Command<Context> {
|
|||
const lookup = await specUtils.loadSpec(this.context.cwd);
|
||||
switch (lookup.type) {
|
||||
case `NoProject`:
|
||||
throw new UsageError(`Couldn't find a project in the local directory - please explicit the package manager to pack, or run this command from a valid project`);
|
||||
throw new UsageError(`Couldn't find a project in the local directory - please specify the package manager to pack, or run this command from a valid project`);
|
||||
|
||||
case `NoSpec`:
|
||||
throw new UsageError(`The local project doesn't feature a 'packageManager' field - please explicit the package manager to pack, or update the manifest to reference it`);
|
||||
throw new UsageError(`The local project doesn't feature a 'packageManager' field nor a 'devEngines.packageManager' field - please specify the package manager to pack, or update the manifest to reference it`);
|
||||
|
||||
default: {
|
||||
return [lookup.spec];
|
||||
return [lookup.range ?? lookup.getSpec()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import fs from 'f
|
|||
import path from 'path';
|
||||
import which from 'which';
|
||||
|
||||
import * as corepackUtils from '../corepackUtils';
|
||||
import {Context} from '../main';
|
||||
import type {NodeError} from '../nodeUtils';
|
||||
import {isSupportedPackageManager, SupportedPackageManagerSetWithoutNpm} from '../types';
|
||||
|
@ -70,6 +71,11 @@ export class DisableCommand extends Command<Context> {
|
|||
async removePosixLink(installDirectory: string, binName: string) {
|
||||
const file = path.join(installDirectory, binName);
|
||||
try {
|
||||
if (binName.includes(`yarn`) && corepackUtils.isYarnSwitchPath(await fs.promises.realpath(file))) {
|
||||
console.warn(`${binName} is already installed in ${file} and points to a Yarn Switch install - skipping`);
|
||||
return;
|
||||
}
|
||||
|
||||
await fs.promises.unlink(file);
|
||||
} catch (err) {
|
||||
if ((err as NodeError).code !== `ENOENT`) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import fs from 'f
|
|||
import path from 'path';
|
||||
import which from 'which';
|
||||
|
||||
import * as corepackUtils from '../corepackUtils';
|
||||
import {Context} from '../main';
|
||||
import {isSupportedPackageManager, SupportedPackageManagerSetWithoutNpm} from '../types';
|
||||
|
||||
|
@ -13,7 +14,7 @@ export class EnableCommand extends Command<Context> {
|
|||
];
|
||||
|
||||
static usage = Command.Usage({
|
||||
description: `Add the Corepack shims to the install directories`,
|
||||
description: `Add the Corepack shims to the install directory`,
|
||||
details: `
|
||||
When run, this command will check whether the shims for the specified package managers can be found with the correct values inside the install directory. If not, or if they don't exist, they will be created.
|
||||
|
||||
|
@ -83,6 +84,12 @@ export class EnableCommand extends Command<Context> {
|
|||
|
||||
if (fs.existsSync(file)) {
|
||||
const currentSymlink = await fs.promises.readlink(file);
|
||||
|
||||
if (binName.includes(`yarn`) && corepackUtils.isYarnSwitchPath(await fs.promises.realpath(file))) {
|
||||
console.warn(`${binName} is already installed in ${file} and points to a Yarn Switch install - skipping`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentSymlink !== symlink) {
|
||||
await fs.promises.unlink(file);
|
||||
} else {
|
||||
|
|
|
@ -77,11 +77,11 @@ export class InstallGlobalCommand extends BaseCommand {
|
|||
const installFolder = folderUtils.getInstallFolder();
|
||||
|
||||
const archiveEntries = new Map<string, Set<string>>();
|
||||
const {default: tar} = await import(`tar`);
|
||||
const {list: tarT} = await import(`tar/list`);
|
||||
|
||||
let hasShortEntries = false;
|
||||
|
||||
await tar.t({file: p, onentry: entry => {
|
||||
await tarT({file: p, onentry: entry => {
|
||||
const segments = entry.path.split(/\//g);
|
||||
if (segments.length > 0 && segments[segments.length - 1] !== `.corepack`)
|
||||
return;
|
||||
|
@ -100,6 +100,8 @@ export class InstallGlobalCommand extends BaseCommand {
|
|||
if (hasShortEntries || archiveEntries.size < 1)
|
||||
throw new UsageError(`Invalid archive format; did it get generated by 'corepack pack'?`);
|
||||
|
||||
const {extract: tarX} = await import(`tar/extract`);
|
||||
|
||||
for (const [name, references] of archiveEntries) {
|
||||
for (const reference of references) {
|
||||
if (!isSupportedPackageManager(name))
|
||||
|
@ -110,7 +112,7 @@ export class InstallGlobalCommand extends BaseCommand {
|
|||
// Recreate the folder in case it was deleted somewhere else:
|
||||
await fs.promises.mkdir(installFolder, {recursive: true});
|
||||
|
||||
await tar.x({file: p, cwd: installFolder}, [`${name}/${reference}`]);
|
||||
await tarX({file: p, cwd: installFolder}, [`${name}/${reference}`]);
|
||||
|
||||
if (!this.cacheOnly) {
|
||||
await this.context.engine.activatePackageManager({name, reference});
|
||||
|
|
|
@ -62,11 +62,11 @@ export class PackCommand extends BaseCommand {
|
|||
this.context.stdout.write(`Packing the selected tools in ${path.basename(outputPath)}...\n`);
|
||||
}
|
||||
|
||||
const {default: tar} = await import(`tar`);
|
||||
const {create: tarC} = await import(`tar/create`);
|
||||
|
||||
// Recreate the folder in case it was deleted somewhere else:
|
||||
await mkdir(baseInstallFolder, {recursive: true});
|
||||
await tar.c({gzip: true, cwd: baseInstallFolder, file: path.resolve(outputPath)}, installLocations.map(location => {
|
||||
await tarC({gzip: true, cwd: baseInstallFolder, file: path.resolve(outputPath)}, installLocations.map(location => {
|
||||
return path.relative(baseInstallFolder, location);
|
||||
}));
|
||||
|
||||
|
|
|
@ -24,9 +24,9 @@ export class HydrateCommand extends Command<Context> {
|
|||
const archiveEntries = new Map<string, Set<string>>();
|
||||
let hasShortEntries = false;
|
||||
|
||||
const {default: tar} = await import(`tar`);
|
||||
const {list: tarT} = await import(`tar/list`);
|
||||
|
||||
await tar.t({file: fileName, onentry: entry => {
|
||||
await tarT({file: fileName, onentry: entry => {
|
||||
const segments = entry.path.split(/\//g);
|
||||
|
||||
if (segments.length < 3) {
|
||||
|
@ -43,6 +43,8 @@ export class HydrateCommand extends Command<Context> {
|
|||
if (hasShortEntries || archiveEntries.size < 1)
|
||||
throw new UsageError(`Invalid archive format; did it get generated by 'corepack prepare'?`);
|
||||
|
||||
const {extract: tarX} = await import(`tar/extract`);
|
||||
|
||||
for (const [name, references] of archiveEntries) {
|
||||
for (const reference of references) {
|
||||
if (!isSupportedPackageManager(name))
|
||||
|
@ -56,7 +58,7 @@ export class HydrateCommand extends Command<Context> {
|
|||
// Recreate the folder in case it was deleted somewhere else:
|
||||
await mkdir(installFolder, {recursive: true});
|
||||
|
||||
await tar.x({file: fileName, cwd: installFolder}, [`${name}/${reference}`]);
|
||||
await tarX({file: fileName, cwd: installFolder}, [`${name}/${reference}`]);
|
||||
|
||||
if (this.activate) {
|
||||
await this.context.engine.activatePackageManager({name, reference});
|
||||
|
|
|
@ -36,13 +36,13 @@ export class PrepareCommand extends Command<Context> {
|
|||
const lookup = await specUtils.loadSpec(this.context.cwd);
|
||||
switch (lookup.type) {
|
||||
case `NoProject`:
|
||||
throw new UsageError(`Couldn't find a project in the local directory - please explicit the package manager to pack, or run this command from a valid project`);
|
||||
throw new UsageError(`Couldn't find a project in the local directory - please specify the package manager to pack, or run this command from a valid project`);
|
||||
|
||||
case `NoSpec`:
|
||||
throw new UsageError(`The local project doesn't feature a 'packageManager' field - please explicit the package manager to pack, or update the manifest to reference it`);
|
||||
throw new UsageError(`The local project doesn't feature a 'packageManager' field - please specify the package manager to pack, or update the manifest to reference it`);
|
||||
|
||||
default: {
|
||||
specs.push(lookup.spec);
|
||||
specs.push(lookup.getSpec());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,10 +83,10 @@ export class PrepareCommand extends Command<Context> {
|
|||
if (!this.json)
|
||||
this.context.stdout.write(`Packing the selected tools in ${path.basename(outputPath)}...\n`);
|
||||
|
||||
const {default: tar} = await import(`tar`);
|
||||
const {create: tarC} = await import(`tar/create`);
|
||||
// Recreate the folder in case it was deleted somewhere else:
|
||||
await mkdir(baseInstallFolder, {recursive: true});
|
||||
await tar.c({gzip: true, cwd: baseInstallFolder, file: path.resolve(outputPath)}, installLocations.map(location => {
|
||||
await tarC({gzip: true, cwd: baseInstallFolder, file: path.resolve(outputPath)}, installLocations.map(location => {
|
||||
return path.relative(baseInstallFolder, location);
|
||||
}));
|
||||
|
||||
|
|
|
@ -19,6 +19,12 @@ import * as npmRegistryUtils from './npmRegist
|
|||
import {RegistrySpec, Descriptor, Locator, PackageManagerSpec} from './types';
|
||||
import {BinList, BinSpec, InstallSpec, DownloadSpec} from './types';
|
||||
|
||||
const YARN_SWITCH_REGEX = /[/\\]switch[/\\]bin[/\\]/;
|
||||
|
||||
export function isYarnSwitchPath(p: string) {
|
||||
return YARN_SWITCH_REGEX.test(p);
|
||||
}
|
||||
|
||||
export function getRegistryFromPackageManagerSpec(spec: PackageManagerSpec) {
|
||||
return process.env.COREPACK_NPM_REGISTRY
|
||||
? spec.npmRegistry ?? spec.registry
|
||||
|
@ -151,8 +157,8 @@ async function download(installTarget: string, url: string, algo: string, binPat
|
|||
let sendTo: any;
|
||||
|
||||
if (ext === `.tgz`) {
|
||||
const {default: tar} = await import(`tar`);
|
||||
sendTo = tar.x({
|
||||
const {extract: tarX} = await import(`tar/extract`);
|
||||
sendTo = tarX({
|
||||
strip: 1,
|
||||
cwd: tmpFolder,
|
||||
filter: binPath ? path => {
|
||||
|
@ -207,7 +213,7 @@ export async function installVersion(installTarget: string, locator: Locator, {s
|
|||
|
||||
const corepackData = JSON.parse(corepackContent);
|
||||
|
||||
debugUtils.log(`Reusing ${locator.name}@${locator.reference}`);
|
||||
debugUtils.log(`Reusing ${locator.name}@${locator.reference} found in ${installFolder}`);
|
||||
|
||||
return {
|
||||
hash: corepackData.hash as string,
|
||||
|
@ -333,7 +339,7 @@ export async function installVersion(installTarget: string, locator: Locator, {s
|
|||
}
|
||||
}
|
||||
|
||||
debugUtils.log(`Install finished`);
|
||||
debugUtils.log(`Download and install of ${locator.name}@${locator.reference} is finished`);
|
||||
|
||||
return {
|
||||
location: installFolder,
|
||||
|
@ -400,12 +406,16 @@ export async function runVersion(locator: Locator, installSpec: InstallSpec & {s
|
|||
if (!binPath)
|
||||
throw new Error(`Assertion failed: Unable to locate path for bin '${binName}'`);
|
||||
|
||||
// Node.js segfaults when using npm@>=9.7.0 and v8-compile-cache
|
||||
// $ docker run -it node:20.3.0-slim corepack npm@9.7.1 --version
|
||||
// [SIGSEGV]
|
||||
if (locator.name !== `npm` || semverLt(locator.reference, `9.7.0`))
|
||||
// @ts-expect-error - No types
|
||||
await import(`v8-compile-cache`);
|
||||
// @ts-expect-error - Missing types
|
||||
if (!Module.enableCompileCache) {
|
||||
// Node.js segfaults when using npm@>=9.7.0 and v8-compile-cache
|
||||
// $ docker run -it node:20.3.0-slim corepack npm@9.7.1 --version
|
||||
// [SIGSEGV]
|
||||
if (locator.name !== `npm` || semverLt(locator.reference, `9.7.0`)) {
|
||||
// @ts-expect-error - No types
|
||||
await import(`v8-compile-cache`);
|
||||
}
|
||||
}
|
||||
|
||||
// We load the binary into the current process,
|
||||
// while making it think it was spawned.
|
||||
|
@ -429,6 +439,12 @@ export async function runVersion(locator: Locator, installSpec: InstallSpec & {s
|
|||
// Use nextTick to unwind the stack, and consequently remove Corepack from
|
||||
// the stack trace of the package manager.
|
||||
process.nextTick(Module.runMain, binPath);
|
||||
|
||||
// @ts-expect-error - No types
|
||||
if (Module.flushCompileCache) {
|
||||
// @ts-expect-error - No types
|
||||
setImmediate(Module.flushCompileCache);
|
||||
}
|
||||
}
|
||||
|
||||
export function shouldSkipIntegrityCheck() {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import {BaseContext, Builtins, Cli} from 'clipanion';
|
||||
import type {UsageError} from 'clipanion';
|
||||
|
||||
import {version as corepackVersion} from '../package.json';
|
||||
|
||||
|
@ -37,6 +38,10 @@ function getPackageManagerRequestFromCli(parameter: string | undefined, engine:
|
|||
};
|
||||
}
|
||||
|
||||
function isUsageError(error: any): error is UsageError {
|
||||
return error?.name === `UsageError`;
|
||||
}
|
||||
|
||||
export async function runMain(argv: Array<string>) {
|
||||
const engine = new Engine();
|
||||
|
||||
|
@ -79,9 +84,17 @@ export async function runMain(argv: Array<string>) {
|
|||
process.exitCode ??= code;
|
||||
}
|
||||
} else {
|
||||
await engine.executePackageManagerRequest(request, {
|
||||
cwd: process.cwd(),
|
||||
args: restArgs,
|
||||
});
|
||||
try {
|
||||
await engine.executePackageManagerRequest(request, {
|
||||
cwd: process.cwd(),
|
||||
args: restArgs,
|
||||
});
|
||||
} catch (error) {
|
||||
if (isUsageError(error)) {
|
||||
console.error(error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,19 +38,27 @@ export function verifySignature({signatures, integrity, packageName, version}: {
|
|||
packageName: string;
|
||||
version: string;
|
||||
}) {
|
||||
const {npm: keys} = process.env.COREPACK_INTEGRITY_KEYS ?
|
||||
if (!Array.isArray(signatures) || !signatures.length) throw new Error(`No compatible signature found in package metadata`);
|
||||
|
||||
const {npm: trustedKeys} = process.env.COREPACK_INTEGRITY_KEYS ?
|
||||
JSON.parse(process.env.COREPACK_INTEGRITY_KEYS) as typeof defaultConfig.keys :
|
||||
defaultConfig.keys;
|
||||
|
||||
const key = keys.find(({keyid}) => signatures.some(s => s.keyid === keyid));
|
||||
const signature = signatures.find(({keyid}) => keyid === key?.keyid);
|
||||
|
||||
if (key == null || signature == null) throw new Error(`Cannot find matching keyid: ${JSON.stringify({signatures, keys})}`);
|
||||
let signature: typeof signatures[0] | undefined;
|
||||
let key!: string;
|
||||
for (const k of trustedKeys) {
|
||||
signature = signatures.find(({keyid}) => keyid === k.keyid);
|
||||
if (signature != null) {
|
||||
key = k.key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (signature?.sig == null) throw new UsageError(`The package was not signed by any trusted keys: ${JSON.stringify({signatures, trustedKeys}, undefined, 2)}`);
|
||||
|
||||
const verifier = createVerify(`SHA256`);
|
||||
verifier.end(`${packageName}@${version}:${integrity}`);
|
||||
const valid = verifier.verify(
|
||||
`-----BEGIN PUBLIC KEY-----\n${key.key}\n-----END PUBLIC KEY-----`,
|
||||
`-----BEGIN PUBLIC KEY-----\n${key}\n-----END PUBLIC KEY-----`,
|
||||
signature.sig,
|
||||
`base64`,
|
||||
);
|
||||
|
@ -62,16 +70,25 @@ export function verifySignature({signatures, integrity, packageName, version}: {
|
|||
export async function fetchLatestStableVersion(packageName: string) {
|
||||
const metadata = await fetchAsJson(packageName, `latest`);
|
||||
|
||||
const {version, dist: {integrity, signatures}} = metadata;
|
||||
const {version, dist: {integrity, signatures, shasum}} = metadata;
|
||||
|
||||
if (!shouldSkipIntegrityCheck()) {
|
||||
verifySignature({
|
||||
packageName, version,
|
||||
integrity, signatures,
|
||||
});
|
||||
try {
|
||||
verifySignature({
|
||||
packageName, version,
|
||||
integrity, signatures,
|
||||
});
|
||||
} catch (cause) {
|
||||
// TODO: consider switching to `UsageError` when https://github.com/arcanis/clipanion/issues/157 is fixed
|
||||
throw new Error(`Corepack cannot download the latest stable version of ${packageName}; you can disable signature verification by setting COREPACK_INTEGRITY_CHECK to 0 in your env, or instruct Corepack to use the latest stable release known by this version of Corepack by setting COREPACK_USE_LATEST to 0`, {cause});
|
||||
}
|
||||
}
|
||||
|
||||
return `${version}+sha512.${Buffer.from(integrity.slice(7), `base64`).toString(`hex`)}`;
|
||||
return `${version}+${
|
||||
integrity ?
|
||||
`sha512.${Buffer.from(integrity.slice(7), `base64`).toString(`hex`)}` :
|
||||
`sha1.${shasum}`
|
||||
}`;
|
||||
}
|
||||
|
||||
export async function fetchAvailableTags(packageName: string) {
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
import {UsageError} from 'clipanion';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import semverSatisfies from 'semver/functions/satisfies';
|
||||
import semverValid from 'semver/functions/valid';
|
||||
import semverValidRange from 'semver/ranges/valid';
|
||||
import {parseEnv} from 'util';
|
||||
|
||||
import {PreparedPackageManagerInfo} from './Engine';
|
||||
import * as debugUtils from './debugUtils';
|
||||
import {NodeError} from './nodeUtils';
|
||||
import * as nodeUtils from './nodeUtils';
|
||||
import {Descriptor, isSupportedPackageManager} from './types';
|
||||
import type {LocalEnvFile} from './types';
|
||||
|
||||
const nodeModulesRegExp = /[\\/]node_modules[\\/](@[^\\/]*[\\/])?([^@\\/][^\\/]*)$/;
|
||||
|
||||
|
@ -51,16 +56,87 @@ export function parseSpec(raw: unknown, source: string, {enforceExactVersion = t
|
|||
};
|
||||
}
|
||||
|
||||
type CorepackPackageJSON = {
|
||||
packageManager?: string;
|
||||
devEngines?: {packageManager?: DevEngineDependency};
|
||||
};
|
||||
|
||||
interface DevEngineDependency {
|
||||
name: string;
|
||||
version: string;
|
||||
onFail?: `ignore` | `warn` | `error`;
|
||||
}
|
||||
function warnOrThrow(errorMessage: string, onFail?: DevEngineDependency[`onFail`]) {
|
||||
switch (onFail) {
|
||||
case `ignore`:
|
||||
break;
|
||||
case `error`:
|
||||
case undefined:
|
||||
throw new UsageError(errorMessage);
|
||||
default:
|
||||
console.warn(`! Corepack validation warning: ${errorMessage}`);
|
||||
}
|
||||
}
|
||||
function parsePackageJSON(packageJSONContent: CorepackPackageJSON) {
|
||||
const {packageManager: pm} = packageJSONContent;
|
||||
if (packageJSONContent.devEngines?.packageManager != null) {
|
||||
const {packageManager} = packageJSONContent.devEngines;
|
||||
|
||||
if (typeof packageManager !== `object`) {
|
||||
console.warn(`! Corepack only supports objects as valid value for devEngines.packageManager. The current value (${JSON.stringify(packageManager)}) will be ignored.`);
|
||||
return pm;
|
||||
}
|
||||
if (Array.isArray(packageManager)) {
|
||||
console.warn(`! Corepack does not currently support array values for devEngines.packageManager`);
|
||||
return pm;
|
||||
}
|
||||
|
||||
const {name, version, onFail} = packageManager;
|
||||
if (typeof name !== `string` || name.includes(`@`)) {
|
||||
warnOrThrow(`The value of devEngines.packageManager.name ${JSON.stringify(name)} is not a supported string value`, onFail);
|
||||
return pm;
|
||||
}
|
||||
if (version != null && (typeof version !== `string` || !semverValidRange(version))) {
|
||||
warnOrThrow(`The value of devEngines.packageManager.version ${JSON.stringify(version)} is not a valid semver range`, onFail);
|
||||
return pm;
|
||||
}
|
||||
|
||||
debugUtils.log(`devEngines.packageManager defines that ${name}@${version} is the local package manager`);
|
||||
|
||||
if (pm) {
|
||||
if (!pm.startsWith?.(`${name}@`))
|
||||
warnOrThrow(`"packageManager" field is set to ${JSON.stringify(pm)} which does not match the "devEngines.packageManager" field set to ${JSON.stringify(name)}`, onFail);
|
||||
|
||||
else if (version != null && !semverSatisfies(pm.slice(packageManager.name.length + 1), version))
|
||||
warnOrThrow(`"packageManager" field is set to ${JSON.stringify(pm)} which does not match the value defined in "devEngines.packageManager" for ${JSON.stringify(name)} of ${JSON.stringify(version)}`, onFail);
|
||||
|
||||
return pm;
|
||||
}
|
||||
|
||||
|
||||
return `${name}@${version ?? `*`}`;
|
||||
}
|
||||
|
||||
return pm;
|
||||
}
|
||||
|
||||
export async function setLocalPackageManager(cwd: string, info: PreparedPackageManagerInfo) {
|
||||
const lookup = await loadSpec(cwd);
|
||||
|
||||
const range = `range` in lookup && lookup.range;
|
||||
if (range) {
|
||||
if (info.locator.name !== range.name || !semverSatisfies(info.locator.reference, range.range)) {
|
||||
warnOrThrow(`The requested version of ${info.locator.name}@${info.locator.reference} does not match the devEngines specification (${range.name}@${range.range})`, range.onFail);
|
||||
}
|
||||
}
|
||||
|
||||
const content = lookup.type !== `NoProject`
|
||||
? await fs.promises.readFile(lookup.target, `utf8`)
|
||||
: ``;
|
||||
|
||||
const {data, indent} = nodeUtils.readPackageJson(content);
|
||||
|
||||
const previousPackageManager = data.packageManager ?? `unknown`;
|
||||
const previousPackageManager = data.packageManager ?? (range ? `${range.name}@${range.range}` : `unknown`);
|
||||
data.packageManager = `${info.locator.name}@${info.locator.reference}`;
|
||||
|
||||
const newContent = nodeUtils.normalizeLineEndings(content, `${JSON.stringify(data, null, indent)}\n`);
|
||||
|
@ -71,10 +147,17 @@ export async function setLocalPackageManager(cwd: string, info: PreparedPackageM
|
|||
};
|
||||
}
|
||||
|
||||
interface FoundSpecResult {
|
||||
type: `Found`;
|
||||
target: string;
|
||||
getSpec: () => Descriptor;
|
||||
range?: Descriptor & {onFail?: DevEngineDependency[`onFail`]};
|
||||
envFilePath?: string;
|
||||
}
|
||||
export type LoadSpecResult =
|
||||
| {type: `NoProject`, target: string}
|
||||
| {type: `NoSpec`, target: string}
|
||||
| {type: `Found`, target: string, spec: Descriptor};
|
||||
| FoundSpecResult;
|
||||
|
||||
export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
|
||||
let nextCwd = initialCwd;
|
||||
|
@ -83,6 +166,8 @@ export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
|
|||
let selection: {
|
||||
data: any;
|
||||
manifestPath: string;
|
||||
envFilePath?: string;
|
||||
localEnv: LocalEnvFile;
|
||||
} | null = null;
|
||||
|
||||
while (nextCwd !== currCwd && (!selection || !selection.data.packageManager)) {
|
||||
|
@ -93,6 +178,7 @@ export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
|
|||
continue;
|
||||
|
||||
const manifestPath = path.join(currCwd, `package.json`);
|
||||
debugUtils.log(`Checking ${manifestPath}`);
|
||||
let content: string;
|
||||
try {
|
||||
content = await fs.promises.readFile(manifestPath, `utf8`);
|
||||
|
@ -109,19 +195,60 @@ export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
|
|||
if (typeof data !== `object` || data === null)
|
||||
throw new UsageError(`Invalid package.json in ${path.relative(initialCwd, manifestPath)}`);
|
||||
|
||||
selection = {data, manifestPath};
|
||||
let localEnv: LocalEnvFile;
|
||||
const envFilePath = path.resolve(currCwd, process.env.COREPACK_ENV_FILE ?? `.corepack.env`);
|
||||
if (process.env.COREPACK_ENV_FILE == `0`) {
|
||||
debugUtils.log(`Skipping env file as configured with COREPACK_ENV_FILE`);
|
||||
localEnv = process.env;
|
||||
} else if (typeof parseEnv !== `function`) {
|
||||
// TODO: remove this block when support for Node.js 18.x is dropped.
|
||||
debugUtils.log(`Skipping env file as it is not supported by the current version of Node.js`);
|
||||
localEnv = process.env;
|
||||
} else {
|
||||
debugUtils.log(`Checking ${envFilePath}`);
|
||||
try {
|
||||
localEnv = {
|
||||
...Object.fromEntries(Object.entries(parseEnv(await fs.promises.readFile(envFilePath, `utf8`))).filter(e => e[0].startsWith(`COREPACK_`))),
|
||||
...process.env,
|
||||
};
|
||||
debugUtils.log(`Successfully loaded env file found at ${envFilePath}`);
|
||||
} catch (err) {
|
||||
if ((err as NodeError)?.code !== `ENOENT`)
|
||||
throw err;
|
||||
|
||||
debugUtils.log(`No env file found at ${envFilePath}`);
|
||||
localEnv = process.env;
|
||||
}
|
||||
}
|
||||
|
||||
selection = {data, manifestPath, localEnv, envFilePath};
|
||||
}
|
||||
|
||||
if (selection === null)
|
||||
return {type: `NoProject`, target: path.join(initialCwd, `package.json`)};
|
||||
|
||||
const rawPmSpec = selection.data.packageManager;
|
||||
let envFilePath: string | undefined;
|
||||
if (selection.localEnv !== process.env) {
|
||||
envFilePath = selection.envFilePath;
|
||||
process.env = selection.localEnv;
|
||||
}
|
||||
|
||||
const rawPmSpec = parsePackageJSON(selection.data);
|
||||
if (typeof rawPmSpec === `undefined`)
|
||||
return {type: `NoSpec`, target: selection.manifestPath};
|
||||
|
||||
debugUtils.log(`${selection.manifestPath} defines ${rawPmSpec} as local package manager`);
|
||||
|
||||
return {
|
||||
type: `Found`,
|
||||
target: selection.manifestPath,
|
||||
spec: parseSpec(rawPmSpec, path.relative(initialCwd, selection.manifestPath)),
|
||||
envFilePath,
|
||||
range: selection.data.devEngines?.packageManager?.version && {
|
||||
name: selection.data.devEngines.packageManager.name,
|
||||
range: selection.data.devEngines.packageManager.version,
|
||||
onFail: selection.data.devEngines.packageManager.onFail,
|
||||
},
|
||||
// Lazy-loading it so we do not throw errors on commands that do not need valid spec.
|
||||
getSpec: () => parseSpec(rawPmSpec, path.relative(initialCwd, selection.manifestPath)),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ export interface DownloadSpec {
|
|||
*/
|
||||
export interface Config {
|
||||
definitions: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
|
||||
[name in SupportedPackageManagers]?: {
|
||||
/**
|
||||
* Defines the version that needs to be used when running commands within
|
||||
|
@ -145,3 +145,20 @@ export interface Locator {
|
|||
*/
|
||||
reference: string;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export interface LazyLocator {
|
||||
/**
|
||||
* The name of the package manager required.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The exact version required.
|
||||
*/
|
||||
reference: () => Promise<string>;
|
||||
}
|
||||
|
||||
export type LocalEnvFile = Record<string, string | undefined>;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {describe, beforeEach, it, expect} from '@jest/globals';
|
||||
import {Filename, ppath, xfs, npath} from '@yarnpkg/fslib';
|
||||
import {delimiter} from 'node:path';
|
||||
import process from 'node:process';
|
||||
import {describe, beforeEach, it, expect} from 'vitest';
|
||||
|
||||
import {Engine} from '../sources/Engine';
|
||||
import {SupportedPackageManagerSetWithoutNpm} from '../sources/types';
|
||||
|
@ -97,4 +97,23 @@ describe(`DisableCommand`, () => {
|
|||
await expect(sortedEntries).resolves.toEqual([...binNames].sort());
|
||||
});
|
||||
});
|
||||
|
||||
it(`shouldn't remove Yarn binaries if they are in a /switch/ folder`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.mkdirPromise(ppath.join(cwd, `switch/bin`), {recursive: true});
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `switch/bin/yarn`), `hello`);
|
||||
|
||||
await xfs.linkPromise(
|
||||
ppath.join(cwd, `switch/bin/yarn`),
|
||||
ppath.join(cwd, `yarn`),
|
||||
);
|
||||
|
||||
await expect(runCli(cwd, [`disable`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
});
|
||||
|
||||
const file = await xfs.readFilePromise(ppath.join(cwd, `yarn`), `utf8`);
|
||||
expect(file).toBe(`hello`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {describe, beforeEach, it, expect} from '@jest/globals';
|
||||
import {Filename, ppath, xfs, npath} from '@yarnpkg/fslib';
|
||||
import {delimiter} from 'node:path';
|
||||
import process from 'node:process';
|
||||
import {describe, beforeEach, it, expect, test} from 'vitest';
|
||||
|
||||
import {Engine} from '../sources/Engine';
|
||||
import {SupportedPackageManagers, SupportedPackageManagerSetWithoutNpm} from '../sources/types';
|
||||
|
@ -87,4 +87,42 @@ describe(`EnableCommand`, () => {
|
|||
await expect(sortedEntries).resolves.toEqual(expectedEntries.sort());
|
||||
});
|
||||
});
|
||||
|
||||
test.skipIf(process.platform === `win32`)(`should overwrite existing files`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `yarn`), `hello`);
|
||||
|
||||
process.env.PATH = `${npath.fromPortablePath(cwd)}${delimiter}${process.env.PATH}`;
|
||||
await expect(runCli(cwd, [`enable`])).resolves.toMatchObject({
|
||||
stdout: ``,
|
||||
stderr: ``,
|
||||
exitCode: 0,
|
||||
});
|
||||
|
||||
const file = await xfs.readFilePromise(ppath.join(cwd, `yarn`), `utf8`);
|
||||
expect(file).toBe(`hello`);
|
||||
});
|
||||
});
|
||||
|
||||
test.skipIf(process.platform === `win32`)(`shouldn't overwrite Yarn files if they are in a /switch/ folder`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.mkdirPromise(ppath.join(cwd, `switch/bin`), {recursive: true});
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `switch/bin/yarn`), `hello`);
|
||||
|
||||
await xfs.linkPromise(
|
||||
ppath.join(cwd, `switch/bin/yarn`),
|
||||
ppath.join(cwd, `yarn`),
|
||||
);
|
||||
|
||||
process.env.PATH = `${npath.fromPortablePath(cwd)}${delimiter}${process.env.PATH}`;
|
||||
await expect(runCli(cwd, [`enable`])).resolves.toMatchObject({
|
||||
stdout: ``,
|
||||
stderr: ``,
|
||||
exitCode: 0,
|
||||
});
|
||||
|
||||
const file = await xfs.readFilePromise(ppath.join(cwd, `yarn`), `utf8`);
|
||||
expect(file).toBe(`hello`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
135
tests/Up.test.ts
135
tests/Up.test.ts
|
@ -1,34 +1,135 @@
|
|||
import {describe, beforeEach, it, expect} from '@jest/globals';
|
||||
import {ppath, xfs, npath} from '@yarnpkg/fslib';
|
||||
import process from 'node:process';
|
||||
import {describe, beforeEach, it, expect} from 'vitest';
|
||||
|
||||
import {runCli} from './_runCli';
|
||||
|
||||
beforeEach(async () => {
|
||||
const home = await xfs.mktempPromise();
|
||||
|
||||
// `process.env` is reset after each tests in setupTests.js.
|
||||
process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise());
|
||||
process.env.COREPACK_HOME = npath.fromPortablePath(home);
|
||||
process.env.COREPACK_DEFAULT_TO_LATEST = `0`;
|
||||
|
||||
return async () => {
|
||||
await xfs.removePromise(home, {recursive: true});
|
||||
};
|
||||
});
|
||||
|
||||
describe(`UpCommand`, () => {
|
||||
it(`should upgrade the package manager from the current project`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
packageManager: `yarn@2.1.0`,
|
||||
});
|
||||
describe(`should update the "packageManager" field from the current project`, () => {
|
||||
it(`to the same major if no devEngines range`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
packageManager: `yarn@2.1.0`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`up`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
});
|
||||
await expect(runCli(cwd, [`up`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@2\.4\.3 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
|
||||
});
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `2.4.3\n`,
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `2.4.3\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`to whichever range devEngines defines`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
packageManager: `yarn@1.1.0`,
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `yarn`,
|
||||
version: `1.x || 2.x`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`up`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@2\.4\.3 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `2.4.3\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`to whichever range devEngines defines even if onFail is set to ignore`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
packageManager: `pnpm@10.1.0`,
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `yarn`,
|
||||
version: `1.x || 2.x`,
|
||||
onFail: `ignore`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`up`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@2\.4\.3 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `2.4.3\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`should succeed even if no 'packageManager' field`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
process.env.NO_COLOR = `1`;
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `yarn`,
|
||||
version: `1.x || 2.x`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`up`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@2\.4\.3 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `2.4.3\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,33 +1,116 @@
|
|||
import {describe, beforeEach, it, expect} from '@jest/globals';
|
||||
import {ppath, xfs, npath} from '@yarnpkg/fslib';
|
||||
import process from 'node:process';
|
||||
import {describe, beforeEach, it, expect} from 'vitest';
|
||||
|
||||
import {runCli} from './_runCli';
|
||||
|
||||
beforeEach(async () => {
|
||||
const home = await xfs.mktempPromise();
|
||||
|
||||
// `process.env` is reset after each tests in setupTests.js.
|
||||
process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise());
|
||||
process.env.COREPACK_HOME = npath.fromPortablePath(home);
|
||||
process.env.COREPACK_DEFAULT_TO_LATEST = `0`;
|
||||
|
||||
return async () => {
|
||||
await xfs.removePromise(home, {recursive: true});
|
||||
};
|
||||
});
|
||||
|
||||
describe(`UseCommand`, () => {
|
||||
it(`should set the package manager in the current project`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
packageManager: `yarn@1.0.0`,
|
||||
});
|
||||
describe(`should set the package manager in the current project`, () => {
|
||||
it(`With an existing 'packageManager' field`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
packageManager: `yarn@1.0.0`,
|
||||
license: `MIT`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
});
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: expect.stringMatching(/^Installing yarn@1\.22\.4 in the project\.\.\.\n\n/),
|
||||
stderr: ``,
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@1.22.4+sha512.a1833b862fe52169bd6c2a033045a07df5bc6a23595c259e675fed1b2d035ab37abe6ce309720abb6636d68f03615054b6292dc0a70da31c8697fda228b50d18`,
|
||||
});
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@1.22.4+sha512.a1833b862fe52169bd6c2a033045a07df5bc6a23595c259e675fed1b2d035ab37abe6ce309720abb6636d68f03615054b6292dc0a70da31c8697fda228b50d18`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `1.22.4\n`,
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `1.22.4\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`with 'devEngines.packageManager' field`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
process.env.NO_COLOR = `1`;
|
||||
const devEngines = {packageManager: {name: `yarn`, version: `2.x`}};
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
devEngines,
|
||||
});
|
||||
|
||||
// Should refuse to install an incompatible version:
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: ``,
|
||||
stdout: `Installing yarn@1.22.4 in the project...\nUsage Error: The requested version of yarn@1.22.4+sha512.a1833b862fe52169bd6c2a033045a07df5bc6a23595c259e675fed1b2d035ab37abe6ce309720abb6636d68f03615054b6292dc0a70da31c8697fda228b50d18 does not match the devEngines specification (yarn@2.x)\n\n$ corepack use <pattern>\n`,
|
||||
});
|
||||
|
||||
// Should accept setting to a compatible version:
|
||||
await expect(runCli(cwd, [`use`, `yarn@2.4.3`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@2\.4\.3 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
devEngines,
|
||||
packageManager: `yarn@2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `2.4.3\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`with 'devEngines.packageManager' and 'packageManager' fields`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
process.env.NO_COLOR = `1`;
|
||||
const devEngines = {packageManager: {name: `yarn`, version: `1.x || 2.x`}};
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
devEngines,
|
||||
packageManager: `yarn@1.1.0`,
|
||||
license: `MIT`,
|
||||
});
|
||||
|
||||
// Should refuse to install an incompatible version:
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@1\.22\.4 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
// Should accept setting to a compatible version:
|
||||
await expect(runCli(cwd, [`use`, `yarn@2.4.3`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@2\.4\.3 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
devEngines,
|
||||
packageManager: `yarn@2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `2.4.3\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -64,4 +147,50 @@ describe(`UseCommand`, () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe(`should not care if packageManager is set to an invalid value`, () => {
|
||||
for (const {description, packageManager} of [
|
||||
{
|
||||
description: `when a version range is given`,
|
||||
packageManager: `yarn@1.x`,
|
||||
},
|
||||
{
|
||||
description: `when only the pm name is given`,
|
||||
packageManager: `yarn`,
|
||||
},
|
||||
{
|
||||
description: `when the version is missing`,
|
||||
packageManager: `yarn@`,
|
||||
},
|
||||
{
|
||||
description: `when the field is not a string`,
|
||||
packageManager: [],
|
||||
},
|
||||
]) {
|
||||
it(description, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
packageManager,
|
||||
license: `MIT`, // To avoid warning
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@1\.22\.4 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@1.22.4+sha512.a1833b862fe52169bd6c2a033045a07df5bc6a23595c259e675fed1b2d035ab37abe6ce309720abb6636d68f03615054b6292dc0a70da31c8697fda228b50d18`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `1.22.4\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -79,7 +79,7 @@ const registry = {
|
|||
__proto__: null,
|
||||
yarn: [`1.9998.9999`],
|
||||
pnpm: [`1.9998.9999`],
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
|
||||
'@yarnpkg/cli-dist': [`5.9999.9999`],
|
||||
customPkgManager: [`1.0.0`],
|
||||
};
|
||||
|
@ -87,7 +87,7 @@ const registry = {
|
|||
function generateSignature(packageName, version) {
|
||||
if (privateKey == null) return undefined;
|
||||
const sign = createSign(`SHA256`).end(`${packageName}@${version}:${integrity}`);
|
||||
return {signatures: [{
|
||||
return {integrity, signatures: [{
|
||||
keyid,
|
||||
sig: sign.sign(privateKey, `base64`),
|
||||
}]};
|
||||
|
@ -100,10 +100,8 @@ function generateVersionMetadata(packageName, version) {
|
|||
[packageName]: `./bin/${packageName}.js`,
|
||||
},
|
||||
dist: {
|
||||
integrity,
|
||||
shasum,
|
||||
size: mockPackageTarGz.length,
|
||||
noattachment: false,
|
||||
tarball: `https://registry.npmjs.org/${packageName}/-/${packageName}-${version}.tgz`,
|
||||
...generateSignature(packageName, version),
|
||||
},
|
||||
|
@ -113,6 +111,8 @@ function generateVersionMetadata(packageName, version) {
|
|||
const TOKEN_MOCK = `SOME_DUMMY_VALUE`;
|
||||
|
||||
const server = createServer((req, res) => {
|
||||
res.setHeader(`connection`, `close`);
|
||||
|
||||
const auth = req.headers.authorization;
|
||||
|
||||
if (
|
||||
|
@ -131,7 +131,6 @@ const server = createServer((req, res) => {
|
|||
const packageName = req.url.slice(1, slashPosition === -1 ? undefined : slashPosition);
|
||||
if (packageName in registry) {
|
||||
if (req.url === `/${packageName}`) {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
res.end(JSON.stringify({"dist-tags": {
|
||||
latest: registry[packageName].at(-1),
|
||||
}, versions: Object.fromEntries(registry[packageName].map(version =>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import {jest, describe, it, expect} from '@jest/globals';
|
||||
import {vi, describe, it, expect} from 'vitest';
|
||||
|
||||
import defaultConfig from '../config.json';
|
||||
import {DEFAULT_NPM_REGISTRY_URL} from '../sources/npmRegistryUtils';
|
||||
import defaultConfig from '../config.json';
|
||||
import {DEFAULT_NPM_REGISTRY_URL} from '../sources/npmRegistryUtils';
|
||||
|
||||
jest.mock(`../sources/httpUtils`);
|
||||
vi.mock(`../sources/httpUtils`);
|
||||
|
||||
describe(`key store should be up-to-date`, () => {
|
||||
it(`should contain up-to-date npm keys`, async () => {
|
||||
const r = await globalThis.fetch(new URL(`/-/npm/v1/keys`, DEFAULT_NPM_REGISTRY_URL));
|
||||
expect(r.ok).toBe(true);
|
||||
expect(r.json()).resolves.toMatchObject({keys: defaultConfig.keys.npm});
|
||||
await expect(r.json()).resolves.toMatchObject({keys: defaultConfig.keys.npm});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {describe, it, expect} from '@jest/globals';
|
||||
import {describe, it, expect} from 'vitest';
|
||||
|
||||
import {shouldSkipIntegrityCheck} from '../sources/corepackUtils';
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
BIN
tests/nocks.db
BIN
tests/nocks.db
Binary file not shown.
|
@ -1,15 +1,15 @@
|
|||
import {jest, describe, beforeEach, it, expect} from '@jest/globals';
|
||||
import {Buffer} from 'node:buffer';
|
||||
import process from 'node:process';
|
||||
import {describe, beforeEach, it, expect, vi} from 'vitest';
|
||||
|
||||
import {fetchAsJson as httpFetchAsJson} from '../sources/httpUtils';
|
||||
import {DEFAULT_HEADERS, DEFAULT_NPM_REGISTRY_URL, fetchAsJson} from '../sources/npmRegistryUtils';
|
||||
|
||||
jest.mock(`../sources/httpUtils`);
|
||||
vi.mock(`../sources/httpUtils`);
|
||||
|
||||
describe(`npm registry utils fetchAsJson`, () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
it(`throw usage error if COREPACK_ENABLE_NETWORK env is set to 0`, async () => {
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
/* global jest, beforeEach, afterAll */
|
||||
|
||||
const process = require(`process`);
|
||||
|
||||
jest.retryTimes(2, {logErrorsBeforeRetry: true});
|
||||
import process from 'process';
|
||||
import {beforeEach, afterAll} from 'vitest';
|
||||
|
||||
const OLD_ENV = process.env;
|
||||
// To ensure we test the default behavior, we must remove these env vars
|
||||
// in case the local machine already set these values.
|
||||
const processEnv = Object.fromEntries(
|
||||
Object.entries(process.env).filter(
|
||||
([key]) => key !== `FORCE_COLOR` && !key.startsWith(`COREPACK_`),
|
||||
([key]) => key !== `FORCE_COLOR` && key !== `DEBUG` && !key.startsWith(`COREPACK_`),
|
||||
),
|
||||
);
|
||||
|
|
@ -4,11 +4,11 @@
|
|||
"baseUrl": ".",
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node",
|
||||
"noEmit": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"lib": ["ES2023"],
|
||||
"module": "commonjs",
|
||||
"module": "preserve",
|
||||
"moduleResolution": "bundler",
|
||||
"noEmit": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import {defineConfig} from 'vitest/config';
|
||||
|
||||
// eslint-disable-next-line arca/no-default-export
|
||||
export default defineConfig({
|
||||
test: {
|
||||
setupFiles: [`./tests/setupTests.ts`],
|
||||
testTimeout: 120000,
|
||||
retry: 2,
|
||||
},
|
||||
esbuild: {
|
||||
target: `node${process.versions.node}`,
|
||||
},
|
||||
});
|
Loading…
Reference in New Issue