diff --git a/RELEASE.md b/RELEASE.md index 6d7f002..b7c9931 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -3,7 +3,6 @@ 1. `pnpm run lint` 1. `pnpm run toc` 1. `pnpm run setup` -1. `pnpm run validate` 1. Raise Version 1. `pnpm run build` 1. `pnpm run release` or with specific version `npx standard-version --release-as 3.0.0` diff --git a/e2e/README.md b/e2e/README.md index fbce399..9f70edd 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -81,3 +81,13 @@ test('should show the proper label', () => { npm run test ``` +## Svelte 5 (ESM) + +A minimal Svelte 5 test to ensure Svelte 5 components and `.svelte.js` modules work with Jest. No special steps were taken to create this suite. It only contains a few components and their associated tests. + +### Run the Svelte 5 tests + +```shell +pnpm build +pnpm e2e:svelte-5 +``` diff --git a/e2e/svelte-5/.npmrc b/e2e/svelte-5/.npmrc new file mode 100644 index 0000000..3bd3b7d --- /dev/null +++ b/e2e/svelte-5/.npmrc @@ -0,0 +1 @@ +shell-emulator=true diff --git a/e2e/svelte-5/package.json b/e2e/svelte-5/package.json new file mode 100644 index 0000000..303921a --- /dev/null +++ b/e2e/svelte-5/package.json @@ -0,0 +1,40 @@ +{ + "name": "@svelte-jester-e2e/svelte-5", + "version": "1.0.0", + "private": true, + "type": "module", + "scripts": { + "test": "pnpm install && NODE_OPTIONS=\"--experimental-vm-modules --no-warnings\" jest --coverage --no-cache", + "test:watch": "pnpm run test --watch" + }, + "devDependencies": { + "@testing-library/jest-dom": "^6.4.5", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "svelte": "^5.0.0-next.139", + "svelte-jester": "workspace:*" + }, + "dependenciesMeta": { + "svelte-jester": { + "injected": true + } + }, + "jest": { + "transform": { + "^.+\\.svelte(?:\\.js)?$": [ + "svelte-jester" + ] + }, + "moduleFileExtensions": [ + "js", + "svelte" + ], + "extensionsToTreatAsEsm": [ + ".svelte" + ], + "setupFilesAfterEnv": [ + "@testing-library/jest-dom" + ], + "testEnvironment": "jsdom" + } +} diff --git a/e2e/svelte-5/src/legacy.svelte b/e2e/svelte-5/src/legacy.svelte new file mode 100644 index 0000000..ffa3fac --- /dev/null +++ b/e2e/svelte-5/src/legacy.svelte @@ -0,0 +1,11 @@ + + + +{#if showGreeting} +

hello {name}

+{/if} diff --git a/e2e/svelte-5/src/legacy.test.js b/e2e/svelte-5/src/legacy.test.js new file mode 100644 index 0000000..46b0bc4 --- /dev/null +++ b/e2e/svelte-5/src/legacy.test.js @@ -0,0 +1,37 @@ +import { mount, unmount, tick } from 'svelte' + +import Subject from './legacy.svelte' + +let component + +afterEach(() => { + unmount(component) + component = undefined +}) + +test('render', () => { + component = mount(Subject, { + target: document.body, + props: { name: 'alice' } + }) + + const button = document.querySelector('button') + + expect(button).toHaveRole('button') +}) + +test('interaction', async () => { + component = mount(Subject, { + target: document.body, + props: { name: 'alice' } + }) + + const button = document.querySelector('button') + + button.click() + await tick() + + const message = document.querySelector('p') + + expect(message.textContent).toMatch(/hello alice/iu) +}) diff --git a/e2e/svelte-5/src/modern.svelte b/e2e/svelte-5/src/modern.svelte new file mode 100644 index 0000000..4062846 --- /dev/null +++ b/e2e/svelte-5/src/modern.svelte @@ -0,0 +1,11 @@ + + + +{#if showGreeting} +

hello {name}

+{/if} diff --git a/e2e/svelte-5/src/modern.test.js b/e2e/svelte-5/src/modern.test.js new file mode 100644 index 0000000..5d63937 --- /dev/null +++ b/e2e/svelte-5/src/modern.test.js @@ -0,0 +1,37 @@ +import { mount, unmount, tick } from 'svelte' + +import Subject from './modern.svelte' + +let component + +afterEach(() => { + unmount(component) + component = undefined +}) + +test('render', () => { + component = mount(Subject, { + target: document.body, + props: { name: 'alice' } + }) + + const button = document.querySelector('button') + + expect(button).toHaveRole('button') +}) + +test('interaction', async () => { + component = mount(Subject, { + target: document.body, + props: { name: 'alice' } + }) + + const button = document.querySelector('button') + + button.click() + await tick() + + const message = document.querySelector('p') + + expect(message.textContent).toMatch(/hello alice/iu) +}) diff --git a/e2e/svelte-5/src/module.svelte.js b/e2e/svelte-5/src/module.svelte.js new file mode 100644 index 0000000..3f6a15b --- /dev/null +++ b/e2e/svelte-5/src/module.svelte.js @@ -0,0 +1,13 @@ +export const createCounter = () => { + let count = $state(0) + + return { + get count () { + return count + }, + + increment () { + count = count + 1 + } + } +} diff --git a/e2e/svelte-5/src/module.test.js b/e2e/svelte-5/src/module.test.js new file mode 100644 index 0000000..97a9465 --- /dev/null +++ b/e2e/svelte-5/src/module.test.js @@ -0,0 +1,19 @@ +import { test } from '@jest/globals' + +import * as Subject from './module.svelte.js' + +test('get current count', () => { + const subject = Subject.createCounter() + const result = subject.count + + expect(result).toBe(0) +}) + +test('increment', () => { + const subject = Subject.createCounter() + + subject.increment() + const result = subject.count + + expect(result).toBe(1) +}) diff --git a/e2e/svelte-5/svelte.config.js b/e2e/svelte-5/svelte.config.js new file mode 100644 index 0000000..b1c6ea4 --- /dev/null +++ b/e2e/svelte-5/svelte.config.js @@ -0,0 +1 @@ +export default {} diff --git a/e2e/svelte/package.json b/e2e/svelte/package.json index ba608fd..552abc0 100644 --- a/e2e/svelte/package.json +++ b/e2e/svelte/package.json @@ -6,7 +6,7 @@ "build": "rollup -c", "dev": "rollup -c -w", "start": "sirv public --no-clear", - "test": "jest src", + "test": "jest src --no-cache", "test:watch": "pnpm run test -- --watch" }, "devDependencies": { diff --git a/e2e/sveltekit/package.json b/e2e/sveltekit/package.json index 00c2c01..7ac698d 100644 --- a/e2e/sveltekit/package.json +++ b/e2e/sveltekit/package.json @@ -8,7 +8,7 @@ "preview": "vite preview", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "test": "svelte-kit sync && cross-env NODE_OPTIONS=--experimental-vm-modules jest src --config jest.config.json", + "test": "svelte-kit sync && cross-env NODE_OPTIONS=--experimental-vm-modules jest src --config jest.config.json --no-cache", "test:watch": "pnpm run test -- --watch" }, "devDependencies": { diff --git a/package.json b/package.json index 190fea3..402b12c 100644 --- a/package.json +++ b/package.json @@ -37,14 +37,15 @@ "test": "pnpm test:esm && pnpm test:cjs", "test:esm": "pnpm build && cross-env NODE_OPTIONS=--experimental-vm-modules jest src/__tests__/transformer.test.js", "test:cjs": "pnpm build && jest src/__tests__/transformer.test.cjs", - "e2e": "pnpm e2e:svelte && pnpm e2e:sveltekit", + "e2e": "pnpm e2e:svelte && pnpm e2e:sveltekit && pnpm e2e:svelte-5", "e2e:svelte": "cd e2e/svelte && pnpm test", "e2e:sveltekit": "cd e2e/sveltekit && pnpm test", + "e2e:svelte-5": "cd e2e/svelte-5 && pnpm test", "test:nocache": "pnpm install && jest --clearCache && pnpm test -- --no-cache", "test:watch": "pnpm test -- --watch", "test:update": "pnpm test -- --updateSnapshot --coverage", "setup": "pnpm install && pnpm validate", - "validate": "pnpm lint && pnpm test:nocache", + "validate": "pnpm lint && pnpm test:nocache && pnpm e2e", "release": "standard-version" }, "standard-version": { @@ -78,7 +79,8 @@ "jest", "it", "expect", - "describe" + "describe", + "$state" ] } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5db456f..4355653 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -110,6 +110,27 @@ importers: specifier: ^5.0.4 version: 5.0.4(@babel/core@7.24.5)(sass@1.75.0)(svelte@3.59.2)(typescript@5.1.6) + e2e/svelte-5: + devDependencies: + '@testing-library/jest-dom': + specifier: ^6.4.5 + version: 6.4.5(@types/jest@29.5.3)(jest@29.7.0) + jest: + specifier: ^29.7.0 + version: 29.7.0 + jest-environment-jsdom: + specifier: ^29.7.0 + version: 29.7.0 + svelte: + specifier: ^5.0.0-next.139 + version: 5.0.0-next.139 + svelte-jester: + specifier: workspace:* + version: file:(jest@29.7.0)(svelte@5.0.0-next.139) + dependenciesMeta: + svelte-jester: + injected: true + e2e/sveltekit: devDependencies: '@babel/core': @@ -190,6 +211,10 @@ packages: resolution: {integrity: sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==} dev: true + /@adobe/css-tools@4.4.0: + resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==} + dev: true + /@ampproject/remapping@2.2.1: resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} engines: {node: '>=6.0.0'} @@ -3881,6 +3906,39 @@ packages: redent: 3.0.0 dev: true + /@testing-library/jest-dom@6.4.5(@types/jest@29.5.3)(jest@29.7.0): + resolution: {integrity: sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + peerDependencies: + '@jest/globals': '>= 28' + '@types/bun': latest + '@types/jest': '>= 28' + jest: '>= 28' + vitest: '>= 0.32' + peerDependenciesMeta: + '@jest/globals': + optional: true + '@types/bun': + optional: true + '@types/jest': + optional: true + jest: + optional: true + vitest: + optional: true + dependencies: + '@adobe/css-tools': 4.4.0 + '@babel/runtime': 7.22.6 + '@types/jest': 29.5.3 + aria-query: 5.3.0 + chalk: 3.0.0 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + jest: 29.7.0 + lodash: 4.17.21 + redent: 3.0.0 + dev: true + /@testing-library/svelte@3.2.2(svelte@3.59.2): resolution: {integrity: sha512-IKwZgqbekC3LpoRhSwhd0JswRGxKdAGkf39UiDXTywK61YyLXbCYoR831e/UUC6EeNW4hiHPY+2WuovxOgI5sw==} engines: {node: '>= 10'} @@ -4089,16 +4147,24 @@ packages: /acorn-globals@7.0.1: resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} dependencies: - acorn: 8.10.0 + acorn: 8.11.3 acorn-walk: 8.2.0 dev: true - /acorn-jsx@5.3.2(acorn@8.10.0): + /acorn-jsx@5.3.2(acorn@8.11.3): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.10.0 + acorn: 8.11.3 + dev: true + + /acorn-typescript@1.4.13(acorn@8.11.3): + resolution: {integrity: sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==} + peerDependencies: + acorn: '>=8.9.0' + dependencies: + acorn: 8.11.3 dev: true /acorn-walk@8.2.0: @@ -4112,6 +4178,12 @@ packages: hasBin: true dev: true + /acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /add-stream@1.0.0: resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==} dev: true @@ -4285,6 +4357,12 @@ packages: dequal: 2.0.3 dev: true + /axobject-query@4.0.0: + resolution: {integrity: sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==} + dependencies: + dequal: 2.0.3 + dev: true + /babel-jest@29.6.1(@babel/core@7.22.9): resolution: {integrity: sha512-qu+3bdPEQC6KZSPz+4Fyjbga5OODNcp49j6GKzG1EKbkfyJBxEYGVUmVGpwCSeGouG52R4EgYMLb6p9YeEEQ4A==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4722,7 +4800,7 @@ packages: dependencies: '@jridgewell/sourcemap-codec': 1.4.15 '@types/estree': 1.0.5 - acorn: 8.10.0 + acorn: 8.11.3 estree-walker: 3.0.3 periscopic: 3.1.0 dev: true @@ -5223,6 +5301,10 @@ packages: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} dev: true + /dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + dev: true + /dom-serializer@1.4.1: resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} dependencies: @@ -5740,8 +5822,8 @@ packages: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.10.0 - acorn-jsx: 5.3.2(acorn@8.10.0) + acorn: 8.11.3 + acorn-jsx: 5.3.2(acorn@8.11.3) eslint-visitor-keys: 3.4.1 dev: true @@ -5758,6 +5840,13 @@ packages: estraverse: 5.3.0 dev: true + /esrap@1.2.2: + resolution: {integrity: sha512-F2pSJklxx1BlQIQgooczXCPHmcWpn6EsP5oo73LQfonG9fIlIENQ8vMmfGXeojP9MrkzUNAfyU5vdFlR9shHAw==} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + '@types/estree': 1.0.5 + dev: true + /esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -6516,6 +6605,12 @@ packages: '@types/estree': 1.0.5 dev: true + /is-reference@3.0.2: + resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} + dependencies: + '@types/estree': 1.0.5 + dev: true + /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} @@ -6812,6 +6907,29 @@ packages: - utf-8-validate dev: true + /jest-environment-jsdom@29.7.0: + resolution: {integrity: sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/jsdom': 20.0.1 + '@types/node': 20.4.2 + jest-mock: 29.7.0 + jest-util: 29.7.0 + jsdom: 20.0.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + /jest-environment-node@29.7.0: resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -7109,6 +7227,27 @@ packages: - ts-node dev: true + /jest@29.7.0: + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 29.7.0 + '@jest/types': 29.6.3 + import-local: 3.1.0 + jest-cli: 29.7.0 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: true @@ -8018,7 +8157,7 @@ packages: dependencies: '@types/estree': 1.0.5 estree-walker: 3.0.3 - is-reference: 3.0.1 + is-reference: 3.0.2 dev: true /picocolors@1.0.0: @@ -9104,6 +9243,25 @@ packages: periscopic: 3.1.0 dev: true + /svelte@5.0.0-next.139: + resolution: {integrity: sha512-g9u7sQjIFdmacxMstZyq1z8jh+CYJjqJzTJ111jFjW4znUKsKmv7Gd2Lwq5n+t6/VxF/HnZ3+/7i6yAEZ2Bg9g==} + engines: {node: '>=18'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@types/estree': 1.0.5 + acorn: 8.11.3 + acorn-typescript: 1.4.13(acorn@8.11.3) + aria-query: 5.3.0 + axobject-query: 4.0.0 + esm-env: 1.0.0 + esrap: 1.2.2 + is-reference: 3.0.2 + locate-character: 3.0.0 + magic-string: 0.30.5 + zimmerframe: 1.1.2 + dev: true + /symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} dev: true @@ -9813,6 +9971,23 @@ packages: engines: {node: '>=10'} dev: true + /zimmerframe@1.1.2: + resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} + dev: true + /zwitch@1.0.5: resolution: {integrity: sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==} dev: true + + file:(jest@29.7.0)(svelte@5.0.0-next.139): + resolution: {directory: '', type: directory} + id: 'file:' + name: svelte-jester + engines: {node: '>=16', pnpm: ^8.0.0} + peerDependencies: + jest: '>= 27' + svelte: '>= 3' + dependencies: + jest: 29.7.0 + svelte: 5.0.0-next.139 + dev: true diff --git a/src/__tests__/transformer.test.cjs b/src/__tests__/transformer.test.cjs index 6d76e8d..16e1b42 100644 --- a/src/__tests__/transformer.test.cjs +++ b/src/__tests__/transformer.test.cjs @@ -69,7 +69,7 @@ describe('CJS transformer', () => { it('should fail, if console.logs are enabled during preprocessing and there is a console.log statement in the svelte config', () => { expect( () => runTransformer('BasicComp', { preprocess: true, rootMode: 'upward', showConsoleLog: true }) - ).toThrow(/^Unexpected token T in JSON at position 0$/) + ).toThrow(/^Unexpected token .*T.*/) }) it('should pass, if console.logs are disabled (default) during preprocessing and there is a console.log statement in the svelte config', () => { diff --git a/src/transformer.js b/src/transformer.js index 0b97710..6da70fc 100644 --- a/src/transformer.js +++ b/src/transformer.js @@ -1,10 +1,10 @@ import { execSync } from 'child_process' import { basename, extname } from 'path' import { pathToFileURL } from 'url' -import { compile, preprocess as sveltePreprocess } from 'svelte/compiler' +import * as SvelteCompiler from 'svelte/compiler' import { getSvelteConfig } from './svelteconfig.js' -import { dynamicImport, IS_COMMON_JS, isSvelte3 } from './utils.js' +import { dynamicImport, IS_COMMON_JS, isSvelte3, isSvelteModule } from './utils.js' const currentFileExtension = (global.__dirname !== undefined ? extname(__filename) : extname(pathToFileURL(import.meta.url).toString())).replace('.', '') @@ -29,7 +29,7 @@ const processAsync = async (source, filename, jestOptions) => { const svelteConfigPath = getSvelteConfig(rootMode, filename, preprocess) const svelteConfig = await dynamicImport(svelteConfigPath) - const processed = await sveltePreprocess( + const processed = await SvelteCompiler.preprocess( source, svelteConfig.default.preprocess || {}, { filename } @@ -91,6 +91,8 @@ const compiler = (format, options = {}, filename, processedCode, processedMap) = opts.format = format } + const compile = isSvelteModule(filename) ? compileModule : compileComponent + let result try { result = compile(processedCode, opts) @@ -115,6 +117,18 @@ const compiler = (format, options = {}, filename, processedCode, processedMap) = } } +const compileComponent = (processedCode, opts) => { + return SvelteCompiler.compile(processedCode, opts) +} + +const compileModule = (processedCode, opts) => { + return SvelteCompiler.compileModule(processedCode, { + filename: opts.filename, + dev: opts.dev, + generate: opts.ssr ? 'server' : 'client' + }) +} + export default { process: processSync, processAsync diff --git a/src/utils.js b/src/utils.js index a3a21bd..82539cf 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,8 +1,17 @@ import { pathToFileURL } from 'url' -import { VERSION } from 'svelte/compiler' +import * as SvelteCompiler from 'svelte/compiler' export const dynamicImport = async (filename) => import(pathToFileURL(filename).toString()) export const IS_COMMON_JS = typeof module !== 'undefined' -export const isSvelte3 = (version = VERSION) => version.startsWith('3') +export const isSvelte3 = (version = SvelteCompiler.VERSION) => version.startsWith('3') + +const DEFAULT_SVELTE_MODULE_INFIX = ['.svelte.'] + +const DEFAULT_SVELTE_MODULE_EXT = ['.js', '.ts'] + +export const isSvelteModule = (filename) => + typeof SvelteCompiler.compileModule === 'function' && + DEFAULT_SVELTE_MODULE_INFIX.some((infix) => filename.includes(infix)) && + DEFAULT_SVELTE_MODULE_EXT.some((ext) => filename.endsWith(ext))