diff --git a/packages/vite-node/src/utils.ts b/packages/vite-node/src/utils.ts index d0b33edeb4cf..138778195921 100644 --- a/packages/vite-node/src/utils.ts +++ b/packages/vite-node/src/utils.ts @@ -1,4 +1,5 @@ import { fileURLToPath, pathToFileURL } from 'url' +import { existsSync } from 'fs' import { relative, resolve } from 'pathe' import type { TransformResult } from 'vite' import { isNodeBuiltin } from 'mlly' @@ -75,13 +76,18 @@ export function pathFromRoot(root: string, filename: string) { } export function toFilePath(id: string, root: string): string { - let absolute = id.startsWith('/@fs/') - ? id.slice(4) - : id.startsWith(root) - ? id - : id.startsWith('/') - ? resolve(root, id.slice(1)) - : id + let absolute = (() => { + if (id.startsWith('/@fs/')) + return id.slice(4) + if (!id.startsWith(root) && id.startsWith('/')) { + const resolved = resolve(root, id.slice(1)) + // The resolved path can have query values. Remove them before checking + // the file path. + if (existsSync(resolved.replace(/\?.*$/, ''))) + return resolved + } + return id + })() if (absolute.startsWith('//')) absolute = absolute.slice(1) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 86bab2c01de7..1895c262512d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1028,6 +1028,21 @@ importers: devDependencies: vitest: link:../../packages/vitest + test/path-resolution: + specifiers: + '@edge-runtime/vm': 1.1.0-beta.26 + '@vitest/test-path-resolution-target': workspace:* + '@vitest/web-worker': workspace:* + vitest: workspace:* + devDependencies: + '@edge-runtime/vm': 1.1.0-beta.26 + '@vitest/test-path-resolution-target': link:../path-resolution-target + '@vitest/web-worker': link:../../packages/web-worker + vitest: link:../../packages/vitest + + test/path-resolution-target: + specifiers: {} + test/related: specifiers: execa: ^6.1.0 @@ -1386,14 +1401,9 @@ packages: dependencies: '@babel/highlight': 7.18.6 - /@babel/compat-data/7.18.13: - resolution: {integrity: sha512-5yUzC5LqyTFp2HLmDoxGQelcdYgSpP9xsnMWBphAscOdFrHSAVbLNzWiy32sVNDqJRDiJK6klfDnAgu6PAGSHw==} - engines: {node: '>=6.9.0'} - /@babel/compat-data/7.20.0: resolution: {integrity: sha512-Gt9jszFJYq7qzXVK4slhc6NzJXnOVmRECWcVjF/T23rNXD9NtWQ0W3qxdg+p9wWIB+VQw3GYV/U2Ha9bRTfs4w==} engines: {node: '>=6.9.0'} - dev: true /@babel/core/7.12.9: resolution: {integrity: sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==} @@ -1468,7 +1478,7 @@ packages: resolution: {integrity: sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.18.13 + '@babel/types': 7.20.0 '@jridgewell/gen-mapping': 0.3.2 jsesc: 2.5.2 @@ -1479,7 +1489,6 @@ packages: '@babel/types': 7.20.0 '@jridgewell/gen-mapping': 0.3.2 jsesc: 2.5.2 - dev: true /@babel/helper-annotate-as-pure/7.18.6: resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} @@ -1502,7 +1511,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.18.13 + '@babel/compat-data': 7.20.0 '@babel/core': 7.18.13 '@babel/helper-validator-option': 7.18.6 browserslist: 4.21.3 @@ -1653,20 +1662,12 @@ packages: '@babel/types': 7.20.0 dev: true - /@babel/helper-function-name/7.18.9: - resolution: {integrity: sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.18.10 - '@babel/types': 7.20.0 - /@babel/helper-function-name/7.19.0: resolution: {integrity: sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==} engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.18.10 '@babel/types': 7.20.0 - dev: true /@babel/helper-hoist-variables/7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} @@ -1700,12 +1701,12 @@ packages: dependencies: '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-module-imports': 7.18.6 - '@babel/helper-simple-access': 7.18.6 + '@babel/helper-simple-access': 7.19.4 '@babel/helper-split-export-declaration': 7.18.6 - '@babel/helper-validator-identifier': 7.18.6 + '@babel/helper-validator-identifier': 7.19.1 '@babel/template': 7.18.10 - '@babel/traverse': 7.18.13 - '@babel/types': 7.18.13 + '@babel/traverse': 7.20.0 + '@babel/types': 7.20.0 transitivePeerDependencies: - supports-color @@ -1736,11 +1737,6 @@ packages: resolution: {integrity: sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==} dev: true - /@babel/helper-plugin-utils/7.18.9: - resolution: {integrity: sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==} - engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-plugin-utils/7.19.0: resolution: {integrity: sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==} engines: {node: '>=6.9.0'} @@ -1788,18 +1784,11 @@ packages: - supports-color dev: true - /@babel/helper-simple-access/7.18.6: - resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.20.0 - /@babel/helper-simple-access/7.19.4: resolution: {integrity: sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.20.0 - dev: true /@babel/helper-skip-transparent-expression-wrappers/7.18.9: resolution: {integrity: sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==} @@ -1814,18 +1803,10 @@ packages: dependencies: '@babel/types': 7.20.0 - /@babel/helper-string-parser/7.18.10: - resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==} - engines: {node: '>=6.9.0'} - /@babel/helper-string-parser/7.19.4: resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} engines: {node: '>=6.9.0'} - /@babel/helper-validator-identifier/7.18.6: - resolution: {integrity: sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==} - engines: {node: '>=6.9.0'} - /@babel/helper-validator-identifier/7.19.1: resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} engines: {node: '>=6.9.0'} @@ -1851,8 +1832,8 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.18.10 - '@babel/traverse': 7.18.13 - '@babel/types': 7.18.13 + '@babel/traverse': 7.20.0 + '@babel/types': 7.20.0 transitivePeerDependencies: - supports-color @@ -1880,7 +1861,7 @@ packages: engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.18.13 + '@babel/types': 7.20.0 /@babel/parser/7.20.0: resolution: {integrity: sha512-G9VgAhEaICnz8iiJeGJQyVl6J2nTjbW0xeisva0PK6XcKsga7BIaqm4ZF8Rg1Wbaqmy6znspNqhPaPkyukujzg==} @@ -3349,7 +3330,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.13 - '@babel/helper-plugin-utils': 7.18.9 + '@babel/helper-plugin-utils': 7.19.0 dev: true /@babel/plugin-transform-react-jsx-source/7.19.6_@babel+core@7.19.6: @@ -3371,9 +3352,9 @@ packages: '@babel/core': 7.18.13 '@babel/helper-annotate-as-pure': 7.18.6 '@babel/helper-module-imports': 7.18.6 - '@babel/helper-plugin-utils': 7.18.9 + '@babel/helper-plugin-utils': 7.19.0 '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.18.13 - '@babel/types': 7.18.13 + '@babel/types': 7.20.0 dev: true /@babel/plugin-transform-react-jsx/7.19.0_@babel+core@7.18.13: @@ -3955,21 +3936,21 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/parser': 7.18.13 - '@babel/types': 7.18.13 + '@babel/parser': 7.20.0 + '@babel/types': 7.20.0 /@babel/traverse/7.18.13: resolution: {integrity: sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/generator': 7.18.13 + '@babel/generator': 7.20.0 '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-function-name': 7.18.9 + '@babel/helper-function-name': 7.19.0 '@babel/helper-hoist-variables': 7.18.6 '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.18.13 - '@babel/types': 7.18.13 + '@babel/parser': 7.20.0 + '@babel/types': 7.20.0 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: @@ -3991,14 +3972,13 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color - dev: true /@babel/types/7.18.13: resolution: {integrity: sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.18.10 - '@babel/helper-validator-identifier': 7.18.6 + '@babel/helper-string-parser': 7.19.4 + '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 /@babel/types/7.20.0: @@ -6292,10 +6272,10 @@ packages: /@storybook/mdx1-csf/0.0.4_u2aypivye4tius5ftakppbroiy: resolution: {integrity: sha512-xxUEMy0D+0G1aSYxbeVNbs+XBU5nCqW4I7awpBYSTywXDv/MJWeC6FDRpj5P1pgfq8j8jWDD5ZDvBQ7syFg0LQ==} dependencies: - '@babel/generator': 7.18.13 - '@babel/parser': 7.18.13 + '@babel/generator': 7.20.0 + '@babel/parser': 7.20.0 '@babel/preset-env': 7.18.10_@babel+core@7.18.13 - '@babel/types': 7.18.13 + '@babel/types': 7.20.0 '@mdx-js/mdx': 1.6.22 '@mdx-js/react': 1.6.22_react@17.0.2 '@types/lodash': 4.14.186 @@ -7829,7 +7809,7 @@ packages: /@vue/compiler-sfc/3.2.39: resolution: {integrity: sha512-fqAQgFs1/BxTUZkd0Vakn3teKUt//J3c420BgnYgEOoVdTwYpBTSXCMJ88GOBCylmUBbtquGPli9tVs7LzsWIA==} dependencies: - '@babel/parser': 7.18.13 + '@babel/parser': 7.20.0 '@vue/compiler-core': 3.2.39 '@vue/compiler-dom': 3.2.39 '@vue/compiler-ssr': 3.2.39 @@ -7837,7 +7817,7 @@ packages: '@vue/shared': 3.2.39 estree-walker: 2.0.2 magic-string: 0.25.9 - postcss: 8.4.16 + postcss: 8.4.18 source-map: 0.6.1 /@vue/compiler-sfc/3.2.41: @@ -7851,7 +7831,7 @@ packages: '@vue/shared': 3.2.41 estree-walker: 2.0.2 magic-string: 0.25.9 - postcss: 8.4.16 + postcss: 8.4.18 source-map: 0.6.1 /@vue/compiler-ssr/3.2.39: @@ -16774,14 +16754,6 @@ packages: source-map: 0.6.1 dev: true - /postcss/8.4.16: - resolution: {integrity: sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.4 - picocolors: 1.0.0 - source-map-js: 1.0.2 - /postcss/8.4.18: resolution: {integrity: sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==} engines: {node: ^10 || ^12 || >=14} @@ -17213,7 +17185,7 @@ packages: hasBin: true dependencies: '@babel/core': 7.19.6 - '@babel/generator': 7.18.13 + '@babel/generator': 7.20.0 ast-types: 0.14.2 commander: 2.20.3 doctrine: 3.0.0 @@ -18417,9 +18389,9 @@ packages: peerDependencies: solid-js: ^1.3 dependencies: - '@babel/generator': 7.18.13 + '@babel/generator': 7.20.0 '@babel/helper-module-imports': 7.18.6 - '@babel/types': 7.18.13 + '@babel/types': 7.20.0 solid-js: 1.5.2 dev: true diff --git a/test/core/test/file-path.test.ts b/test/core/test/file-path.test.ts index 2a8f0b629e88..4f4271ce2a9e 100644 --- a/test/core/test/file-path.test.ts +++ b/test/core/test/file-path.test.ts @@ -1,6 +1,9 @@ +import { existsSync } from 'fs' import { describe, expect, it, vi } from 'vitest' import { isWindows, slash, toFilePath } from '../../../packages/vite-node/src/utils' +vi.mock('fs') + describe('toFilePath', () => { // the following tests will work incorrectly on unix systems if (isWindows) { @@ -37,8 +40,10 @@ describe('toFilePath', () => { const expected = '/path/to/project/node_modules/pkg/file.js' const processSpy = vi.spyOn(process, 'cwd').mockReturnValue(root) + const existsSpy = vi.mocked(existsSync).mockReturnValue(true) const filePath = toFilePath(id, root) processSpy.mockRestore() + existsSpy.mockRestore() expect(slash(filePath)).toEqual(expected) }) @@ -49,8 +54,11 @@ describe('toFilePath', () => { const expected = '/path/to/project/node_modules/pkg/file.js' const processSpy = vi.spyOn(process, 'cwd').mockReturnValue(root) + const existsSpy = vi.mocked(existsSync).mockReturnValue(true) const filePath = toFilePath(id, root) processSpy.mockRestore() + existsSpy.mockRestore() + expect(slash(filePath)).toEqual(expected) }) @@ -60,8 +68,10 @@ describe('toFilePath', () => { const expected = '/root/node_modules/pkg/file.js' const processSpy = vi.spyOn(process, 'cwd').mockReturnValue(root) + const existsSpy = vi.mocked(existsSync).mockReturnValue(true) const filePath = toFilePath(id, root) processSpy.mockRestore() + existsSpy.mockRestore() expect(slash(filePath)).toEqual(expected) }) @@ -72,8 +82,10 @@ describe('toFilePath', () => { const expected = '/root/node_modules/pkg/file.js' const processSpy = vi.spyOn(process, 'cwd').mockReturnValue(root) + const existsSpy = vi.mocked(existsSync).mockReturnValue(true) const filePath = toFilePath(id, root) processSpy.mockRestore() + existsSpy.mockRestore() expect(slash(filePath)).toEqual(expected) }) @@ -84,10 +96,25 @@ describe('toFilePath', () => { const expected = '/root/path/to/file.js' const processSpy = vi.spyOn(process, 'cwd').mockReturnValue(root) + const existsSpy = vi.mocked(existsSync).mockReturnValue(true) const filePath = toFilePath(id, root) processSpy.mockRestore() + existsSpy.mockRestore() expect(slash(filePath)).toEqual(expected) }) + + it('unix with sibling path', () => { + const root = '/path/to/first/package' + const id = '/path/to/second/package/file.js' + + const processSpy = vi.spyOn(process, 'cwd').mockReturnValue(root) + const existsSpy = vi.mocked(existsSync).mockReturnValue(false) + const filePath = toFilePath(id, root) + processSpy.mockRestore() + existsSpy.mockRestore() + + expect(slash(filePath)).toEqual(id) + }) } }) diff --git a/test/path-resolution-target/.eslintignore b/test/path-resolution-target/.eslintignore new file mode 100644 index 000000000000..af18ca9559d2 --- /dev/null +++ b/test/path-resolution-target/.eslintignore @@ -0,0 +1 @@ +!dist/ diff --git a/test/path-resolution-target/.gitignore b/test/path-resolution-target/.gitignore new file mode 100644 index 000000000000..af18ca9559d2 --- /dev/null +++ b/test/path-resolution-target/.gitignore @@ -0,0 +1 @@ +!dist/ diff --git a/test/path-resolution-target/README.md b/test/path-resolution-target/README.md new file mode 100644 index 000000000000..79839556fa38 --- /dev/null +++ b/test/path-resolution-target/README.md @@ -0,0 +1,2 @@ +This package is here just to be a sibling package to `path-resolution`. It +contains no tests of its own. diff --git a/test/path-resolution-target/dist/index.d.ts b/test/path-resolution-target/dist/index.d.ts new file mode 100644 index 000000000000..3b9981e05940 --- /dev/null +++ b/test/path-resolution-target/dist/index.d.ts @@ -0,0 +1 @@ +export function sub(a: number, b: number): number diff --git a/test/path-resolution-target/dist/index.js b/test/path-resolution-target/dist/index.js new file mode 100644 index 000000000000..cb92ed2e794b --- /dev/null +++ b/test/path-resolution-target/dist/index.js @@ -0,0 +1,3 @@ +export function sub(a, b) { + return a - b; +} diff --git a/test/path-resolution-target/package.json b/test/path-resolution-target/package.json new file mode 100644 index 000000000000..8b66a23ae3c1 --- /dev/null +++ b/test/path-resolution-target/package.json @@ -0,0 +1,6 @@ +{ + "name": "@vitest/test-path-resolution-target", + "type": "module", + "private": true, + "main": "./dist/index.js" +} diff --git a/test/path-resolution/package.json b/test/path-resolution/package.json new file mode 100644 index 000000000000..8e9d53a622e1 --- /dev/null +++ b/test/path-resolution/package.json @@ -0,0 +1,15 @@ +{ + "name": "@vitest/test-path-resolution", + "type": "module", + "private": true, + "scripts": { + "test": "vitest", + "coverage": "vitest run --coverage" + }, + "devDependencies": { + "@edge-runtime/vm": "1.1.0-beta.26", + "@vitest/test-path-resolution-target": "workspace:*", + "@vitest/web-worker": "workspace:*", + "vitest": "workspace:*" + } +} diff --git a/test/path-resolution/test/sister-package.test.ts b/test/path-resolution/test/sister-package.test.ts new file mode 100644 index 000000000000..abc20c44e2eb --- /dev/null +++ b/test/path-resolution/test/sister-package.test.ts @@ -0,0 +1,17 @@ +import { expect, it, vitest } from 'vitest' + +import { sub } from '@vitest/test-path-resolution-target' + +vitest.mock('@vitest/test-path-resolution-target') + +it('should be mocked', () => { + expect(sub).toHaveProperty('mock') + expect(sub(5, 3)).toBeUndefined() +}) + +it('should import actual', async () => { + const { sub } = await vitest.importActual('@vitest/test-path-resolution-target') + + expect(sub).not.toHaveProperty('mock') + expect(sub(5, 3)).toBe(2) +}) diff --git a/test/path-resolution/vitest.config.ts b/test/path-resolution/vitest.config.ts new file mode 100644 index 000000000000..41bc8c0ff39f --- /dev/null +++ b/test/path-resolution/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' + +export default defineConfig({ + test: { + include: ['test/*.test.ts'], + }, +})