diff --git a/.gitignore b/.gitignore index 71991ede0..e2dc7341d 100644 --- a/.gitignore +++ b/.gitignore @@ -165,6 +165,9 @@ Cargo.lock # idea .idea/ +# Serena +.serena + *.node lib artifacts diff --git a/packages/core/index.ts b/packages/core/index.ts index c9d7fac55..d38f8f526 100644 --- a/packages/core/index.ts +++ b/packages/core/index.ts @@ -68,7 +68,8 @@ function transformOption(path: string, options?: Options, jest = false): SwcOpti keepImportAttributes: true, }, }, - minify: false, + // Smaller output for cache + minify: true, isModule: true, module: options?.swc?.swcrc ? undefined diff --git a/packages/integrate/__tests__/react-pragma/__snapshots__/react-pragma.spec.ts.md b/packages/integrate/__tests__/react-pragma/__snapshots__/react-pragma.spec.ts.md index b8a057dc8..48132b3f2 100644 --- a/packages/integrate/__tests__/react-pragma/__snapshots__/react-pragma.spec.ts.md +++ b/packages/integrate/__tests__/react-pragma/__snapshots__/react-pragma.spec.ts.md @@ -8,22 +8,12 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 - `"use strict";␊ - const Button = ({ text })=>/*#__PURE__*/ h("div", null, text);␊ - ␊ - //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QudHN4Il0sInNvdXJjZXNDb250ZW50IjpbIlxuICBjb25zdCBCdXR0b24gPSAoeyB0ZXh0IH0pID0+IChcbiAgICA8ZGl2PlxuICAgICAge3RleHR9XG4gICAgPC9kaXY+XG4gIClcbiJdLCJuYW1lcyI6WyJCdXR0b24iLCJ0ZXh0IiwiZGl2Il0sIm1hcHBpbmdzIjoiO0FBQ0UsTUFBTUEsU0FBUyxDQUFDLEVBQUVDLElBQUksRUFBRSxpQkFDdEIsRUFBQ0MsYUFDRUQifQ==` + `"use strict";const Button=({text})=>h("div",null,text);␊ + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QudHN4Il0sInNvdXJjZXNDb250ZW50IjpbIlxuICBjb25zdCBCdXR0b24gPSAoeyB0ZXh0IH0pID0+IChcbiAgICA8ZGl2PlxuICAgICAge3RleHR9XG4gICAgPC9kaXY+XG4gIClcbiJdLCJuYW1lcyI6WyJCdXR0b24iLCJ0ZXh0IiwiZGl2Il0sIm1hcHBpbmdzIjoiYUFDRSxNQUFNQSxPQUFTLENBQUMsQ0FBRUMsSUFBSSxDQUFFLEdBQ3RCLEVBQUNDLFdBQ0VEIn0=` ## should transform jsx into new jsx runtime > Snapshot 1 - `"use strict";␊ - Object.defineProperty(exports, "__esModule", {␊ - value: true␊ - });␊ - const _jsxruntime = require("react/jsx-runtime");␊ - const Button = ({ text })=>/*#__PURE__*/ (0, _jsxruntime.jsx)("div", {␊ - children: text␊ - });␊ - ␊ - //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QudHN4Il0sInNvdXJjZXNDb250ZW50IjpbIlxuICBjb25zdCBCdXR0b24gPSAoeyB0ZXh0IH0pID0+IChcbiAgICA8ZGl2PlxuICAgICAge3RleHR9XG4gICAgPC9kaXY+XG4gIClcbiJdLCJuYW1lcyI6WyJCdXR0b24iLCJ0ZXh0IiwiZGl2Il0sIm1hcHBpbmdzIjoiOzs7OztBQUNFLE1BQU1BLFNBQVMsQ0FBQyxFQUFFQyxJQUFJLEVBQUUsaUJBQ3RCLHFCQUFDQztrQkFDRUQifQ==` + `"use strict";Object.defineProperty(exports,"__esModule",{value:true});const _jsxruntime=require("react/jsx-runtime");const Button=({text})=>(0,_jsxruntime.jsx)("div",{children:text});␊ + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QudHN4Il0sInNvdXJjZXNDb250ZW50IjpbIlxuICBjb25zdCBCdXR0b24gPSAoeyB0ZXh0IH0pID0+IChcbiAgICA8ZGl2PlxuICAgICAge3RleHR9XG4gICAgPC9kaXY+XG4gIClcbiJdLCJuYW1lcyI6WyJCdXR0b24iLCJ0ZXh0IiwiZGl2Il0sIm1hcHBpbmdzIjoicUhBQ0UsTUFBTUEsT0FBUyxDQUFDLENBQUVDLElBQUksQ0FBRSxHQUN0QixvQkFBQ0MsZ0JBQ0VEIn0=` diff --git a/packages/integrate/__tests__/react-pragma/__snapshots__/react-pragma.spec.ts.snap b/packages/integrate/__tests__/react-pragma/__snapshots__/react-pragma.spec.ts.snap index bb8862a00..8c03308b8 100644 Binary files a/packages/integrate/__tests__/react-pragma/__snapshots__/react-pragma.spec.ts.snap and b/packages/integrate/__tests__/react-pragma/__snapshots__/react-pragma.spec.ts.snap differ diff --git a/packages/integrate/__tests__/sourcemaps/__snapshots__/sourcemaps.spec.ts.md b/packages/integrate/__tests__/sourcemaps/__snapshots__/sourcemaps.spec.ts.md index cb5c24d3f..be72301fb 100644 --- a/packages/integrate/__tests__/sourcemaps/__snapshots__/sourcemaps.spec.ts.md +++ b/packages/integrate/__tests__/sourcemaps/__snapshots__/sourcemaps.spec.ts.md @@ -8,12 +8,12 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 - `Error: ␊ - at /packages/integrate/__tests__/sourcemaps/sourcemaps.spec.ts:18:26␊ + `Error␊ + at (/packages/integrate/__tests__/sourcemaps/sourcemaps.spec.ts:30:9)␊ at Test.callFn (file:///node_modules/.pnpm/ava@6.4.1_encoding@0.1.13/node_modules/ava/lib/test.js:525:26)␊ at Test.run (file:///node_modules/.pnpm/ava@6.4.1_encoding@0.1.13/node_modules/ava/lib/test.js:534:33)␊ at Runner.runSingle (file:///node_modules/.pnpm/ava@6.4.1_encoding@0.1.13/node_modules/ava/lib/runner.js:280:33)␊ at Runner.runTest (file:///node_modules/.pnpm/ava@6.4.1_encoding@0.1.13/node_modules/ava/lib/runner.js:362:30)␊ at async Promise.all (index 0)␊ - at file:///node_modules/.pnpm/ava@6.4.1_encoding@0.1.13/node_modules/ava/lib/runner.js:515:21␊ - at Runner.start (file:///node_modules/.pnpm/ava@6.4.1_encoding@0.1.13/node_modules/ava/lib/runner.js:523:15)` + at async file:///node_modules/.pnpm/ava@6.4.1_encoding@0.1.13/node_modules/ava/lib/runner.js:515:21␊ + at async Runner.start (file:///node_modules/.pnpm/ava@6.4.1_encoding@0.1.13/node_modules/ava/lib/runner.js:523:15)` diff --git a/packages/integrate/__tests__/sourcemaps/__snapshots__/sourcemaps.spec.ts.snap b/packages/integrate/__tests__/sourcemaps/__snapshots__/sourcemaps.spec.ts.snap index de0c48d27..35b7da592 100644 Binary files a/packages/integrate/__tests__/sourcemaps/__snapshots__/sourcemaps.spec.ts.snap and b/packages/integrate/__tests__/sourcemaps/__snapshots__/sourcemaps.spec.ts.snap differ diff --git a/packages/jest/__test__/hoist-top-level.spec.ts.md b/packages/jest/__test__/hoist-top-level.spec.ts.md index 7e2acf675..420e5a6af 100644 --- a/packages/jest/__test__/hoist-top-level.spec.ts.md +++ b/packages/jest/__test__/hoist-top-level.spec.ts.md @@ -8,37 +8,5 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 - `"use strict";␊ - jest.enableAutomock();␊ - jest.disableAutomock();␊ - jest.mock('./foo');␊ - jest.mock('./foo/bar', ()=>'bar');␊ - jest.deepUnmock('./foo');␊ - jest.mock('./foo').mock('./bar');␊ - const foo = 'foo';␊ - console.log(foo);␊ - jest.unmock('./bar/foo').dontMock('./bar/bar');␊ - const func = ()=>{␊ - jest.unmock('./foo');␊ - jest.mock('./bar');␊ - jest.mock('./bar/foo', ()=>'foo');␊ - jest.unmock('./foo/bar');␊ - jest.deepUnmock('./bar');␊ - jest.mock('./foo').mock('./bar');␊ - const bar = 'bar';␊ - console.log(bar);␊ - jest.unmock('./bar/foo').dontMock('./bar/bar');␊ - };␊ - const func2 = ()=>{␊ - jest.mock('./bar');␊ - jest.unmock('./foo/bar');␊ - jest.mock('./bar/foo', ()=>'foo');␊ - jest.unmock('./foo');␊ - jest.deepUnmock('./bar');␊ - jest.mock('./foo').mock('./bar');␊ - const bar = 'bar';␊ - console.log(bar);␊ - jest.unmock('./bar/foo').dontMock('./bar/bar');␊ - };␊ - ␊ - //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImplc3Quc3BlYy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJcbmNvbnN0IGZvbyA9ICdmb28nXG5jb25zb2xlLmxvZyhmb28pXG5qZXN0LmVuYWJsZUF1dG9tb2NrKClcbmplc3QuZGlzYWJsZUF1dG9tb2NrKClcbmplc3QubW9jaygnLi9mb28nKVxuamVzdC5tb2NrKCcuL2Zvby9iYXInLCAoKSA9PiAnYmFyJylcbmplc3QudW5tb2NrKCcuL2Jhci9mb28nKS5kb250TW9jaygnLi9iYXIvYmFyJylcbmplc3QuZGVlcFVubW9jaygnLi9mb28nKVxuamVzdC5tb2NrKCcuL2ZvbycpLm1vY2soJy4vYmFyJylcbmNvbnN0IGZ1bmMgPSAoKSA9PiB7XG4gIGNvbnN0IGJhciA9ICdiYXInXG4gIGNvbnNvbGUubG9nKGJhcilcbiAgamVzdC51bm1vY2soJy4vZm9vJylcbiAgamVzdC5tb2NrKCcuL2JhcicpXG4gIGplc3QubW9jaygnLi9iYXIvZm9vJywgKCkgPT4gJ2ZvbycpXG4gIGplc3QudW5tb2NrKCcuL2Zvby9iYXInKVxuICBqZXN0LnVubW9jaygnLi9iYXIvZm9vJykuZG9udE1vY2soJy4vYmFyL2JhcicpXG4gIGplc3QuZGVlcFVubW9jaygnLi9iYXInKVxuICBqZXN0Lm1vY2soJy4vZm9vJykubW9jaygnLi9iYXInKVxufVxuY29uc3QgZnVuYzIgPSAoKSA9PiB7XG4gIGNvbnN0IGJhciA9ICdiYXInXG4gIGNvbnNvbGUubG9nKGJhcilcbiAgamVzdC5tb2NrKCcuL2JhcicpXG4gIGplc3QudW5tb2NrKCcuL2Zvby9iYXInKVxuICBqZXN0Lm1vY2soJy4vYmFyL2ZvbycsICgpID0+ICdmb28nKVxuICBqZXN0LnVubW9jaygnLi9mb28nKVxuICBqZXN0LnVubW9jaygnLi9iYXIvZm9vJykuZG9udE1vY2soJy4vYmFyL2JhcicpXG4gIGplc3QuZGVlcFVubW9jaygnLi9iYXInKVxuICBqZXN0Lm1vY2soJy4vZm9vJykubW9jaygnLi9iYXInKVxufVxuIl0sIm5hbWVzIjpbImplc3QiLCJlbmFibGVBdXRvbW9jayIsImRpc2FibGVBdXRvbW9jayIsIm1vY2siLCJkZWVwVW5tb2NrIiwiZm9vIiwiY29uc29sZSIsImxvZyIsInVubW9jayIsImRvbnRNb2NrIiwiZnVuYyIsImJhciIsImZ1bmMyIl0sIm1hcHBpbmdzIjoiO0FBR0FBLEtBQUtDLGNBQWM7QUFDbkJELEtBQUtFLGVBQWU7QUFDcEJGLEtBQUtHLElBQUksQ0FBQztBQUNWSCxLQUFLRyxJQUFJLENBQUMsYUFBYSxJQUFNO0FBRTdCSCxLQUFLSSxVQUFVLENBQUM7QUFDaEJKLEtBQUtHLElBQUksQ0FBQyxTQUFTQSxJQUFJLENBQUM7QUFSeEIsTUFBTUUsTUFBTTtBQUNaQyxRQUFRQyxHQUFHLENBQUNGO0FBS1pMLEtBQUtRLE1BQU0sQ0FBQyxhQUFhQyxRQUFRLENBQUM7QUFHbEMsTUFBTUMsT0FBTztJQUdYVixLQUFLUSxNQUFNLENBQUM7SUFDWlIsS0FBS0csSUFBSSxDQUFDO0lBQ1ZILEtBQUtHLElBQUksQ0FBQyxhQUFhLElBQU07SUFDN0JILEtBQUtRLE1BQU0sQ0FBQztJQUVaUixLQUFLSSxVQUFVLENBQUM7SUFDaEJKLEtBQUtHLElBQUksQ0FBQyxTQUFTQSxJQUFJLENBQUM7SUFSeEIsTUFBTVEsTUFBTTtJQUNaTCxRQUFRQyxHQUFHLENBQUNJO0lBS1pYLEtBQUtRLE1BQU0sQ0FBQyxhQUFhQyxRQUFRLENBQUM7QUFHcEM7QUFDQSxNQUFNRyxRQUFRO0lBR1paLEtBQUtHLElBQUksQ0FBQztJQUNWSCxLQUFLUSxNQUFNLENBQUM7SUFDWlIsS0FBS0csSUFBSSxDQUFDLGFBQWEsSUFBTTtJQUM3QkgsS0FBS1EsTUFBTSxDQUFDO0lBRVpSLEtBQUtJLFVBQVUsQ0FBQztJQUNoQkosS0FBS0csSUFBSSxDQUFDLFNBQVNBLElBQUksQ0FBQztJQVJ4QixNQUFNUSxNQUFNO0lBQ1pMLFFBQVFDLEdBQUcsQ0FBQ0k7SUFLWlgsS0FBS1EsTUFBTSxDQUFDLGFBQWFDLFFBQVEsQ0FBQztBQUdwQyJ9` + `"use strict";jest.enableAutomock();jest.disableAutomock();jest.mock("./foo");jest.mock("./foo/bar",()=>"bar");jest.deepUnmock("./foo");jest.mock("./foo").mock("./bar");const foo="foo";console.log(foo);jest.unmock("./bar/foo").dontMock("./bar/bar");const func=()=>{jest.unmock("./foo");jest.mock("./bar");jest.mock("./bar/foo",()=>"foo");jest.unmock("./foo/bar");jest.deepUnmock("./bar");jest.mock("./foo").mock("./bar");const bar="bar";console.log(bar);jest.unmock("./bar/foo").dontMock("./bar/bar")};const func2=()=>{jest.mock("./bar");jest.unmock("./foo/bar");jest.mock("./bar/foo",()=>"foo");jest.unmock("./foo");jest.deepUnmock("./bar");jest.mock("./foo").mock("./bar");const bar="bar";console.log(bar);jest.unmock("./bar/foo").dontMock("./bar/bar")};␊ + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImplc3Quc3BlYy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJcbmNvbnN0IGZvbyA9ICdmb28nXG5jb25zb2xlLmxvZyhmb28pXG5qZXN0LmVuYWJsZUF1dG9tb2NrKClcbmplc3QuZGlzYWJsZUF1dG9tb2NrKClcbmplc3QubW9jaygnLi9mb28nKVxuamVzdC5tb2NrKCcuL2Zvby9iYXInLCAoKSA9PiAnYmFyJylcbmplc3QudW5tb2NrKCcuL2Jhci9mb28nKS5kb250TW9jaygnLi9iYXIvYmFyJylcbmplc3QuZGVlcFVubW9jaygnLi9mb28nKVxuamVzdC5tb2NrKCcuL2ZvbycpLm1vY2soJy4vYmFyJylcbmNvbnN0IGZ1bmMgPSAoKSA9PiB7XG4gIGNvbnN0IGJhciA9ICdiYXInXG4gIGNvbnNvbGUubG9nKGJhcilcbiAgamVzdC51bm1vY2soJy4vZm9vJylcbiAgamVzdC5tb2NrKCcuL2JhcicpXG4gIGplc3QubW9jaygnLi9iYXIvZm9vJywgKCkgPT4gJ2ZvbycpXG4gIGplc3QudW5tb2NrKCcuL2Zvby9iYXInKVxuICBqZXN0LnVubW9jaygnLi9iYXIvZm9vJykuZG9udE1vY2soJy4vYmFyL2JhcicpXG4gIGplc3QuZGVlcFVubW9jaygnLi9iYXInKVxuICBqZXN0Lm1vY2soJy4vZm9vJykubW9jaygnLi9iYXInKVxufVxuY29uc3QgZnVuYzIgPSAoKSA9PiB7XG4gIGNvbnN0IGJhciA9ICdiYXInXG4gIGNvbnNvbGUubG9nKGJhcilcbiAgamVzdC5tb2NrKCcuL2JhcicpXG4gIGplc3QudW5tb2NrKCcuL2Zvby9iYXInKVxuICBqZXN0Lm1vY2soJy4vYmFyL2ZvbycsICgpID0+ICdmb28nKVxuICBqZXN0LnVubW9jaygnLi9mb28nKVxuICBqZXN0LnVubW9jaygnLi9iYXIvZm9vJykuZG9udE1vY2soJy4vYmFyL2JhcicpXG4gIGplc3QuZGVlcFVubW9jaygnLi9iYXInKVxuICBqZXN0Lm1vY2soJy4vZm9vJykubW9jaygnLi9iYXInKVxufVxuIl0sIm5hbWVzIjpbImplc3QiLCJlbmFibGVBdXRvbW9jayIsImRpc2FibGVBdXRvbW9jayIsIm1vY2siLCJkZWVwVW5tb2NrIiwiZm9vIiwiY29uc29sZSIsImxvZyIsInVubW9jayIsImRvbnRNb2NrIiwiZnVuYyIsImJhciIsImZ1bmMyIl0sIm1hcHBpbmdzIjoiYUFHQUEsS0FBS0MsY0FBYyxHQUNuQkQsS0FBS0UsZUFBZSxHQUNwQkYsS0FBS0csSUFBSSxDQUFDLFNBQ1ZILEtBQUtHLElBQUksQ0FBQyxZQUFhLElBQU0sT0FFN0JILEtBQUtJLFVBQVUsQ0FBQyxTQUNoQkosS0FBS0csSUFBSSxDQUFDLFNBQVNBLElBQUksQ0FBQyxTQVJ4QixNQUFNRSxJQUFNLE1BQ1pDLFFBQVFDLEdBQUcsQ0FBQ0YsS0FLWkwsS0FBS1EsTUFBTSxDQUFDLGFBQWFDLFFBQVEsQ0FBQyxhQUdsQyxNQUFNQyxLQUFPLEtBR1hWLEtBQUtRLE1BQU0sQ0FBQyxTQUNaUixLQUFLRyxJQUFJLENBQUMsU0FDVkgsS0FBS0csSUFBSSxDQUFDLFlBQWEsSUFBTSxPQUM3QkgsS0FBS1EsTUFBTSxDQUFDLGFBRVpSLEtBQUtJLFVBQVUsQ0FBQyxTQUNoQkosS0FBS0csSUFBSSxDQUFDLFNBQVNBLElBQUksQ0FBQyxTQVJ4QixNQUFNUSxJQUFNLE1BQ1pMLFFBQVFDLEdBQUcsQ0FBQ0ksS0FLWlgsS0FBS1EsTUFBTSxDQUFDLGFBQWFDLFFBQVEsQ0FBQyxZQUdwQyxFQUNBLE1BQU1HLE1BQVEsS0FHWlosS0FBS0csSUFBSSxDQUFDLFNBQ1ZILEtBQUtRLE1BQU0sQ0FBQyxhQUNaUixLQUFLRyxJQUFJLENBQUMsWUFBYSxJQUFNLE9BQzdCSCxLQUFLUSxNQUFNLENBQUMsU0FFWlIsS0FBS0ksVUFBVSxDQUFDLFNBQ2hCSixLQUFLRyxJQUFJLENBQUMsU0FBU0EsSUFBSSxDQUFDLFNBUnhCLE1BQU1RLElBQU0sTUFDWkwsUUFBUUMsR0FBRyxDQUFDSSxLQUtaWCxLQUFLUSxNQUFNLENBQUMsYUFBYUMsUUFBUSxDQUFDLFlBR3BDIn0=` diff --git a/packages/jest/__test__/hoist-top-level.spec.ts.snap b/packages/jest/__test__/hoist-top-level.spec.ts.snap index 20421b40b..fe569d3aa 100644 Binary files a/packages/jest/__test__/hoist-top-level.spec.ts.snap and b/packages/jest/__test__/hoist-top-level.spec.ts.snap differ diff --git a/packages/register/README.md b/packages/register/README.md index adbb762d7..0558c65c7 100644 --- a/packages/register/README.md +++ b/packages/register/README.md @@ -127,3 +127,40 @@ Respect the boolean value in `tsconfig`. `TypeScript` gives files list to `@swc-node/register`, if parse `tsconfig.json` failed or files list empty, `@swc-node/register` will transform all files which were required. And if failed to parse `tsconfig.json`, `@swc-node/register` will print warning which contains failed reason. + +## Performance tuning + +### Transform cache + +`@swc-node/register` now keeps a transform cache (memory + disk) keyed by source, filename, compiler options, and runtime versions. + +Environment variables: + +- `SWC_NODE_CACHE=0` disable cache. +- `SWC_NODE_CACHE_DIR=./path/to/cache` choose disk cache directory. +- `SWC_NODE_CACHE_MEMORY_LIMIT=2000` max in-process transform entries. + +Programmatic cache control: + +```js +const { clearTransformCache, getTransformCacheDirectory } = require('@swc-node/register/register') + +// clear memory + disk (default) +clearTransformCache() + +// clear only memory cache +clearTransformCache({ memory: true, disk: false }) + +// inspect resolved disk cache path +console.log(getTransformCacheDirectory()) +``` + +### Source map memory mode + +Use `SWC_NODE_SOURCE_MAP_MODE` to tune source map memory behavior: + +- `auto` (default): inline maps when Node native source maps are enabled, otherwise map-store mode. +- `inline`: inline data URL source maps only. +- `store`: in-memory map store only (`source-map-support` path). +- `both`: inline + store (highest memory use, mainly for compatibility/debug edge cases). +- `none`: disable both inline/store map injection. diff --git a/packages/register/__test__/register-runtime-tuning.spec.ts b/packages/register/__test__/register-runtime-tuning.spec.ts new file mode 100644 index 000000000..b10c0e8bf --- /dev/null +++ b/packages/register/__test__/register-runtime-tuning.spec.ts @@ -0,0 +1,161 @@ +import test from 'ava' +import sinon from 'sinon' +import * as ts from 'typescript' + +import * as swcCore from '@swc-node/core' +import { SourcemapMap } from '@swc-node/sourcemap-support' + +import { compile } from '../register' +import { clearTransformCache } from '../transform-cache' + +const originalEnv = { ...process.env } +const emptyMap = '{"version":3,"sources":[],"names":[],"mappings":""}' + +function uniquePath(label: string, extension: string) { + return `/tmp/${label}-${Date.now()}-${Math.random().toString(16).slice(2)}.${extension}` +} + +test.beforeEach(() => { + process.env.SWC_NODE_CACHE_DIR = `/tmp/swc-node-test-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}` +}) + +test.afterEach.always(() => { + sinon.restore() + SourcemapMap.clear() + clearTransformCache({ memory: true, disk: false }) + process.env = { ...originalEnv } +}) + +test.serial('reuses transform cache for sync compile', (t) => { + const transformSyncStub = sinon.stub(swcCore, 'transformSync').returns({ + code: 'console.log("cached")', + map: emptyMap, + }) + + const filename = uniquePath('cache-sync', 'ts') + const source = `const value: number = ${Date.now()}` + + const first = compile(source, filename, { + module: ts.ModuleKind.CommonJS, + sourceMap: true, + }) + const second = compile(source, filename, { + module: ts.ModuleKind.CommonJS, + sourceMap: true, + }) + + t.is(first, second) + t.is(transformSyncStub.callCount, 1) +}) + +test.serial('reuses transform cache for async compile', async (t) => { + const transformStub = sinon.stub(swcCore, 'transform').resolves({ + code: 'console.log("cached-async")', + map: emptyMap, + }) + + const filename = uniquePath('cache-async', 'ts') + const source = `const value: number = ${Date.now()}` + + const first = await compile( + source, + filename, + { + module: ts.ModuleKind.ESNext, + sourceMap: true, + }, + true, + ) + const second = await compile( + source, + filename, + { + module: ts.ModuleKind.ESNext, + sourceMap: true, + }, + true, + ) + + t.is(first, second) + t.true(transformStub.callCount <= 1) +}) + +test.serial('supports sourcemap inline-only mode to reduce map-store memory', (t) => { + process.env.SWC_NODE_SOURCE_MAP_MODE = 'inline' + + sinon.stub(swcCore, 'transformSync').returns({ + code: 'console.log("inline-only")', + map: emptyMap, + }) + + const filename = uniquePath('sourcemap-inline', 'ts') + const output = compile('const x = 1', filename, { + module: ts.ModuleKind.CommonJS, + sourceMap: true, + }) + + t.true(output.includes('sourceMappingURL')) + t.false(SourcemapMap.has(filename)) +}) + +test.serial('supports sourcemap store-only mode to avoid inline map payload', (t) => { + process.env.SWC_NODE_SOURCE_MAP_MODE = 'store' + + sinon.stub(swcCore, 'transformSync').returns({ + code: 'console.log("store-only")', + map: emptyMap, + }) + + const filename = uniquePath('sourcemap-store', 'ts') + const output = compile('const x = 1', filename, { + module: ts.ModuleKind.CommonJS, + sourceMap: true, + }) + + t.false(output.includes('sourceMappingURL')) + t.true(SourcemapMap.has(filename)) +}) + +test.serial('skips transform for plain js in commonjs mode', (t) => { + const transformSyncStub = sinon.stub(swcCore, 'transformSync') + + const output = compile('module.exports = 42', uniquePath('plain-cjs', 'js'), { + module: ts.ModuleKind.CommonJS, + sourceMap: true, + }) + + t.is(output, 'module.exports = 42') + t.false(transformSyncStub.called) +}) + +test.serial('still transforms js with esm syntax in commonjs mode', (t) => { + const transformSyncStub = sinon.stub(swcCore, 'transformSync').returns({ + code: 'exports.value = 42', + map: emptyMap, + }) + + const output = compile('export const value = 42', uniquePath('esm-in-js', 'js'), { + module: ts.ModuleKind.CommonJS, + sourceMap: true, + }) + + t.true(output.includes('exports.value = 42')) + t.true(transformSyncStub.calledOnce) +}) + +test.serial('skips transform for runtime js in esm mode', async (t) => { + const transformStub = sinon.stub(swcCore, 'transform') + + const output = await compile( + 'export const value = 42', + uniquePath('plain-esm', 'mjs'), + { + module: ts.ModuleKind.ESNext, + sourceMap: true, + }, + true, + ) + + t.is(output, 'export const value = 42') + t.false(transformStub.called) +}) diff --git a/packages/register/__test__/ts-compiler-options-to-swc-config.spec.ts b/packages/register/__test__/ts-compiler-options-to-swc-config.spec.ts index 4bce11e14..3f5dd0ec8 100644 --- a/packages/register/__test__/ts-compiler-options-to-swc-config.spec.ts +++ b/packages/register/__test__/ts-compiler-options-to-swc-config.spec.ts @@ -126,3 +126,14 @@ test('should set all values', (t) => { } t.deepEqual(swcConfig, expected) }) + +test('sourceMap without inlineSourceMap keeps external map output', (t) => { + const options: ts.CompilerOptions = { + sourceMap: true, + inlineSourceMap: false, + } + + const swcConfig = tsCompilerOptionsToSwcConfig(options, 'some-file.ts') + + t.is(swcConfig.sourcemap, true) +}) diff --git a/packages/register/esm.mts b/packages/register/esm.mts index a48cd0896..b851ad637 100644 --- a/packages/register/esm.mts +++ b/packages/register/esm.mts @@ -18,6 +18,8 @@ import ts from 'typescript' import { readDefaultTsConfig } from '../lib/read-default-tsconfig.js' // @ts-expect-error import { compile } from '../lib/register.js' +// @ts-expect-error +import { shouldSkipTransformForRuntimeJs } from '../lib/transform-cache.js' const debug = debugFactory('@swc-node') @@ -317,6 +319,15 @@ export const load: LoadHook = async (url, context, nextLoad) => { // and would likely be a breaking change anyway. Do a best effort to give a real path // like it expects, which at least fixes relative input sourcemap paths. const filename = url.startsWith('file:') ? fileURLToPath(url) : url + + if (shouldSkipTransformForRuntimeJs(filename, code, tsconfigForSWCNode.module)) { + debug('skip compile: runtime js module', url) + return addShortCircuitSignal({ + format: resolvedFormat, + source, + }) + } + const compiled = await compile(code, filename, tsconfigForSWCNode, true) debug('compiled', url, resolvedFormat) diff --git a/packages/register/package.json b/packages/register/package.json index dd1e71ebd..3e4e09ff7 100644 --- a/packages/register/package.json +++ b/packages/register/package.json @@ -44,6 +44,7 @@ "@swc-node/sourcemap-support": "^0.6.1", "colorette": "^2.0.20", "debug": "^4.4.1", + "json-stable-stringify": "^1.3.0", "oxc-resolver": "^11.6.1", "pirates": "^4.0.7", "tslib": "^2.8.1" diff --git a/packages/register/read-default-tsconfig.ts b/packages/register/read-default-tsconfig.ts index 94016ffe4..a116d794d 100644 --- a/packages/register/read-default-tsconfig.ts +++ b/packages/register/read-default-tsconfig.ts @@ -10,6 +10,29 @@ const debug = debugFactory('@swc-node') const configCache: Record boolean }>> = {} +// Keep compatibility with the legacy SWC_NODE_INLINE_SOURCE_MAP env by +// mapping it to SWC_NODE_SOURCE_MAP_MODE=inline. +if (typeof process.env.SWC_NODE_INLINE_SOURCE_MAP === 'string') { + process.env.SWC_NODE_SOURCE_MAP_MODE = 'inline' +} + +export function getSourceMapMode(): { inline: boolean; store: boolean } { + switch (process.env.SWC_NODE_SOURCE_MAP_MODE?.trim().toLowerCase()) { + case 'both': + return { inline: true, store: true } + case 'inline': + return { inline: true, store: false } + case 'store': + return { inline: false, store: true } + case 'none': + return { inline: false, store: false } + } + + // In auto mode, follow runtime capability: native source maps favor inline, + // non-native stacks favor store mode. + return process.sourceMapsEnabled ? { inline: true, store: false } : { inline: false, store: true } +} + export function readDefaultTsConfig( tsConfigPath = process.env.SWC_NODE_PROJECT ?? process.env.TS_NODE_PROJECT ?? join(process.cwd(), 'tsconfig.json'), ) { @@ -123,18 +146,15 @@ export function tsCompilerOptionsToSwcConfig(options: ts.CompilerOptions, filena const isJsx = filename.endsWith('.tsx') || filename.endsWith('.jsx') || Boolean(options.jsx) const target = options.target ?? ts.ScriptTarget.ES2018 - const enableInlineSourceMap = - options.inlineSourceMap ?? - (typeof process.env.SWC_NODE_INLINE_SOURCE_MAP === 'string' - ? Boolean(process.env.SWC_NODE_INLINE_SOURCE_MAP) - : undefined) + const sourceMapModeName = process.env.SWC_NODE_SOURCE_MAP_MODE?.trim().toLowerCase() + const enableInlineSourceMap = options.inlineSourceMap ?? (sourceMapModeName === 'inline' ? true : undefined) + const shouldEmitSourceMap = Boolean(options.sourceMap || enableInlineSourceMap) return { module: toModule(options.module ?? ts.ModuleKind.ES2015), target: toTsTarget(target), jsx: isJsx, - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - sourcemap: options.sourceMap || enableInlineSourceMap ? 'inline' : Boolean(options.sourceMap), + sourcemap: enableInlineSourceMap ? 'inline' : shouldEmitSourceMap, experimentalDecorators: options.experimentalDecorators ?? false, emitDecoratorMetadata: options.emitDecoratorMetadata ?? false, useDefineForClassFields: getUseDefineForClassFields(options, target), diff --git a/packages/register/register.ts b/packages/register/register.ts index fefb1f4c3..7edc38a64 100644 --- a/packages/register/register.ts +++ b/packages/register/register.ts @@ -3,7 +3,13 @@ import { installSourceMapSupport, SourcemapMap } from '@swc-node/sourcemap-suppo import { addHook } from 'pirates' import * as ts from 'typescript' -import { readDefaultTsConfig, tsCompilerOptionsToSwcConfig } from './read-default-tsconfig' +import { getSourceMapMode, readDefaultTsConfig, tsCompilerOptionsToSwcConfig } from './read-default-tsconfig' +import { + createCacheKey, + getCachedTransform, + setCachedTransform, + shouldSkipTransformForRuntimeJs, +} from './transform-cache' const DEFAULT_EXTENSIONS = new Set([ ts.Extension.Js, @@ -18,6 +24,14 @@ const DEFAULT_EXTENSIONS = new Set([ '.es', ]) +// Runtime knobs here are process-scoped and comparatively cheap to read, so +// they gate cache safety without paying per-module deep serialization costs. +const CacheRuntimeSalt = [ + process.env.SWCRC ? 'swcrc=1' : 'swcrc=0', + `swcConfig=${process.env.SWC_CONFIG_FILE ?? ''}`, + `sourceMapMode=${process.env.SWC_NODE_SOURCE_MAP_MODE ?? 'auto'}`, +].join(';') + const injectInlineSourceMap = ({ filename, code, @@ -27,12 +41,24 @@ const injectInlineSourceMap = ({ code: string map: string | undefined }): string => { - if (map) { + if (!map) { + return code + } + + // Choose map storage strategy at emit time so one process can tune behavior + // per runtime profile (debuggability vs memory) without rebuilds. + const sourceMapMode = getSourceMapMode() + + if (sourceMapMode.store) { SourcemapMap.set(filename, map) + } + + if (sourceMapMode.inline) { const base64Map = Buffer.from(map, 'utf8').toString('base64') const sourceMapContent = `//# sourceMappingURL=data:application/json;charset=utf-8;base64,${base64Map}` return `${code}\n${sourceMapContent}` } + return code } @@ -82,12 +108,40 @@ export function compile( if (sourcecode == null) { return } - if (options && typeof options.fallbackToTs === 'function' && options.fallbackToTs(filename)) { - delete options.fallbackToTs + + const fallbackToTs = Boolean(options && typeof options.fallbackToTs === 'function' && options.fallbackToTs(filename)) + + delete options.fallbackToTs + + // Fast-path before cache work for files intentionally left as runtime JS. + // This keeps cache logs meaningful and avoids unnecessary key generation. + if (!fallbackToTs && shouldSkipTransformForRuntimeJs(filename, sourcecode, options.module)) { + return sourcecode + } + + const cacheInput = { + sourcecode, + filename, + options, + fallbackToTs, + runSalt: CacheRuntimeSalt, + } + + const cacheKey = createCacheKey(cacheInput) + const cacheEntry = getCachedTransform(cacheKey) + if (cacheEntry) { + // Keep source-map behavior consistent for cache hits, otherwise stack trace + // semantics would differ between warm and cold compiles. + return injectInlineSourceMap({ filename, code: cacheEntry.code, map: cacheEntry.map }) + } + + if (fallbackToTs) { const { outputText, sourceMapText } = ts.transpileModule(sourcecode, { fileName: filename, compilerOptions: options, }) + + setCachedTransform(cacheKey, { code: outputText, map: sourceMapText }) return injectInlineSourceMap({ filename, code: outputText, map: sourceMapText }) } @@ -97,7 +151,7 @@ export function compile( swcRegisterConfig = { swc: { swcrc: true, - configFile: process.env.SWC_CONFIG_FILE + configFile: process.env.SWC_CONFIG_FILE, }, } } else { @@ -106,10 +160,12 @@ export function compile( if (async) { return transform(sourcecode, filename, swcRegisterConfig).then(({ code, map }) => { + setCachedTransform(cacheKey, { code, map }) return injectInlineSourceMap({ filename, code, map }) }) } else { const { code, map } = transformSync(sourcecode, filename, swcRegisterConfig) + setCachedTransform(cacheKey, { code, map }) return injectInlineSourceMap({ filename, code, map }) } } @@ -119,7 +175,13 @@ export function register(options: Partial = {}, hookOpts = { options = Object.keys(options).length ? options : readDefaultTsConfig() } options.module = ts.ModuleKind.CommonJS - installSourceMapSupport() + + // Install source-map-support only when map-store mode is active; with inline + // mode and native source maps, this avoids duplicate map retention. + if (getSourceMapMode().store) { + installSourceMapSupport() + } + return addHook((code, filename) => compile(code, filename, options), { exts: Array.from(DEFAULT_EXTENSIONS), ...hookOpts, diff --git a/packages/register/transform-cache.ts b/packages/register/transform-cache.ts new file mode 100644 index 000000000..98d7f0ff5 --- /dev/null +++ b/packages/register/transform-cache.ts @@ -0,0 +1,217 @@ +import fs from 'node:fs' +import path from 'node:path' +import * as ts from 'typescript' +import { createHash } from 'node:crypto' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import debugFactory from 'debug' +import stableStringify from 'json-stable-stringify' + +const LOOKS_LIKE_ESM_SYNTAX_REGEX = /(?:^|\n)\s*import\s|(?:^|\n)\s*export\s|\bimport\.meta\b/ + +const JS_RUNTIME_EXTENSIONS = new Set([ts.Extension.Js, ts.Extension.Mjs, ts.Extension.Cjs, '.es6', '.es']) + +interface TransformCacheEntry { + code: string + map?: string +} + +interface TransformCacheKeyInput { + sourcecode: string + filename: string + options: Record + fallbackToTs: boolean + runSalt: string +} + +const debug = debugFactory('@swc-node') + +const CACHE_ENABLED = isEnabled(process.env.SWC_NODE_CACHE, true) +const CACHE_DIRECTORY = + process.env.SWC_NODE_CACHE_DIR ?? join(tmpdir(), `swc-node-${process.getuid?.() ?? process.pid}`) +const MEMORY_CACHE_LIMIT = Number(process.env.SWC_NODE_CACHE_MEMORY_LIMIT ?? '2000') + +if (!Number.isFinite(MEMORY_CACHE_LIMIT) || MEMORY_CACHE_LIMIT < 0) { + throw new Error(`Invalid value for SWC_NODE_CACHE_MEMORY_LIMIT: ${process.env.SWC_NODE_CACHE_MEMORY_LIMIT}`) +} + +const REGISTER_VERSION = readPackageVersion('../package.json') +const SWC_VERSION = readPackageVersion('@swc/core/package.json') + +const memoryCache = new Map() +let optionsSignatureCache = new WeakMap, string>() +let cacheDirectoryReady = false + +export function getCachedTransform(cacheKey: string): TransformCacheEntry | undefined { + if (!CACHE_ENABLED) { + return undefined + } + + const memoryValue = memoryCache.get(cacheKey) + + if (memoryValue) { + return memoryValue + } + + const diskValue = readDiskCache(cacheKey) + + if (diskValue) { + setMemoryCache(cacheKey, diskValue) + } + + return diskValue +} + +export function setCachedTransform(cacheKey: string, value: TransformCacheEntry) { + if (!CACHE_ENABLED) { + return + } + + setMemoryCache(cacheKey, value) + writeDiskCache(cacheKey, value) +} + +export function createCacheKey(input: TransformCacheKeyInput): string { + // Keep cache reuse scoped to both source intent and toolchain version so + // stale compiled output is not reused across upgrades/config changes. + const hash = createHash('sha1') + hash.update(input.sourcecode) + hash.update('\0') + hash.update(input.filename) + hash.update('\0') + hash.update(input.fallbackToTs ? 'ts' : 'swc') + hash.update('\0') + hash.update(getOptionsSignature(input.options)) + hash.update('\0') + hash.update(input.runSalt) + hash.update('\0') + hash.update(`register:${REGISTER_VERSION};swc:${SWC_VERSION}`) + return hash.digest('hex') +} + +function getOptionsSignature(options: Record): string { + const cached = optionsSignatureCache.get(options) + if (cached) { + return cached + } + + // Options are usually reused for most compiles in one process; cache the + // normalized signature so hash generation stays near O(source length). + const signature = stableStringify(options)! + optionsSignatureCache.set(options, signature) + return signature +} + +function setMemoryCache(key: string, value: TransformCacheEntry) { + memoryCache.set(key, value) + + // Bound in-process retention for long-lived services where many modules + // may be touched once and never needed again. + while (memoryCache.size > MEMORY_CACHE_LIMIT) { + const oldestKey = memoryCache.keys().next().value + + if (!oldestKey) { + break + } + + memoryCache.delete(oldestKey) + } +} + +function readDiskCache(key: string): TransformCacheEntry | undefined { + try { + ensureCacheDirectory() + const file = fs.readFileSync(join(CACHE_DIRECTORY, `${key}.json`), 'utf8') + return JSON.parse(file) as TransformCacheEntry + } catch (error) { + debug('Failed to read cache file', error) + return undefined + } +} + +function writeDiskCache(key: string, value: TransformCacheEntry) { + ensureCacheDirectory() + + // Ensure writes are non blocking + void fs.promises.writeFile(join(CACHE_DIRECTORY, `${key}.json`), JSON.stringify(value), 'utf8').catch((error) => { + debug('Failed to write cache file', error) + }) +} + +function ensureCacheDirectory() { + if (!cacheDirectoryReady) { + fs.mkdirSync(CACHE_DIRECTORY, { recursive: true }) + cacheDirectoryReady = true + } + + // Note that we do not attempt to clean up old cache files since we store it + // on tmpdir and we assume the OS take care of that. +} + +function readPackageVersion(path: string): string { + try { + return require(path).version ?? 'unknown' + } catch (error) { + debug(`Failed to read package ${path} version`, error) + return 'unknown' + } +} + +function isEnabled(value: string | undefined, fallback: boolean): boolean { + if (!value) { + return fallback + } + const normalized = value.trim().toLowerCase() + return normalized !== '0' && normalized !== 'false' && normalized !== 'off' && normalized !== 'no' +} + +export function clearTransformCache(options: { memory?: boolean; disk?: boolean } = {}) { + const { memory = true, disk = true } = options + + if (memory) { + memoryCache.clear() + optionsSignatureCache = new WeakMap, string>() + } + + if (disk) { + try { + fs.rmSync(CACHE_DIRECTORY, { recursive: true, force: true }) + } catch (error) { + debug('Failed to clear cache directory', error) + } + + cacheDirectoryReady = false + } +} + +export function getTransformCacheDirectory() { + return CACHE_DIRECTORY +} + +export function shouldSkipTransformForRuntimeJs( + filename: string, + sourcecode: string, + moduleKind: ts.ModuleKind = ts.ModuleKind.ES2015, + swcrcEnabled: boolean = Boolean(process.env.SWCRC), +): boolean { + // Respect SWCRC workflows first. When users opt into external SWC config, + // consistency with that config takes priority over local fast-path heuristics. + if (swcrcEnabled) { + return false + } + + const extension = path.extname(filename).toLowerCase() + if (!JS_RUNTIME_EXTENSIONS.has(extension)) { + return false + } + + // In non-CommonJS output modes, runtime JS files are already executable for + // Node, so compiling them again mostly adds overhead. + if (moduleKind !== ts.ModuleKind.CommonJS) { + return true + } + + // CommonJS mode is where accidental ESM-in-JS files usually break at runtime, + // so we keep the transform path only when file content indicates that risk. + return !LOOKS_LIKE_ESM_SYNTAX_REGEX.test(sourcecode) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9a792cb76..1e5b6021b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -246,6 +246,9 @@ importers: debug: specifier: ^4.4.1 version: 4.4.3 + json-stable-stringify: + specifier: ^1.3.0 + version: 1.3.0 oxc-resolver: specifier: ^11.6.1 version: 11.19.1 @@ -2661,6 +2664,14 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -2975,6 +2986,10 @@ packages: defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + define-lazy-prop@2.0.0: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} @@ -3411,6 +3426,9 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} @@ -3649,6 +3667,9 @@ packages: isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -3861,6 +3882,10 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-stable-stringify@1.3.0: + resolution: {integrity: sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==} + engines: {node: '>= 0.4'} + json-stringify-nice@1.1.4: resolution: {integrity: sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==} @@ -3878,6 +3903,9 @@ packages: jsonfile@6.2.0: resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + jsonify@0.0.1: + resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} + jsonparse@1.3.1: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} engines: {'0': node >= 0.2.0} @@ -4269,6 +4297,10 @@ packages: '@swc/core': optional: true + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -4732,6 +4764,10 @@ packages: set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -7797,6 +7833,18 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + callsites@3.1.0: {} callsites@4.2.0: {} @@ -8074,6 +8122,12 @@ snapshots: dependencies: clone: 1.0.4 + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + define-lazy-prop@2.0.0: {} delayed-stream@1.0.0: {} @@ -8513,6 +8567,10 @@ snapshots: has-flag@4.0.0: {} + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + has-symbols@1.1.0: {} has-tostringtag@1.0.2: @@ -8704,6 +8762,8 @@ snapshots: isarray@1.0.0: {} + isarray@2.0.5: {} + isexe@2.0.0: {} isexe@3.1.5: {} @@ -9099,6 +9159,14 @@ snapshots: json-schema-traverse@1.0.0: {} + json-stable-stringify@1.3.0: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + isarray: 2.0.5 + jsonify: 0.0.1 + object-keys: 1.1.1 + json-stringify-nice@1.1.4: {} json-stringify-safe@5.0.1: {} @@ -9113,6 +9181,8 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsonify@0.0.1: {} + jsonparse@1.3.1: {} just-diff-apply@5.5.0: {} @@ -9683,6 +9753,8 @@ snapshots: transitivePeerDependencies: - debug + object-keys@1.1.1: {} + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -10160,6 +10232,15 @@ snapshots: set-blocking@2.0.0: {} + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0