From 9b92705822b9132908856c568df946e51931c9cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Sep 2026 18:30:47 +0000 Subject: [PATCH 1/2] chore(deps-dev): bump memfs from 4.68.2 to 4.79.0 Bumps [memfs](https://github.com/streamich/memfs) from 4.68.2 to 4.79.0. - [Release notes](https://github.com/streamich/memfs/releases) - [Changelog](https://github.com/streamich/memfs/blob/master/CHANGELOG.md) - [Commits](https://github.com/streamich/memfs/compare/v4.68.2...v4.79.0) --- updated-dependencies: - dependency-name: memfs dependency-version: 4.79.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pnpm-lock.yaml | 186 +++++++++++++++++-------------------------------- 1 file changed, 62 insertions(+), 124 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 378a263dc0..78b4b60d2c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3273,7 +3273,7 @@ importers: version: 1.1.0 memfs: specifier: ^4.17.0 - version: 4.68.2 + version: 4.79.0 typescript: specifier: ^7.0.2 version: 7.0.2 @@ -4828,10 +4828,6 @@ packages: '@iconify/utils@3.1.4': resolution: {integrity: sha512-b1S7B1k9ohZ+iNTi2ATxbRYG9fTrJmUT0rc46bvVnNxqNRGW7dyo/vRREwyniI5IRN2RSJHDcm+s3BjWrSAjHw==} - '@inquirer/ansi@2.0.7': - resolution: {integrity: sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - '@inquirer/ansi@2.0.8': resolution: {integrity: sha512-WpQM+Ti6Z40EFwwt+uL2p4UabT+W179zHp6HhLVOzfbwnVn05IPO/eXIZXGNqcT1jbQ15SujNLzQ39k4QPPxBQ==} engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} @@ -4845,15 +4841,6 @@ packages: '@types/node': optional: true - '@inquirer/confirm@6.3.0': - resolution: {integrity: sha512-pZHXJImFtERmSNMBHcjwuz8Ck5vEFEYNUZnwbb8aJpjHv/TwGuFErNxF2Hp8+V+pNJs2EYPMlyWscvFEqO9jOQ==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/confirm@6.3.2': resolution: {integrity: sha512-Xvr/0HggjddPtGppuqVmxhTw+Hr8PvsZ/k0HmOEaAqQEt80OITNkFWnsdNmyT0/eM4Ab+iJLx2R8rctlEyfSVg==} engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} @@ -4863,15 +4850,6 @@ packages: '@types/node': optional: true - '@inquirer/core@12.0.1': - resolution: {integrity: sha512-JMD5Jy/ScL5TZE18m83Nw25HjqGFLoWXwnEkW7IdwwAhZpB9Bus55/WU7zn3UqR1MOCjjTQOIYpiD4vjWA3LPw==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/core@12.0.3': resolution: {integrity: sha512-wsSy0sznmXwkty+2PzZwx00Cazc/E0r0B7mAzdGROz2Ct+DFZXaK7WDjGZvgjRldxH5ZhFVfF2lgkYrqgOw2KA==} engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} @@ -4908,10 +4886,6 @@ packages: '@types/node': optional: true - '@inquirer/figures@2.0.8': - resolution: {integrity: sha512-tApbon79GM9ry56ja/Ud3SY2CL4TQsao9fIwDQbgTeNY55025GdMzQ2+UdegV/lx51VNGUB59M0v0nMpybYY4Q==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - '@inquirer/figures@2.0.9': resolution: {integrity: sha512-EAWgUTGQ/Umgga51dE3B2PUHbufuXarDfg86uVgoSgNHNNQnyFKcOrQLWVqYMghuSyHh8+2HUH0Js9cTC1WAdg==} engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} @@ -4979,15 +4953,6 @@ packages: '@types/node': optional: true - '@inquirer/type@4.1.0': - resolution: {integrity: sha512-FMiJpuHUG3Dk0ex+UIXkre7i+i4OcwHWk9YdcVtZHFwb/r2rnrU2ipTCNAB7A+QOP0ryzIcqOfy76fRyyvOEAw==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/type@4.1.1': resolution: {integrity: sha512-yJoHYrMnxIsJZCY+0Vb66Dy3he3kL3e2wOBKhoSwWWAzZAY82emlxwgprCtp6yRixvNRNq9ztfRWQYPNr3Go7A==} engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} @@ -5061,50 +5026,50 @@ packages: peerDependencies: tslib: '2' - '@jsonjoy.com/fs-core@4.68.2': - resolution: {integrity: sha512-PoBeUNEbjyLKKwCap2z8LkkqdhdfttS4rTHCALVuP65BdF+sAoyBqHo1m+uGTRBiQWv3H7MGfr8f7lY4pDwanw==} + '@jsonjoy.com/fs-core@4.79.0': + resolution: {integrity: sha512-bxSwMrDY71OjEdj2mAYBxSe4BnHtAOjOxqUoFJc0WsllcGgA8iYl6wRF+4aVdFUjjEyHfBwxVv0QqW4AweIUZw==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' - '@jsonjoy.com/fs-fsa@4.68.2': - resolution: {integrity: sha512-h6eGXlLGGMyPfNliDQrbuHKTB9Z29ksCLjreAmdBqrDOBdfrTrHssi+b9WLfrF+J2KzAbIt9OMjJu6AEpTnYkg==} + '@jsonjoy.com/fs-fsa@4.79.0': + resolution: {integrity: sha512-EdadmStAvZw4jYg4iW3mDxBmzMFSI8jcHQkSl+rIQIO7dWbPdXaB83PBQhNCCtMBeX7zwcOFjpp0ecXqbYbjUA==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' - '@jsonjoy.com/fs-node-builtins@4.68.2': - resolution: {integrity: sha512-V8WzQsW2YIrH3RxBGY6HZisxn+dDUltHgksVRuCdPEOXEkAfXuhL/01eHFrabNu84Dn13XuLqvcQUKOYVKAUOA==} + '@jsonjoy.com/fs-node-builtins@4.79.0': + resolution: {integrity: sha512-LoBHewVHp/bZQ8Om1Iivl6NEHg7Mmby9kXJZysfnHYW4256rzXFSEcEpto1qgSAka+sq2v4N/Cnl562Z15MByA==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' - '@jsonjoy.com/fs-node-to-fsa@4.68.2': - resolution: {integrity: sha512-4O1K4w5G4oJIpKpoa3WSLG83AsQYVnGv+aUSBGOvIUph9Axm6bB1mPlvldkNg2tBx/4dkiTlZnqNrK5SQ21Wtg==} + '@jsonjoy.com/fs-node-to-fsa@4.79.0': + resolution: {integrity: sha512-xFza/t81sVL4rik7h3SlcymC6X7pvNllI88LW1GESEANDXinf5lZoqju59i3AsGLyy4i0eBQvPiizWSMwCunQA==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' - '@jsonjoy.com/fs-node-utils@4.68.2': - resolution: {integrity: sha512-CxFwyG9fJr7dAKAd1uanNRNrRMtDDqbYJA8do53+M4LY7SxcBEEmMjC1zi9MOsBlVLHTXvA7OP9+n639UqtIcw==} + '@jsonjoy.com/fs-node-utils@4.79.0': + resolution: {integrity: sha512-Rj/WevHB8DV8VyEvFGSvDD3m3JHOVk3fO1biH26iworL9/rqdUMKQQeyiKTLbdf3Z9s9vVZnn8ZC0FWZgtO2mg==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' - '@jsonjoy.com/fs-node@4.68.2': - resolution: {integrity: sha512-Kpj519Qk4OXG4+mZ8vTf9BEflliJrPueIDEVcbx8tAOufMJJ8IxR0WwdbcEvJol2KQog3PJjtALXVclorE+xbQ==} + '@jsonjoy.com/fs-node@4.79.0': + resolution: {integrity: sha512-/k18aT1X+A2yLdlTe3WKpL5y2qrvbcUY1BXA4A+s8fBfTeXfi+xdvEB85JVXVf2i9kzASQZFx8dHw9OchgMUhQ==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' - '@jsonjoy.com/fs-print@4.68.2': - resolution: {integrity: sha512-cBABQmZJXig6bahwNka3+yPNGUF1GeMWbR76ZM1N2ajgCd+S+twZigCoe9+0ueZmkhM9xd2a7688Gy/ch7T+2w==} + '@jsonjoy.com/fs-print@4.79.0': + resolution: {integrity: sha512-Bp5Q+OV1Dnl8oKf8hVhmboeI+NWbWRk1GxtJzuRvopDeNBDBh0RLevEsfnOVtwBwgRZaptSXn3e/mm3kbOzfDw==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' - '@jsonjoy.com/fs-snapshot@4.68.2': - resolution: {integrity: sha512-Aix7+NM38LzvewM0T3PICSgFdF5BVCtVgsjNsrlDPGc9hiMgJzReTDDl2/elgl0A9USMl3QP27x5WwxZSOtrfw==} + '@jsonjoy.com/fs-snapshot@4.79.0': + resolution: {integrity: sha512-/GY+eMvOl4ZQHUnrKYjC/t3N0BImBg7zv/cAGm3kiwUfqSQuo87jtbjmD3mzgQMv16K8zttkHE2wT9GaVsehvA==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' @@ -10868,8 +10833,8 @@ packages: mdurl@2.1.0: resolution: {integrity: sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==} - memfs@4.68.2: - resolution: {integrity: sha512-Un1ElEBoIdPI9kg0sm3LebVEuEViodfIvlaG8Z1MFXa7ZnR9vWuPKUo3dt/vuWY2ivc05l76B5QOjdgCzAzmGw==} + memfs@4.79.0: + resolution: {integrity: sha512-vDFqA9WSa//xa3XIKwMmVqxgWWft4PMKW0k69gBM2rYOzZ3VqL9BrK3Kyl45jSxS7qImDgwejZzEb/xDWhP37g==} merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} @@ -14600,8 +14565,6 @@ snapshots: '@iconify/types': 2.0.0 import-meta-resolve: 4.2.0 - '@inquirer/ansi@2.0.7': {} - '@inquirer/ansi@2.0.8': {} '@inquirer/checkbox@5.2.5(@types/node@26.6.2)': @@ -14613,21 +14576,14 @@ snapshots: optionalDependencies: '@types/node': 26.6.2 - '@inquirer/confirm@6.3.0(@types/node@26.2.0)': + '@inquirer/confirm@6.3.2(@types/node@26.2.0)': dependencies: - '@inquirer/core': 12.0.1(@types/node@26.2.0) - '@inquirer/type': 4.1.0(@types/node@26.2.0) + '@inquirer/core': 12.0.3(@types/node@26.2.0) + '@inquirer/type': 4.1.1(@types/node@26.2.0) optionalDependencies: '@types/node': 26.2.0 optional: true - '@inquirer/confirm@6.3.0(@types/node@26.6.2)': - dependencies: - '@inquirer/core': 12.0.1(@types/node@26.6.2) - '@inquirer/type': 4.1.0(@types/node@26.6.2) - optionalDependencies: - '@types/node': 26.6.2 - '@inquirer/confirm@6.3.2(@types/node@26.6.2)': dependencies: '@inquirer/core': 12.0.3(@types/node@26.6.2) @@ -14635,11 +14591,11 @@ snapshots: optionalDependencies: '@types/node': 26.6.2 - '@inquirer/core@12.0.1(@types/node@26.2.0)': + '@inquirer/core@12.0.3(@types/node@26.2.0)': dependencies: - '@inquirer/ansi': 2.0.7 - '@inquirer/figures': 2.0.8 - '@inquirer/type': 4.1.0(@types/node@26.2.0) + '@inquirer/ansi': 2.0.8 + '@inquirer/figures': 2.0.9 + '@inquirer/type': 4.1.1(@types/node@26.2.0) cli-width: 4.1.0 fast-wrap-ansi: 0.2.2 mute-stream: 3.0.0 @@ -14648,18 +14604,6 @@ snapshots: '@types/node': 26.2.0 optional: true - '@inquirer/core@12.0.1(@types/node@26.6.2)': - dependencies: - '@inquirer/ansi': 2.0.7 - '@inquirer/figures': 2.0.8 - '@inquirer/type': 4.1.0(@types/node@26.6.2) - cli-width: 4.1.0 - fast-wrap-ansi: 0.2.2 - mute-stream: 3.0.0 - signal-exit: 4.1.0 - optionalDependencies: - '@types/node': 26.6.2 - '@inquirer/core@12.0.3(@types/node@26.6.2)': dependencies: '@inquirer/ansi': 2.0.8 @@ -14694,8 +14638,6 @@ snapshots: optionalDependencies: '@types/node': 26.6.2 - '@inquirer/figures@2.0.8': {} - '@inquirer/figures@2.0.9': {} '@inquirer/input@5.1.6(@types/node@26.6.2)': @@ -14759,15 +14701,11 @@ snapshots: optionalDependencies: '@types/node': 26.6.2 - '@inquirer/type@4.1.0(@types/node@26.2.0)': + '@inquirer/type@4.1.1(@types/node@26.2.0)': optionalDependencies: '@types/node': 26.2.0 optional: true - '@inquirer/type@4.1.0(@types/node@26.6.2)': - optionalDependencies: - '@types/node': 26.6.2 - '@inquirer/type@4.1.1(@types/node@26.6.2)': optionalDependencies: '@types/node': 26.6.2 @@ -14832,59 +14770,59 @@ snapshots: dependencies: tslib: 2.8.1 - '@jsonjoy.com/fs-core@4.68.2(tslib@2.8.1)': + '@jsonjoy.com/fs-core@4.79.0(tslib@2.8.1)': dependencies: - '@jsonjoy.com/fs-node-builtins': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-node-utils': 4.68.2(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.79.0(tslib@2.8.1) thingies: 2.6.1(tslib@2.8.1) tslib: 2.8.1 - '@jsonjoy.com/fs-fsa@4.68.2(tslib@2.8.1)': + '@jsonjoy.com/fs-fsa@4.79.0(tslib@2.8.1)': dependencies: - '@jsonjoy.com/fs-core': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-node-builtins': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-node-utils': 4.68.2(tslib@2.8.1) + '@jsonjoy.com/fs-core': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.79.0(tslib@2.8.1) thingies: 2.6.1(tslib@2.8.1) tslib: 2.8.1 - '@jsonjoy.com/fs-node-builtins@4.68.2(tslib@2.8.1)': + '@jsonjoy.com/fs-node-builtins@4.79.0(tslib@2.8.1)': dependencies: tslib: 2.8.1 - '@jsonjoy.com/fs-node-to-fsa@4.68.2(tslib@2.8.1)': + '@jsonjoy.com/fs-node-to-fsa@4.79.0(tslib@2.8.1)': dependencies: - '@jsonjoy.com/fs-fsa': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-node-builtins': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-node-utils': 4.68.2(tslib@2.8.1) + '@jsonjoy.com/fs-fsa': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.79.0(tslib@2.8.1) tslib: 2.8.1 - '@jsonjoy.com/fs-node-utils@4.68.2(tslib@2.8.1)': + '@jsonjoy.com/fs-node-utils@4.79.0(tslib@2.8.1)': dependencies: - '@jsonjoy.com/fs-node-builtins': 4.68.2(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.79.0(tslib@2.8.1) glob-to-regex.js: 1.3.1(tslib@2.8.1) tslib: 2.8.1 - '@jsonjoy.com/fs-node@4.68.2(tslib@2.8.1)': + '@jsonjoy.com/fs-node@4.79.0(tslib@2.8.1)': dependencies: - '@jsonjoy.com/fs-core': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-node-builtins': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-node-utils': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-print': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-snapshot': 4.68.2(tslib@2.8.1) + '@jsonjoy.com/fs-core': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-print': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-snapshot': 4.79.0(tslib@2.8.1) glob-to-regex.js: 1.3.1(tslib@2.8.1) thingies: 2.6.1(tslib@2.8.1) tslib: 2.8.1 - '@jsonjoy.com/fs-print@4.68.2(tslib@2.8.1)': + '@jsonjoy.com/fs-print@4.79.0(tslib@2.8.1)': dependencies: - '@jsonjoy.com/fs-node-utils': 4.68.2(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.79.0(tslib@2.8.1) tree-dump: 1.1.0(tslib@2.8.1) tslib: 2.8.1 - '@jsonjoy.com/fs-snapshot@4.68.2(tslib@2.8.1)': + '@jsonjoy.com/fs-snapshot@4.79.0(tslib@2.8.1)': dependencies: '@jsonjoy.com/buffers': 17.67.0(tslib@2.8.1) - '@jsonjoy.com/fs-node-utils': 4.68.2(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.79.0(tslib@2.8.1) '@jsonjoy.com/json-pack': 17.67.0(tslib@2.8.1) '@jsonjoy.com/util': 17.67.0(tslib@2.8.1) tslib: 2.8.1 @@ -21052,16 +20990,16 @@ snapshots: mdurl@2.1.0: {} - memfs@4.68.2: + memfs@4.79.0: dependencies: - '@jsonjoy.com/fs-core': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-fsa': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-node': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-node-builtins': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-node-to-fsa': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-node-utils': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-print': 4.68.2(tslib@2.8.1) - '@jsonjoy.com/fs-snapshot': 4.68.2(tslib@2.8.1) + '@jsonjoy.com/fs-core': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-fsa': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-node': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-node-to-fsa': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-print': 4.79.0(tslib@2.8.1) + '@jsonjoy.com/fs-snapshot': 4.79.0(tslib@2.8.1) '@jsonjoy.com/json-pack': 1.21.0(tslib@2.8.1) '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) glob-to-regex.js: 1.3.1(tslib@2.8.1) @@ -21275,7 +21213,7 @@ snapshots: msw@2.15.0(@types/node@26.2.0)(typescript@7.0.2): dependencies: - '@inquirer/confirm': 6.3.0(@types/node@26.2.0) + '@inquirer/confirm': 6.3.2(@types/node@26.2.0) '@mswjs/interceptors': 0.41.3 '@open-draft/deferred-promise': 3.0.0 '@types/statuses': 2.0.6 @@ -21301,7 +21239,7 @@ snapshots: msw@2.15.0(@types/node@26.6.2)(typescript@7.0.2): dependencies: - '@inquirer/confirm': 6.3.0(@types/node@26.6.2) + '@inquirer/confirm': 6.3.2(@types/node@26.6.2) '@mswjs/interceptors': 0.41.3 '@open-draft/deferred-promise': 3.0.0 '@types/statuses': 2.0.6 From 0c6d409ea8f5fe7cb60d50955e896f90b9e04bf6 Mon Sep 17 00:00:00 2001 From: Odin Thomas Rochmann Date: Tue, 29 Sep 2026 11:44:41 +0200 Subject: [PATCH 2/2] fix(imports): support memfs 4.79 paths Resolve JSON paths at the filesystem boundary and align virtual test fixtures with the mocked project directory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../imports_normalize-relative-json-paths.md | 5 ++++ packages/utils/imports/src/import-json.ts | 3 ++- .../utils/imports/tests/import-config.test.ts | 15 ++++++------ .../utils/imports/tests/import-json.test.ts | 15 ++++++------ .../utils/imports/tests/import-script.test.ts | 24 +++++++++++-------- .../utils/imports/tests/test-file-path.ts | 9 +++++++ 6 files changed, 46 insertions(+), 25 deletions(-) create mode 100644 .changeset/imports_normalize-relative-json-paths.md create mode 100644 packages/utils/imports/tests/test-file-path.ts diff --git a/.changeset/imports_normalize-relative-json-paths.md b/.changeset/imports_normalize-relative-json-paths.md new file mode 100644 index 0000000000..41515c1481 --- /dev/null +++ b/.changeset/imports_normalize-relative-json-paths.md @@ -0,0 +1,5 @@ +--- +"@equinor/fusion-imports": patch +--- + +Resolve relative JSON file paths from the current working directory consistently with script and configuration imports. diff --git a/packages/utils/imports/src/import-json.ts b/packages/utils/imports/src/import-json.ts index 739746ac74..92ac81afa0 100644 --- a/packages/utils/imports/src/import-json.ts +++ b/packages/utils/imports/src/import-json.ts @@ -1,4 +1,5 @@ import { readFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; /** Union of types that `JSON.parse` can produce. */ type JSONContent = Record | string | number | boolean | null | unknown[]; @@ -28,7 +29,7 @@ export const importJSON = async ( encoding: BufferEncoding = 'utf-8', ): Promise => { try { - const content = await readFile(filePath, encoding); + const content = await readFile(resolve(filePath), encoding); return JSON.parse(content); } catch (error) { throw new Error(`Failed to parse JSON from file: '${filePath}'`, { cause: error }); diff --git a/packages/utils/imports/tests/import-config.test.ts b/packages/utils/imports/tests/import-config.test.ts index 325265f9be..85ff6efd80 100644 --- a/packages/utils/imports/tests/import-config.test.ts +++ b/packages/utils/imports/tests/import-config.test.ts @@ -3,6 +3,7 @@ import { describe, expect, it } from 'vitest'; import { vol } from 'memfs'; import { importConfig } from '../src/import-config'; +import { testFilePath } from './test-file-path'; const generateFileContent = (...content: string[]) => { return content.join('\n'); @@ -17,14 +18,14 @@ const mockConfig = { describe('import-config', () => { it('should load config from a json file', async () => { - vol.writeFileSync('config.json', JSON.stringify(mockConfig)); + vol.writeFileSync(testFilePath('config.json'), JSON.stringify(mockConfig)); const result = await importConfig('config'); expect(result.config).toMatchObject(mockConfig); }); it('should load config from a javascript file', async () => { vol.writeFileSync( - 'config.js', + testFilePath('config.js'), generateFileContent( `export const foo = ${JSON.stringify(mockConfig, null, 2)};`, 'export default foo;', @@ -36,11 +37,11 @@ describe('import-config', () => { it('should prefer typescript over javascript', async () => { vol.writeFileSync( - 'config.js', + testFilePath('config.js'), generateFileContent(`export const foo = 'should not be used';`, 'export default foo;'), ); vol.writeFileSync( - 'config.ts', + testFilePath('config.ts'), generateFileContent( `export const foo = ${JSON.stringify(mockConfig, null, 2)};`, 'export default foo;', @@ -49,13 +50,13 @@ describe('import-config', () => { const result = await importConfig('config'); expect(result.config).toMatchObject(mockConfig); expect(result.extension).toBe('.ts'); - expect(vol.existsSync('config.js')).toBe(true); + expect(vol.existsSync(testFilePath('config.js'))).toBe(true); }); it('should load config with a custom resolver', async () => { type Module = { foo: (value: number) => number }; vol.writeFileSync( - 'config.ts', + testFilePath('config.ts'), generateFileContent('export const foo = (value: number) => value + 1;'), ); const result = await importConfig('config', { @@ -69,7 +70,7 @@ describe('import-config', () => { it('should load a config with a custom async resolver', async () => { type Module = { foo: (value: number) => Promise }; vol.writeFileSync( - 'config.ts', + testFilePath('config.ts'), generateFileContent('export const foo = async (value: number) => value + 1;'), ); const result = await importConfig('config', { diff --git a/packages/utils/imports/tests/import-json.test.ts b/packages/utils/imports/tests/import-json.test.ts index 62413582af..30ef8ac7ed 100644 --- a/packages/utils/imports/tests/import-json.test.ts +++ b/packages/utils/imports/tests/import-json.test.ts @@ -3,46 +3,47 @@ import { describe, expect, it } from 'vitest'; import { vol } from 'memfs'; import importJSON from '../src/import-json'; +import { testFilePath } from './test-file-path'; describe('import-json', () => { it('should load a JSON file with a object', async () => { const expected = { foo: 'bar' }; - vol.writeFileSync('config.json', JSON.stringify(expected)); + vol.writeFileSync(testFilePath('config.json'), JSON.stringify(expected)); const result = await importJSON('config.json'); expect(result).toEqual(expected); }); it('should load a JSON file with a nested object', async () => { const expected = { foo: { bar: 'baz' } }; - vol.writeFileSync('config.json', JSON.stringify(expected)); + vol.writeFileSync(testFilePath('config.json'), JSON.stringify(expected)); const result = await importJSON('config.json'); expect(result).toEqual(expected); }); it('should load a JSON file with a string', async () => { const expected = 'foo'; - vol.writeFileSync('config.json', JSON.stringify(expected)); + vol.writeFileSync(testFilePath('config.json'), JSON.stringify(expected)); const result = await importJSON('config.json'); expect(result).toBe(expected); }); it('should load a JSON file with a number', async () => { const expected = 1; - vol.writeFileSync('config.json', JSON.stringify(expected)); + vol.writeFileSync(testFilePath('config.json'), JSON.stringify(expected)); const result = await importJSON('config.json'); expect(result).toBe(expected); }); it('should load a JSON file with a boolean', async () => { const expected = true; - vol.writeFileSync('config.json', JSON.stringify(expected)); + vol.writeFileSync(testFilePath('config.json'), JSON.stringify(expected)); const result = await importJSON('config.json'); expect(result).toBe(expected); }); it('should load a JSON file with an array', async () => { const expected = [1, 2, 3]; - vol.writeFileSync('config.json', JSON.stringify(expected)); + vol.writeFileSync(testFilePath('config.json'), JSON.stringify(expected)); const result = await importJSON('config.json'); expect(result).toEqual(expected); }); @@ -57,7 +58,7 @@ describe('import-json', () => { }); it('should throw an error if the content is not valid JSON', async () => { - vol.writeFileSync('invalid.json', 'foo'); + vol.writeFileSync(testFilePath('invalid.json'), 'foo'); await expect(importJSON('invalid.json')).rejects.toMatchObject({ message: expect.stringContaining('Failed to parse JSON'), cause: { diff --git a/packages/utils/imports/tests/import-script.test.ts b/packages/utils/imports/tests/import-script.test.ts index e9e5d138a9..f2a201f964 100644 --- a/packages/utils/imports/tests/import-script.test.ts +++ b/packages/utils/imports/tests/import-script.test.ts @@ -3,6 +3,7 @@ import { describe, expect, it } from 'vitest'; import { vol } from 'memfs'; import { importScript } from '../src/import-script'; +import { testFilePath } from './test-file-path'; const generateFileContent = (...content: string[]) => { return content.join('\n'); @@ -11,7 +12,7 @@ const generateFileContent = (...content: string[]) => { describe('import-script', () => { it('should load a javascript file', async () => { vol.writeFileSync( - 'config.js', + testFilePath('config.js'), generateFileContent('export const foo = 1;', 'export default foo;'), ); const result = await importScript('config.js'); @@ -20,7 +21,7 @@ describe('import-script', () => { it('should load a typescript file', async () => { vol.writeFileSync( - 'config.ts', + testFilePath('config.ts'), generateFileContent('export const foo: number = 1;', 'export default foo;'), ); const result = await importScript('config.ts'); @@ -29,9 +30,12 @@ describe('import-script', () => { }); it('should load a typescript file with imports', async () => { - vol.writeFileSync('base.ts', generateFileContent('export const foo: number = 1;')); vol.writeFileSync( - 'extended.ts', + testFilePath('base.ts'), + generateFileContent('export const foo: number = 1;'), + ); + vol.writeFileSync( + testFilePath('extended.ts'), generateFileContent( 'import { foo } from "./base";', 'export const bar: number = foo + 1;', @@ -46,7 +50,7 @@ describe('import-script', () => { it('should load a typescript file with functions', async () => { type MockModule = { increment: (by?: number) => number }; vol.writeFileSync( - 'config.ts', + testFilePath('config.ts'), generateFileContent( 'let count = 0;', 'export const increment = (by?: number) => {', @@ -70,9 +74,9 @@ describe('import-script', () => { it('should load a markdown file with ?raw query parameter', async () => { const markdownContent = '# Test Markdown\n\nThis is a test file.'; - vol.writeFileSync('README.md', markdownContent); + vol.writeFileSync(testFilePath('README.md'), markdownContent); vol.writeFileSync( - 'test.ts', + testFilePath('test.ts'), generateFileContent( "import readmeContent from './README.md?raw';", 'export default readmeContent;', @@ -84,10 +88,10 @@ describe('import-script', () => { it('should load a markdown file with ?raw query parameter using relative path with ../', async () => { const markdownContent = '# Parent README\n\nThis is a parent README file.'; - vol.writeFileSync('README.md', markdownContent); - vol.mkdirSync('subdir/nested', { recursive: true }); + vol.writeFileSync(testFilePath('README.md'), markdownContent); + vol.mkdirSync(testFilePath('subdir/nested'), { recursive: true }); vol.writeFileSync( - 'subdir/nested/test.ts', + testFilePath('subdir/nested/test.ts'), generateFileContent( "import readmeContent from '../../README.md?raw';", 'export default readmeContent;', diff --git a/packages/utils/imports/tests/test-file-path.ts b/packages/utils/imports/tests/test-file-path.ts new file mode 100644 index 0000000000..dfa17f1fe9 --- /dev/null +++ b/packages/utils/imports/tests/test-file-path.ts @@ -0,0 +1,9 @@ +import { resolve } from 'node:path'; + +/** + * Resolves a virtual test fixture path from the mocked process working directory. + * + * @param path - Relative path used by an import test fixture. + * @returns Absolute path inside the virtual project directory. + */ +export const testFilePath = (path: string): string => resolve(process.cwd(), path);