diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e1fe314d..78e64e81 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,10 @@ jobs: - run: pnpm build - run: pnpm check test: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macOS-latest] steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 @@ -48,5 +51,6 @@ jobs: node-version: 18 cache: pnpm - run: pnpm install --frozen-lockfile + - run: pnpm exec playwright install chromium - run: pnpm build - run: pnpm test diff --git a/.gitignore b/.gitignore index 486eb366..aeb3dc67 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ package-lock.json yarn.lock vite.config.js.timestamp-* /packages/create-svelte/template/CHANGELOG.md -.test-tmp +.test-output diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index ea3293fe..00000000 --- a/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -packages/core/tests/**/input.* -packages/core/tests/**/output.* diff --git a/community-adder-template/.gitignore b/community-adder-template/.gitignore index 33738ed9..a9e1699a 100644 --- a/community-adder-template/.gitignore +++ b/community-adder-template/.gitignore @@ -1,3 +1,4 @@ node_modules temp .outputs +.test-output diff --git a/community-adder-template/package.json b/community-adder-template/package.json index 557b1e55..fedd5d42 100644 --- a/community-adder-template/package.json +++ b/community-adder-template/package.json @@ -2,25 +2,28 @@ "name": "community-adder-template", "private": true, "version": "0.0.0", - "license": "MIT", "type": "module", - "exports": "./src/index.js", - "keywords": [ - "svelte-add-on", - "sv" - ], + "license": "MIT", "scripts": { + "create-temp": "sv create temp --types ts --template minimal --no-add-ons --no-install", "start": "sv add -C temp --community file:../", - "create-temp": "sv create temp --check-types typescript --template skeleton --no-adders --no-install" + "test": "vitest run" }, + "files": [ + "src", + "!src/**/*.test.*" + ], + "exports": "./src/index.js", "dependencies": { "@sveltejs/cli-core": "workspace:*" }, "devDependencies": { - "sv": "workspace:*" + "@playwright/test": "^1.48.2", + "sv": "workspace:*", + "vitest": "^2.1.4" }, - "files": [ - "src", - "!src/**/*.test.*" + "keywords": [ + "svelte-add-on", + "sv" ] } diff --git a/community-adder-template/src/index.js b/community-adder-template/src/index.js index 9e4348aa..c063124b 100644 --- a/community-adder-template/src/index.js +++ b/community-adder-template/src/index.js @@ -1,17 +1,17 @@ import { defineAdder, defineAdderOptions } from '@sveltejs/cli-core'; import { imports } from '@sveltejs/cli-core/js'; -import { parseScript } from '@sveltejs/cli-core/parsers'; +import { parseSvelte } from '@sveltejs/cli-core/parsers'; export const options = defineAdderOptions({ - demo: { - question: 'Do you want to use a demo?', - type: 'boolean', - default: false - } + demo: { + question: 'Do you want to use a demo?', + type: 'boolean', + default: false + } }); -export const adder = defineAdder({ - id: 'community-adder-template', +export default defineAdder({ + id: 'community-addon', environments: { kit: true, svelte: true }, options, packages: [], @@ -27,10 +27,11 @@ export const adder = defineAdder({ }, { name: () => 'src/DemoComponent.svelte', - content: ({ content }) => { - const { ast, generateCode } = parseScript(content); - imports.addDefault(ast, '../adder-template-demo.txt?raw', 'Demo'); - return generateCode(); + content: ({ content, options, typescript }) => { + if (!options.demo) return content; + const { script, generateCode } = parseSvelte(content, { typescript }); + imports.addDefault(script.ast, '../adder-template-demo.txt?raw', 'demo'); + return generateCode({ script: script.generateCode(), template: '{demo}' }); } } ] diff --git a/community-adder-template/tests/custom-addon.test.ts b/community-adder-template/tests/custom-addon.test.ts new file mode 100644 index 00000000..20a970e3 --- /dev/null +++ b/community-adder-template/tests/custom-addon.test.ts @@ -0,0 +1,28 @@ +import path from 'node:path'; +import { expect } from '@playwright/test'; +import { fixture, setupTest } from './setup/suite.js'; +import addon from '../src/index.js'; + +const id = addon.id; +const { test, variants, prepareServer } = setupTest({ [id]: addon }); + +test.concurrent.for(variants)('demo - %s', async (variant, { page, ...ctx }) => { + const cwd = await ctx.run(variant, { [id]: { demo: true } }); + + // ...add files + if (variant.startsWith('kit')) { + const target = path.resolve(cwd, 'src', 'routes', '+page.svelte'); + fixture({ name: '+page.svelte', target }); + } else { + const target = path.resolve(cwd, 'src', 'App.svelte'); + fixture({ name: 'App.svelte', target }); + } + + const { close } = await prepareServer({ cwd, page }); + // kill server process when we're done + ctx.onTestFinished(async () => await close()); + + // expectations + const textContent = await page.getByTestId('demo').textContent(); + expect(textContent).toContain('This is a text file made by the Community Adder Template demo!'); +}); diff --git a/community-adder-template/tests/fixtures/+page.svelte b/community-adder-template/tests/fixtures/+page.svelte new file mode 100644 index 00000000..bd5a70ff --- /dev/null +++ b/community-adder-template/tests/fixtures/+page.svelte @@ -0,0 +1,5 @@ + + +{demo} diff --git a/community-adder-template/tests/fixtures/App.svelte b/community-adder-template/tests/fixtures/App.svelte new file mode 100644 index 00000000..8694a285 --- /dev/null +++ b/community-adder-template/tests/fixtures/App.svelte @@ -0,0 +1,5 @@ + + +{demo} diff --git a/community-adder-template/tests/setup/global.ts b/community-adder-template/tests/setup/global.ts new file mode 100644 index 00000000..872cd690 --- /dev/null +++ b/community-adder-template/tests/setup/global.ts @@ -0,0 +1,29 @@ +import { fileURLToPath } from 'node:url'; +import { setup, type ProjectVariant } from 'sv/testing'; +import type { GlobalSetupContext } from 'vitest/node'; + +const variants: ProjectVariant[] = ['kit-js', 'kit-ts', 'vite-js', 'vite-ts']; +const TEST_DIR = fileURLToPath(new URL('../../.test-output/', import.meta.url)); + +export default async function ({ provide }: GlobalSetupContext) { + // global setup (e.g. spin up docker containers) + + // downloads different project configurations (sveltekit, js/ts, vite-only, etc) + const { templatesDir } = await setup({ cwd: TEST_DIR, variants, clean: true }); + + provide('testDir', TEST_DIR); + provide('templatesDir', templatesDir); + provide('variants', variants); + + return async () => { + // tear down... (e.g. cleanup docker containers) + }; +} + +declare module 'vitest' { + export interface ProvidedContext { + testDir: string; + templatesDir: string; + variants: ProjectVariant[]; + } +} diff --git a/community-adder-template/tests/setup/suite.ts b/community-adder-template/tests/setup/suite.ts new file mode 100644 index 00000000..46f3f8c8 --- /dev/null +++ b/community-adder-template/tests/setup/suite.ts @@ -0,0 +1,108 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { execSync } from 'node:child_process'; +import * as vitest from 'vitest'; +import { installAddon, type AddonMap, type OptionMap } from 'sv'; +import { createProject, startPreview, type CreateProject, type ProjectVariant } from 'sv/testing'; +import { chromium, type Browser, type Page } from '@playwright/test'; +import { fileURLToPath } from 'node:url'; + +const cwd = vitest.inject('testDir'); +const templatesDir = vitest.inject('templatesDir'); +const variants = vitest.inject('variants'); + +const SETUP_DIR = fileURLToPath(new URL('.', import.meta.url)); + +type Fixtures = { + page: Page; + run(variant: ProjectVariant, options: OptionMap): Promise; +}; + +export function setupTest(addons: Addons) { + let create: CreateProject; + let browser: Browser; + + const test = vitest.test.extend>({} as any); + + vitest.beforeAll(async () => { + browser = await chromium.launch(); + return async () => { + await browser.close(); + }; + }); + + vitest.beforeAll(({ name }) => { + const testName = path.parse(name).name.replace('.test', ''); + + // constructs a builder for create test projects + create = createProject({ cwd, templatesDir, testName }); + + // creates a pnpm workspace in each addon dir + fs.writeFileSync( + path.resolve(cwd, testName, 'pnpm-workspace.yaml'), + `packages:\n - '**/*'`, + 'utf8' + ); + }); + + // runs before each test case + vitest.beforeEach>(async (ctx) => { + const browserCtx = await browser.newContext(); + ctx.page = await browserCtx.newPage(); + ctx.run = async (variant, options) => { + const cwd = create({ testId: ctx.task.id, variant }); + + // test metadata + const metaPath = path.resolve(cwd, 'meta.json'); + fs.writeFileSync(metaPath, JSON.stringify({ variant, options }, null, '\t'), 'utf8'); + + // run addon + await installAddon({ cwd, addons, options, packageManager: 'pnpm' }); + + return cwd; + }; + + return async () => { + await browserCtx.close(); + // ...other tear downs + }; + }); + + return { + test, + variants, + prepareServer + }; +} + +/** + * Installs dependencies, builds the project, and spins up the preview server + */ +async function prepareServer({ cwd, page }: { cwd: string; page: Page }) { + // install deps + execSync('pnpm install --no-frozen-lockfile', { cwd, stdio: 'pipe' }); + + // ...do commands and any other extra stuff + + // build project + execSync('npm run build', { cwd, stdio: 'pipe' }); + + // start preview server `vite preview` + const { url, close } = await startPreview({ cwd }); + + // navigate to the page + await page.goto(url); + + return { url, close }; +} + +/** + * Applies a fixture to the target path + */ +export function fixture({ name, target }: { name: string; target: string }) { + const fixturePath = path.resolve(SETUP_DIR, '..', 'fixtures', name); + if (!fs.existsSync(fixturePath)) { + throw new Error(`Fixture does not exist at: ${fixturePath}`); + } + fs.copyFileSync(fixturePath, target); +} diff --git a/community-adder-template/tests/tests.js b/community-adder-template/tests/tests.js deleted file mode 100644 index 373c556b..00000000 --- a/community-adder-template/tests/tests.js +++ /dev/null @@ -1,16 +0,0 @@ -import { defineAdderTests } from '@sveltejs/cli-core'; -import { options } from '../src/index.js'; - -export const tests = defineAdderTests({ - files: [], - options, - optionValues: [{ demo: true }], - tests: [ - { - name: 'demo test', - run: async ({ elementExists }) => { - await elementExists('.test'); - } - } - ] -}); diff --git a/community-adder-template/vitest.config.js b/community-adder-template/vitest.config.js new file mode 100644 index 00000000..0dee885f --- /dev/null +++ b/community-adder-template/vitest.config.js @@ -0,0 +1,14 @@ +import { defineConfig } from 'vitest/config'; + +const ONE_MINUTE = 1000 * 60; + +export default defineConfig({ + test: { + include: ['tests/**/*.test.{js,ts}'], + exclude: ['tests/setup/*'], + testTimeout: ONE_MINUTE * 3, + hookTimeout: ONE_MINUTE * 3, + maxConcurrency: 10, + globalSetup: ['tests/setup/global.ts'] + } +}); diff --git a/eslint.config.js b/eslint.config.js index c6f1bbf0..62799efb 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -28,10 +28,11 @@ export default [ 'packages/create/scripts/**/*', 'packages/create/templates/**/*', '**/temp/*', - '.test-tmp/**/*', + '**/.test-output/*', '**/dist/*', 'packages/**/tests/**/{output,input}.ts', - 'rollup.config.js' + 'rollup.config.js', + 'community-adder-template/tests/*' ] } ]; diff --git a/package.json b/package.json index 3678c39b..abe8d183 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,25 @@ { "name": "sv-monorepo", - "version": "0.0.1", - "description": "monorepo for sv and friends", "private": true, + "version": "0.0.1", "type": "module", + "description": "monorepo for sv and friends", + "engines": { + "pnpm": "^9.0.0" + }, "scripts": { + "build": "rollup -c", + "changeset:publish": "changeset publish", "check": "pnpm --parallel check", - "lint": "pnpm --parallel lint && eslint --cache --cache-location node_modules/.eslintcache", - "format": "pnpm --parallel format", "dev": "rollup --config --watch", - "build": "rollup -c", - "test": "pnpm --parallel test", - "changeset:publish": "changeset publish" + "format": "pnpm --parallel format", + "lint": "pnpm --parallel lint && eslint --cache --cache-location node_modules/.eslintcache", + "test": "vitest run --silent", + "test:ui": "vitest --ui" }, "devDependencies": { "@changesets/cli": "^2.27.9", + "@playwright/test": "^1.48.2", "@rollup/plugin-commonjs": "^26.0.1", "@rollup/plugin-dynamic-import-vars": "^2.1.2", "@rollup/plugin-json": "^6.1.0", @@ -23,7 +28,7 @@ "@sveltejs/eslint-config": "^8.1.0", "@svitejs/changesets-changelog-github-compact": "^1.1.0", "@types/node": "^22.3.0", - "@vitest/ui": "^2.0.5", + "@vitest/ui": "^2.1.4", "eslint": "^9.10.0", "magic-string": "^0.30.11", "prettier": "^3.3.3", @@ -37,10 +42,7 @@ "typescript": "^5.6.2", "typescript-eslint": "^8.5.0", "unplugin-isolated-decl": "^0.6.5", - "vitest": "^2.0.5" + "vitest": "^2.1.4" }, - "packageManager": "pnpm@9.7.0", - "engines": { - "pnpm": "^9.0.0" - } + "packageManager": "pnpm@9.7.0" } diff --git a/packages/adders/_config/official.ts b/packages/adders/_config/official.ts index 2afb5764..6beba501 100644 --- a/packages/adders/_config/official.ts +++ b/packages/adders/_config/official.ts @@ -9,7 +9,7 @@ import playwright from '../playwright/index.ts'; import prettier from '../prettier/index.ts'; import storybook from '../storybook/index.ts'; import tailwindcss from '../tailwindcss/index.ts'; -import vitest from '../vitest/index.ts'; +import vitest from '../vitest-addon/index.ts'; // The order of adders here determines the order they are displayed inside the CLI // We generally try to order them by perceived popularity diff --git a/packages/adders/_tests/_setup/global.ts b/packages/adders/_tests/_setup/global.ts new file mode 100644 index 00000000..93b6b955 --- /dev/null +++ b/packages/adders/_tests/_setup/global.ts @@ -0,0 +1,23 @@ +import { fileURLToPath } from 'node:url'; +import { setup, type ProjectVariant } from 'sv/testing'; +import type { GlobalSetupContext } from 'vitest/node'; + +const TEST_DIR = fileURLToPath(new URL('../../../../.test-output/adders/', import.meta.url)); +const variants: ProjectVariant[] = ['kit-js', 'kit-ts', 'vite-js', 'vite-ts']; + +export default async function ({ provide }: GlobalSetupContext) { + // downloads different project configurations (sveltekit, js/ts, vite-only, etc) + const { templatesDir } = await setup({ cwd: TEST_DIR, variants }); + + provide('testDir', TEST_DIR); + provide('templatesDir', templatesDir); + provide('variants', variants); +} + +declare module 'vitest' { + export interface ProvidedContext { + testDir: string; + templatesDir: string; + variants: ProjectVariant[]; + } +} diff --git a/packages/adders/_tests/_setup/suite.ts b/packages/adders/_tests/_setup/suite.ts new file mode 100644 index 00000000..df151f87 --- /dev/null +++ b/packages/adders/_tests/_setup/suite.ts @@ -0,0 +1,114 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { execSync } from 'node:child_process'; +import * as vitest from 'vitest'; +import { installAddon, type AddonMap, type OptionMap } from 'sv'; +import { createProject, startPreview, type CreateProject, type ProjectVariant } from 'sv/testing'; +import { chromium, type Browser, type Page } from '@playwright/test'; + +const cwd = vitest.inject('testDir'); +const templatesDir = vitest.inject('templatesDir'); +const variants = vitest.inject('variants'); + +type Fixtures = { + page: Page; + run(variant: ProjectVariant, options: OptionMap): Promise; +}; + +export function setupTest(addons: Addons) { + const test = vitest.test.extend>({} as any); + + let create: CreateProject; + let browser: Browser; + + vitest.beforeAll(async () => { + browser = await chromium.launch(); + return async () => { + await browser.close(); + }; + }); + + vitest.beforeAll(({ name }) => { + const testName = path.dirname(name).split('/').at(-1)!; + + // constructs a builder for create test projects + create = createProject({ cwd, templatesDir, testName }); + + // creates a pnpm workspace in each addon dir + fs.writeFileSync( + path.resolve(cwd, testName, 'pnpm-workspace.yaml'), + "packages:\n - '**/*'", + 'utf8' + ); + }); + + // runs before each test case + vitest.beforeEach>(async (ctx) => { + const browserCtx = await browser.newContext(); + ctx.page = await browserCtx.newPage(); + ctx.run = async (variant, options) => { + const cwd = create({ testId: ctx.task.id, variant }); + + // test metadata + const metaPath = path.resolve(cwd, 'meta.json'); + fs.writeFileSync(metaPath, JSON.stringify({ variant, options }, null, '\t'), 'utf8'); + + // run adder + await installAddon({ cwd, addons, options, packageManager: 'pnpm' }); + + return cwd; + }; + + return async () => { + await browserCtx.close(); + // ...other tear downs + }; + }); + + return { test, variants, prepareServer }; +} + +type PrepareServerOptions = { + cwd: string; + page: Page; + previewCommand?: string; + buildCommand?: string; + installCommand?: string; +}; +// installs dependencies, builds the project, and spins up the preview server +async function prepareServer( + { + cwd, + page, + previewCommand = 'npm run preview', + buildCommand = 'npm run build', + installCommand = 'pnpm install --no-frozen-lockfile' + }: PrepareServerOptions, + afterInstall?: () => Promise | any +) { + // install deps + if (installCommand) execSync(installCommand, { cwd, stdio: 'pipe' }); + + // ...do commands and any other extra stuff + await afterInstall?.(); + + // build project + if (buildCommand) execSync(buildCommand, { cwd, stdio: 'pipe' }); + + // start preview server + const { url, close } = await startPreview({ cwd, command: previewCommand }); + + // increases timeout as 30s is not always enough when running the full suite + page.setDefaultNavigationTimeout(60_000); + + try { + // navigate to the page + await page.goto(url); + } catch (e) { + // cleanup in the instance of a timeout + await close(); + throw e; + } + + return { url, close }; +} diff --git a/packages/adders/_tests/drizzle/docker-compose.yml b/packages/adders/_tests/drizzle/docker-compose.yml new file mode 100644 index 00000000..f6f5e0a7 --- /dev/null +++ b/packages/adders/_tests/drizzle/docker-compose.yml @@ -0,0 +1,20 @@ +services: + db-postgres: + image: postgres + restart: always + shm_size: 128mb + ports: + - 5432:5432 + environment: + POSTGRES_USER: root + POSTGRES_PASSWORD: mysecretpassword + POSTGRES_DB: local + db-mysql: + image: mysql + restart: always + shm_size: 128mb + ports: + - 3306:3306 + environment: + MYSQL_ROOT_PASSWORD: mysecretpassword + MYSQL_DATABASE: local diff --git a/packages/adders/_tests/drizzle/fixtures.ts b/packages/adders/_tests/drizzle/fixtures.ts new file mode 100644 index 00000000..a6e2f803 --- /dev/null +++ b/packages/adders/_tests/drizzle/fixtures.ts @@ -0,0 +1,26 @@ +export const pageServer = ` +import { db } from '$lib/server/db'; +import { user } from '$lib/server/db/schema.js'; + +export const load = async () => { + await insertUser({ name: 'Foobar', id: 0, age: 20 }).catch((err) => console.error(err)); + + const users = await db.select().from(user); + + return { users }; +}; + +function insertUser(value) { + return db.insert(user).values(value); +} +`; + +export const pageComp = ` + + +{#each data.users as user} + {user.id} {user.name} +{/each} +`; diff --git a/packages/adders/_tests/drizzle/test.ts b/packages/adders/_tests/drizzle/test.ts new file mode 100644 index 00000000..2a6d7230 --- /dev/null +++ b/packages/adders/_tests/drizzle/test.ts @@ -0,0 +1,64 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; +import { execSync } from 'node:child_process'; +import * as vitest from 'vitest'; +import { expect } from '@playwright/test'; +import { setupTest } from '../_setup/suite.ts'; +import drizzle from '../../drizzle/index.ts'; +import { pageServer, pageComp } from './fixtures.ts'; + +const { test, variants, prepareServer } = setupTest({ drizzle }); + +// only linux is supported for running docker containers in github runners +const noDocker = process.env.CI && process.platform !== 'linux'; + +vitest.beforeAll(() => { + if (noDocker) return; + const cwd = path.dirname(fileURLToPath(import.meta.url)); + execSync('docker compose up --detach', { cwd, stdio: 'pipe' }); + + return () => { + execSync('docker compose down --volumes', { cwd, stdio: 'pipe' }); + }; +}); + +const kitOnly = variants.filter((v) => v.includes('kit')); +const testCases = [ + { name: 'better-sqlite3', options: { database: 'sqlite', sqlite: 'better-sqlite3' } }, + { name: 'libsql', options: { database: 'sqlite', sqlite: 'libsql' } }, + { name: 'mysql2', options: { database: 'mysql', mysql: 'mysql2', docker: true } }, + { + name: 'postgres.js', + options: { database: 'postgresql', postgresql: 'postgres.js', docker: true } + } +].flatMap((opts) => kitOnly.map((variant) => ({ ...opts, variant }))); + +test.concurrent.for(testCases)( + 'queries database - $name - $variant', + async ({ options, variant }, { page, ...ctx }) => { + if (options.docker && noDocker) ctx.skip(); + const cwd = await ctx.run(variant, { drizzle: options as any }); + + const ts = variant === 'kit-ts'; + const drizzleConfig = path.resolve(cwd, `drizzle.config.${ts ? 'ts' : 'js'}`); + const content = fs.readFileSync(drizzleConfig, 'utf8').replace('strict: true,', ''); + fs.writeFileSync(drizzleConfig, content, 'utf8'); + + const routes = path.resolve(cwd, 'src', 'routes'); + const pagePath = path.resolve(routes, '+page.svelte'); + fs.writeFileSync(pagePath, pageComp, 'utf8'); + + const pageServerPath = path.resolve(routes, `+page.server.${ts ? 'ts' : 'js'}`); + fs.writeFileSync(pageServerPath, pageServer, 'utf8'); + + const { close } = await prepareServer({ cwd, page }, () => { + execSync('npm run db:push', { cwd, stdio: 'pipe' }); + }); + // kill server process when we're done + ctx.onTestFinished(async () => await close()); + + expect(await page.$('[data-testid]')).toBeTruthy(); + } +); diff --git a/packages/adders/_tests/eslint/test.ts b/packages/adders/_tests/eslint/test.ts new file mode 100644 index 00000000..6a8d3e20 --- /dev/null +++ b/packages/adders/_tests/eslint/test.ts @@ -0,0 +1,15 @@ +import { expect } from '@playwright/test'; +import { setupTest } from '../_setup/suite.ts'; +import eslint from '../../eslint/index.ts'; + +const { test, variants, prepareServer } = setupTest({ eslint }); + +test.concurrent.for(variants)('core - %s', async (variant, { page, ...ctx }) => { + const cwd = await ctx.run(variant, { eslint: {} }); + + const { close } = await prepareServer({ cwd, page }); + // kill server process when we're done + ctx.onTestFinished(async () => await close()); + + expect(true).toBe(true); +}); diff --git a/packages/adders/_tests/lucia/test.ts b/packages/adders/_tests/lucia/test.ts new file mode 100644 index 00000000..c95ac959 --- /dev/null +++ b/packages/adders/_tests/lucia/test.ts @@ -0,0 +1,20 @@ +import { expect } from '@playwright/test'; +import { setupTest } from '../_setup/suite.ts'; +import lucia from '../../lucia/index.ts'; +import drizzle from '../../drizzle/index.ts'; + +const { test, variants, prepareServer } = setupTest({ drizzle, lucia }); + +const kitOnly = variants.filter((v) => v.includes('kit')); +test.concurrent.for(kitOnly)('core - %s', async (variant, { page, ...ctx }) => { + const cwd = await ctx.run(variant, { + drizzle: { database: 'sqlite', sqlite: 'libsql' }, + lucia: { demo: true } + }); + + const { close } = await prepareServer({ cwd, page }); + // kill server process when we're done + ctx.onTestFinished(async () => await close()); + + expect(true).toBe(true); +}); diff --git a/packages/adders/_tests/mdsvex/fixtures.ts b/packages/adders/_tests/mdsvex/fixtures.ts new file mode 100644 index 00000000..909f8173 --- /dev/null +++ b/packages/adders/_tests/mdsvex/fixtures.ts @@ -0,0 +1,11 @@ +export const svxFile = ` +--- +title: Svex up your markdown +--- + +# { title } + +## Good stuff in your markdown + +Markdown is pretty good but sometimes you just need more. +`; diff --git a/packages/adders/_tests/mdsvex/test.ts b/packages/adders/_tests/mdsvex/test.ts new file mode 100644 index 00000000..13f71ab6 --- /dev/null +++ b/packages/adders/_tests/mdsvex/test.ts @@ -0,0 +1,55 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { expect } from '@playwright/test'; +import { parseSvelte } from '@sveltejs/cli-core/parsers'; +import { imports } from '@sveltejs/cli-core/js'; +import * as html from '@sveltejs/cli-core/html'; +import { setupTest } from '../_setup/suite.ts'; +import { svxFile } from './fixtures.ts'; +import mdsvex from '../../mdsvex/index.ts'; + +const { test, variants, prepareServer } = setupTest({ mdsvex }); + +test.concurrent.for(variants)('core - %s', async (variant, { page, ...ctx }) => { + const cwd = await ctx.run(variant, { mdsvex: {} }); + + // ...add test files + addFixture(cwd, variant); + + const { close } = await prepareServer({ cwd, page }); + // kill server process when we're done + ctx.onTestFinished(async () => await close()); + + expect(await page.$('.mdsvex h1')).toBeTruthy(); + expect(await page.$('.mdsvex h2')).toBeTruthy(); + expect(await page.$('.mdsvex p')).toBeTruthy(); +}); + +function addFixture(cwd: string, variant: string) { + let page; + let svx; + if (variant.startsWith('kit')) { + page = path.resolve(cwd, 'src', 'routes', '+page.svelte'); + svx = path.resolve(cwd, 'src', 'routes', 'Demo.svx'); + } else { + page = path.resolve(cwd, 'src', 'App.svelte'); + svx = path.resolve(cwd, 'src', 'Demo.svx'); + } + + const src = fs.readFileSync(page, 'utf8'); + const { script, template, generateCode } = parseSvelte(src); + imports.addDefault(script.ast, './Demo.svx', 'Demo'); + + const div = html.div({ class: 'mdsvex' }); + html.appendElement(template.ast.childNodes, div); + const mdsvexNode = html.element('Demo'); + html.appendElement(div.childNodes, mdsvexNode); + + const content = generateCode({ + script: script.generateCode(), + template: template.generateCode() + }); + + fs.writeFileSync(page, content, 'utf8'); + fs.writeFileSync(svx, svxFile, 'utf8'); +} diff --git a/packages/adders/_tests/paraglide/test.ts b/packages/adders/_tests/paraglide/test.ts new file mode 100644 index 00000000..e2d2ac01 --- /dev/null +++ b/packages/adders/_tests/paraglide/test.ts @@ -0,0 +1,16 @@ +import { expect } from '@playwright/test'; +import { setupTest } from '../_setup/suite.ts'; +import paraglide from '../../paraglide/index.ts'; + +const { test, variants, prepareServer } = setupTest({ paraglide }); + +const kitOnly = variants.filter((v) => v.includes('kit')); +test.concurrent.for(kitOnly)('core - %s', async (variant, { page, ...ctx }) => { + const cwd = await ctx.run(variant, { paraglide: { demo: true, availableLanguageTags: 'en' } }); + + const { close } = await prepareServer({ cwd, page }); + // kill server process when we're done + ctx.onTestFinished(async () => await close()); + + expect(true).toBe(true); +}); diff --git a/packages/adders/_tests/playwright/test.ts b/packages/adders/_tests/playwright/test.ts new file mode 100644 index 00000000..e8d735f7 --- /dev/null +++ b/packages/adders/_tests/playwright/test.ts @@ -0,0 +1,15 @@ +import { expect } from '@playwright/test'; +import { setupTest } from '../_setup/suite.ts'; +import playwright from '../../playwright/index.ts'; + +const { test, variants, prepareServer } = setupTest({ playwright }); + +test.concurrent.for(variants)('core - %s', async (variant, { page, ...ctx }) => { + const cwd = await ctx.run(variant, { playwright: {} }); + + const { close } = await prepareServer({ cwd, page }); + // kill server process when we're done + ctx.onTestFinished(async () => await close()); + + expect(true).toBe(true); +}); diff --git a/packages/adders/_tests/prettier/test.ts b/packages/adders/_tests/prettier/test.ts new file mode 100644 index 00000000..1b3f2992 --- /dev/null +++ b/packages/adders/_tests/prettier/test.ts @@ -0,0 +1,15 @@ +import { expect } from '@playwright/test'; +import { setupTest } from '../_setup/suite.ts'; +import prettier from '../../prettier/index.ts'; + +const { test, variants, prepareServer } = setupTest({ prettier }); + +test.concurrent.for(variants)('core - %s', async (variant, { page, ...ctx }) => { + const cwd = await ctx.run(variant, { prettier: {} }); + + const { close } = await prepareServer({ cwd, page }); + // kill server process when we're done + ctx.onTestFinished(async () => await close()); + + expect(true).toBe(true); +}); diff --git a/packages/adders/_tests/storybook/test.ts b/packages/adders/_tests/storybook/test.ts new file mode 100644 index 00000000..4fdc82a4 --- /dev/null +++ b/packages/adders/_tests/storybook/test.ts @@ -0,0 +1,28 @@ +import process from 'node:process'; +import { expect } from '@playwright/test'; +import { setupTest } from '../_setup/suite.ts'; +import storybook from '../../storybook/index.ts'; + +const { test, variants, prepareServer } = setupTest({ storybook }); + +let port = 6006; + +const skip = process.env.CI && process.platform === 'win32'; +test.skipIf(skip).concurrent.for(variants)( + 'storybook loaded - %s', + async (variant, { page, ...ctx }) => { + const cwd = await ctx.run(variant, { storybook: {} }); + + const { close } = await prepareServer({ + cwd, + page, + previewCommand: `pnpm storybook -p ${++port} --ci`, + buildCommand: '' + }); + // kill server process when we're done + ctx.onTestFinished(async () => await close()); + + expect(await page.$('main .sb-bar')).toBeTruthy(); + expect(await page.$('#storybook-preview-wrapper')).toBeTruthy(); + } +); diff --git a/packages/adders/_tests/tailwindcss/fixtures.ts b/packages/adders/_tests/tailwindcss/fixtures.ts new file mode 100644 index 00000000..737a10fc --- /dev/null +++ b/packages/adders/_tests/tailwindcss/fixtures.ts @@ -0,0 +1,19 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +const markup = ` +
+

+
+`; + +export function addFixture(cwd: string, variant: string) { + let page; + if (variant.startsWith('kit')) { + page = path.resolve(cwd, 'src', 'routes', '+page.svelte'); + } else { + page = path.resolve(cwd, 'src', 'App.svelte'); + } + const content = fs.readFileSync(page, 'utf8') + markup; + fs.writeFileSync(page, content, 'utf8'); +} diff --git a/packages/adders/_tests/tailwindcss/test.ts b/packages/adders/_tests/tailwindcss/test.ts new file mode 100644 index 00000000..1ede1055 --- /dev/null +++ b/packages/adders/_tests/tailwindcss/test.ts @@ -0,0 +1,40 @@ +import { expect } from '@playwright/test'; +import { setupTest } from '../_setup/suite.ts'; +import { addFixture } from './fixtures.ts'; +import tailwindcss from '../../tailwindcss/index.ts'; + +const { test, variants, prepareServer } = setupTest({ tailwindcss }); + +test.concurrent.for(variants)('none - %s', async (variant, { page, ...ctx }) => { + const cwd = await ctx.run(variant, { tailwindcss: { plugins: [] } }); + + // ...add test files + addFixture(cwd, variant); + + const { close } = await prepareServer({ cwd, page }); + // kill server process when we're done + ctx.onTestFinished(async () => await close()); + + const el = page.getByTestId('base'); + await expect(el).toHaveCSS('background-color', 'rgb(71, 85, 105)'); + await expect(el).toHaveCSS('border-color', 'rgb(249, 250, 251)'); + await expect(el).toHaveCSS('border-width', '4px'); + await expect(el).toHaveCSS('margin-top', '4px'); +}); + +test.concurrent.for(variants)('typography - %s', async (variant, { page, ...ctx }) => { + const cwd = await ctx.run(variant, { tailwindcss: { plugins: ['typography'] } }); + + // ...add files + addFixture(cwd, variant); + + const { close } = await prepareServer({ cwd, page }); + // kill server process when we're done + ctx.onTestFinished(async () => await close()); + + const el = page.getByTestId('typography'); + await expect(el).toHaveCSS('font-size', '18px'); + await expect(el).toHaveCSS('line-height', '28px'); + await expect(el).toHaveCSS('text-align', 'right'); + await expect(el).toHaveCSS('text-decoration-line', 'line-through'); +}); diff --git a/packages/adders/_tests/vitest/test.ts b/packages/adders/_tests/vitest/test.ts new file mode 100644 index 00000000..ed451996 --- /dev/null +++ b/packages/adders/_tests/vitest/test.ts @@ -0,0 +1,15 @@ +import { expect } from '@playwright/test'; +import { setupTest } from '../_setup/suite.ts'; +import vitest from '../../vitest-addon/index.ts'; + +const { test, variants, prepareServer } = setupTest({ vitest }); + +test.concurrent.for(variants)('core - %s', async (variant, { page, ...ctx }) => { + const cwd = await ctx.run(variant, { vitest: {} }); + + const { close } = await prepareServer({ cwd, page }); + // kill server process when we're done + ctx.onTestFinished(async () => await close()); + + expect(true).toBe(true); +}); diff --git a/packages/adders/drizzle/index.ts b/packages/adders/drizzle/index.ts index f3174054..69a15b9c 100644 --- a/packages/adders/drizzle/index.ts +++ b/packages/adders/drizzle/index.ts @@ -8,7 +8,7 @@ const PORTS = { sqlite: '' } as const; -export const options = defineAdderOptions({ +const options = defineAdderOptions({ database: { question: 'Which database would you like to use?', type: 'select', @@ -204,7 +204,7 @@ export default defineAdder({ imports.addNamed(ast, 'drizzle-kit', { defineConfig: 'defineConfig' }); const envCheckStatement = common.statementFromString( - `if (!process.env.DATABASE_URL) throw new Error('DATABASE_URL is not set');` + "if (!process.env.DATABASE_URL) throw new Error('DATABASE_URL is not set');" ); common.addStatement(ast, envCheckStatement); @@ -306,7 +306,7 @@ export default defineAdder({ // env var checks const dbURLCheck = common.statementFromString( - `if (!env.DATABASE_URL) throw new Error('DATABASE_URL is not set');` + "if (!env.DATABASE_URL) throw new Error('DATABASE_URL is not set');" ); common.addStatement(ast, dbURLCheck); @@ -326,7 +326,7 @@ export default defineAdder({ imports.addNamed(ast, '$app/environment', { dev: 'dev' }); // auth token check in prod const authTokenCheck = common.statementFromString( - `if (!dev && !env.DATABASE_AUTH_TOKEN) throw new Error('DATABASE_AUTH_TOKEN is not set');` + "if (!dev && !env.DATABASE_AUTH_TOKEN) throw new Error('DATABASE_AUTH_TOKEN is not set');" ); common.addStatement(ast, authTokenCheck); diff --git a/packages/adders/drizzle/tests.ts b/packages/adders/drizzle/tests.ts deleted file mode 100644 index 3257b575..00000000 --- a/packages/adders/drizzle/tests.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { options } from './index.ts'; -import { defineAdderTests } from '@sveltejs/cli-core'; -import { parseSvelte, parseJson } from '@sveltejs/cli-core/parsers'; - -const defaultOptionValues = { - sqlite: options.sqlite.default, - mysql: options.mysql.default, - postgresql: options.postgresql.default, - docker: options.docker.default -}; - -export const tests = defineAdderTests({ - options, - optionValues: [ - { ...defaultOptionValues, database: 'sqlite', sqlite: 'better-sqlite3' }, - { ...defaultOptionValues, database: 'sqlite', sqlite: 'libsql' }, - { ...defaultOptionValues, database: 'mysql', mysql: 'mysql2', docker: true }, - { ...defaultOptionValues, database: 'postgresql', postgresql: 'postgres.js', docker: true } - ], - files: [ - { - name: ({ kit }) => `${kit?.routesDirectory}/+page.svelte`, - condition: ({ kit }) => Boolean(kit), - content: ({ content }) => { - const { script, template, generateCode } = parseSvelte(content); - const dataProp = '\nexport let data;'; - const eachBlock = ` - {#each data.users as user} - {user.id} {user.name} - {/each}`; - return generateCode({ - script: script.source + dataProp, - template: template.source + eachBlock - }); - } - }, - { - name: ({ kit, typescript }) => - `${kit?.routesDirectory}/+page.server.${typescript ? 'ts' : 'js'}`, - condition: ({ kit }) => Boolean(kit), - content: ({ typescript }) => { - return ` - import { db } from '$lib/server/db'; - import { user } from '$lib/server/db/schema.js'; - - export const load = async () => { - await insertUser({ name: 'Foobar', id: 0, age: 20 }).catch((err) => console.error(err)); - - const users = await db.select().from(user); - - return { users }; - }; - - function insertUser(${typescript ? 'value: typeof user.$inferInsert' : 'value'}) { - return db.insert(user).values(value); - } - `; - } - }, - { - // override the config so we can remove strict mode - name: ({ typescript }) => `drizzle.config.${typescript ? 'ts' : 'js'}`, - condition: ({ kit }) => Boolean(kit), - content: ({ content }) => { - return content.replace('strict: true,', ''); - } - }, - { - name: () => 'package.json', - content: ({ content }) => { - const { data, generateCode } = parseJson(content); - // executes after pnpm install - data.scripts['postinstall'] ??= 'pnpm run db:push'; - return generateCode(); - } - } - ], - tests: [ - { - name: 'queries database', - run: async ({ elementExists }) => { - await elementExists('[data-test-id]'); - } - } - ] -}); diff --git a/packages/adders/eslint/tests.ts b/packages/adders/eslint/tests.ts deleted file mode 100644 index 764975ed..00000000 --- a/packages/adders/eslint/tests.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineAdderTests } from '@sveltejs/cli-core'; - -export const tests = defineAdderTests({ - files: [], - options: {}, - optionValues: [], - tests: [] -}); diff --git a/packages/adders/lucia/index.ts b/packages/adders/lucia/index.ts index f66df276..18e9aaa7 100644 --- a/packages/adders/lucia/index.ts +++ b/packages/adders/lucia/index.ts @@ -25,7 +25,7 @@ type Dialect = 'mysql' | 'postgresql' | 'sqlite'; let drizzleDialect: Dialect; let schemaPath: string; -export const options = defineAdderOptions({ +const options = defineAdderOptions({ demo: { type: 'boolean', default: true, @@ -121,21 +121,21 @@ export default defineAdder({ integer: 'integer' }); object.overrideProperties(userAttributes, { - id: common.expressionFromString(`text('id').primaryKey()`) + id: common.expressionFromString("text('id').primaryKey()") }); if (options.demo) { object.overrideProperties(userAttributes, { - username: common.expressionFromString(`text('username').notNull().unique()`), - passwordHash: common.expressionFromString(`text('password_hash').notNull()`) + username: common.expressionFromString("text('username').notNull().unique()"), + passwordHash: common.expressionFromString("text('password_hash').notNull()") }); } object.overrideProperties(sessionAttributes, { - id: common.expressionFromString(`text('id').primaryKey()`), + id: common.expressionFromString("text('id').primaryKey()"), userId: common.expressionFromString( - `text('user_id').notNull().references(() => user.id)` + "text('user_id').notNull().references(() => user.id)" ), expiresAt: common.expressionFromString( - `integer('expires_at', { mode: 'timestamp' }).notNull()` + "integer('expires_at', { mode: 'timestamp' }).notNull()" ) }); } @@ -146,24 +146,24 @@ export default defineAdder({ datetime: 'datetime' }); object.overrideProperties(userAttributes, { - id: common.expressionFromString(`varchar('id', { length: 255 }).primaryKey()`) + id: common.expressionFromString("varchar('id', { length: 255 }).primaryKey()") }); if (options.demo) { object.overrideProperties(userAttributes, { username: common.expressionFromString( - `varchar('username', { length: 32 }).notNull().unique()` + "varchar('username', { length: 32 }).notNull().unique()" ), passwordHash: common.expressionFromString( - `varchar('password_hash', { length: 255 }).notNull()` + "varchar('password_hash', { length: 255 }).notNull()" ) }); } object.overrideProperties(sessionAttributes, { - id: common.expressionFromString(`varchar('id', { length: 255 }).primaryKey()`), + id: common.expressionFromString("varchar('id', { length: 255 }).primaryKey()"), userId: common.expressionFromString( - `varchar('user_id', { length: 255 }).notNull().references(() => user.id)` + "varchar('user_id', { length: 255 }).notNull().references(() => user.id)" ), - expiresAt: common.expressionFromString(`datetime('expires_at').notNull()`) + expiresAt: common.expressionFromString("datetime('expires_at').notNull()") }); } if (drizzleDialect === 'postgresql') { @@ -173,21 +173,21 @@ export default defineAdder({ timestamp: 'timestamp' }); object.overrideProperties(userAttributes, { - id: common.expressionFromString(`text('id').primaryKey()`) + id: common.expressionFromString("text('id').primaryKey()") }); if (options.demo) { object.overrideProperties(userAttributes, { - username: common.expressionFromString(`text('username').notNull().unique()`), - passwordHash: common.expressionFromString(`text('password_hash').notNull()`) + username: common.expressionFromString("text('username').notNull().unique()"), + passwordHash: common.expressionFromString("text('password_hash').notNull()") }); } object.overrideProperties(sessionAttributes, { - id: common.expressionFromString(`text('id').primaryKey()`), + id: common.expressionFromString("text('id').primaryKey()"), userId: common.expressionFromString( - `text('user_id').notNull().references(() => user.id)` + "text('user_id').notNull().references(() => user.id)" ), expiresAt: common.expressionFromString( - `timestamp('expires_at', { withTimezone: true, mode: 'date' }).notNull()` + "timestamp('expires_at', { withTimezone: true, mode: 'date' }).notNull()" ) }); } @@ -396,7 +396,7 @@ export default defineAdder({ import * as auth from '$lib/server/auth'; import { db } from '$lib/server/db'; import * as table from '$lib/server/db/schema'; - ${ts(`import type { Actions, PageServerLoad } from './$types';\n`)} + ${ts("import type { Actions, PageServerLoad } from './$types';\n")} export const load${ts(': PageServerLoad')} = async (event) => { if (event.locals.user) { return redirect(302, '/demo/lucia'); @@ -516,9 +516,9 @@ export default defineAdder({ const svelte5 = !!dependencyVersion('svelte')?.startsWith('5'); const [ts, s5] = utils.createPrinter(typescript, svelte5); return dedent` - @@ -555,7 +555,7 @@ export default defineAdder({ return dedent` import * as auth from '$lib/server/auth'; import { fail, redirect } from '@sveltejs/kit'; - ${ts(`import type { Actions, PageServerLoad } from './$types';\n`)} + ${ts("import type { Actions, PageServerLoad } from './$types';\n")} export const load${ts(': PageServerLoad')} = async (event) => { if (!event.locals.user) { return redirect(302, '/demo/lucia/login'); @@ -590,9 +590,9 @@ export default defineAdder({ const svelte5 = !!dependencyVersion('svelte')?.startsWith('5'); const [ts, s5] = utils.createPrinter(typescript, svelte5); return dedent` - diff --git a/packages/adders/lucia/tests.ts b/packages/adders/lucia/tests.ts deleted file mode 100644 index cf23fa33..00000000 --- a/packages/adders/lucia/tests.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineAdderTests } from '@sveltejs/cli-core'; -import { options } from './index.ts'; - -export const tests = defineAdderTests({ - files: [], - options, - optionValues: [], - tests: [] -}); diff --git a/packages/adders/mdsvex/tests.ts b/packages/adders/mdsvex/tests.ts deleted file mode 100644 index 503d2a1b..00000000 --- a/packages/adders/mdsvex/tests.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { defineAdderTests, type OptionDefinition, type FileEditor } from '@sveltejs/cli-core'; -import { imports } from '@sveltejs/cli-core/js'; -import * as html from '@sveltejs/cli-core/html'; -import { parseSvelte } from '@sveltejs/cli-core/parsers'; - -export const tests = defineAdderTests({ - files: [ - { - name: ({ kit }) => `${kit?.routesDirectory}/+page.svelte`, - content: useMarkdownFile, - condition: ({ kit }) => Boolean(kit) - }, - { - name: () => 'src/App.svelte', - content: useMarkdownFile, - condition: ({ kit }) => !kit - }, - { - name: ({ kit }) => `${kit?.routesDirectory}/Demo.svx`, - content: addMarkdownFile, - condition: ({ kit }) => Boolean(kit) - }, - { - name: () => 'src/Demo.svx', - content: addMarkdownFile, - condition: ({ kit }) => !kit - } - ], - options: {}, - optionValues: [], - tests: [ - { - name: 'elements exist', - run: async ({ elementExists }) => { - await elementExists('.mdsvex h1'); - await elementExists('.mdsvex h2'); - await elementExists('.mdsvex p'); - } - } - ] -}); - -function addMarkdownFile({ content }: FileEditor) { - // example taken from website: https://mdsvex.pngwn.io - return ( - content + - ` ---- -title: Svex up your markdown ---- - -# { title } - -## Good stuff in your markdown - -Markdown is pretty good but sometimes you just need more. -` - ); -} - -function useMarkdownFile({ content }: FileEditor) { - const { script, template, generateCode } = parseSvelte(content); - imports.addDefault(script.ast, './Demo.svx', 'Demo'); - - const div = html.div({ class: 'mdsvex' }); - html.appendElement(template.ast.childNodes, div); - const mdsvexNode = html.element('Demo'); - html.appendElement(div.childNodes, mdsvexNode); - return generateCode({ script: script.generateCode(), template: template.generateCode() }); -} diff --git a/packages/adders/package.json b/packages/adders/package.json index c580c405..05a0f370 100644 --- a/packages/adders/package.json +++ b/packages/adders/package.json @@ -6,14 +6,11 @@ "scripts": { "check": "tsc", "format": "pnpm lint --write", - "lint": "prettier --check . --config ../../prettier.config.js --ignore-path ../../.gitignore --ignore-path .gitignore --ignore-path ../../.prettierignore" - }, - "exports": { - ".": { - "types": "./index.ts", - "default": "./index.ts" - } + "lint": "prettier --check . --config ../../prettier.config.js --ignore-path ../../.gitignore --ignore-path .gitignore --ignore-path ../../.prettierignore", + "test": "vitest run", + "test:ui": "vitest --ui" }, + "exports": "./index.ts", "dependencies": { "@sveltejs/cli-core": "workspace:*" } diff --git a/packages/adders/paraglide/index.ts b/packages/adders/paraglide/index.ts index 459f0295..b2f1b49d 100644 --- a/packages/adders/paraglide/index.ts +++ b/packages/adders/paraglide/index.ts @@ -32,7 +32,7 @@ const DEFAULT_INLANG_PROJECT = { } }; -export const options = defineAdderOptions({ +const options = defineAdderOptions({ availableLanguageTags: { question: `Which languages would you like to support? ${colors.gray('(e.g. en,de-ch)')}`, type: 'string', diff --git a/packages/adders/paraglide/tests.ts b/packages/adders/paraglide/tests.ts deleted file mode 100644 index 8941a20b..00000000 --- a/packages/adders/paraglide/tests.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineAdderTests } from '@sveltejs/cli-core'; -import { options } from './index.ts'; -// e2e tests make no sense in this context - -export const tests = defineAdderTests({ - files: [], - options, - optionValues: [], - tests: [] -}); diff --git a/packages/adders/playwright/tests.ts b/packages/adders/playwright/tests.ts deleted file mode 100644 index 764975ed..00000000 --- a/packages/adders/playwright/tests.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineAdderTests } from '@sveltejs/cli-core'; - -export const tests = defineAdderTests({ - files: [], - options: {}, - optionValues: [], - tests: [] -}); diff --git a/packages/adders/prettier/tests.ts b/packages/adders/prettier/tests.ts deleted file mode 100644 index 764975ed..00000000 --- a/packages/adders/prettier/tests.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineAdderTests } from '@sveltejs/cli-core'; - -export const tests = defineAdderTests({ - files: [], - options: {}, - optionValues: [], - tests: [] -}); diff --git a/packages/adders/storybook/index.ts b/packages/adders/storybook/index.ts index 9a76cbef..20fdc5e8 100644 --- a/packages/adders/storybook/index.ts +++ b/packages/adders/storybook/index.ts @@ -9,7 +9,7 @@ export default defineAdder({ scripts: [ { description: 'applies storybook', - args: ['storybook@latest', 'init', '--skip-install', '--no-dev'], + args: ['storybook@8.3.6', 'init', '--skip-install', '--no-dev'], stdio: 'inherit' } ], diff --git a/packages/adders/storybook/tests.ts b/packages/adders/storybook/tests.ts deleted file mode 100644 index 5fb56a32..00000000 --- a/packages/adders/storybook/tests.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { defineAdderTests } from '@sveltejs/cli-core'; - -let port = 6006; - -export const tests = defineAdderTests({ - options: {}, - optionValues: [], - get command() { - return `storybook -p ${port++} --ci`; - }, - files: [], - tests: [ - { - name: 'storybook loaded', - run: async ({ elementExists }) => { - await elementExists('main .sb-bar'); - await elementExists('#storybook-preview-wrapper'); - } - } - ] -}); diff --git a/packages/adders/tailwindcss/index.ts b/packages/adders/tailwindcss/index.ts index 4993f9fb..b0f30d33 100644 --- a/packages/adders/tailwindcss/index.ts +++ b/packages/adders/tailwindcss/index.ts @@ -45,7 +45,7 @@ const pluginPackages: Array> = plugins.map((x) condition: ({ options }) => options.plugins.includes(x.id) })); -export const options = defineAdderOptions({ +const options = defineAdderOptions({ plugins: { type: 'multiselect', question: 'Which plugins would you like to add?', diff --git a/packages/adders/tailwindcss/tests.ts b/packages/adders/tailwindcss/tests.ts deleted file mode 100644 index ea28b2af..00000000 --- a/packages/adders/tailwindcss/tests.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { defineAdderTests } from '@sveltejs/cli-core'; -import { options } from './index.ts'; - -const divId = 'myDiv'; -const typographyDivId = 'myTypographyDiv'; - -export const tests = defineAdderTests({ - files: [ - { - name: ({ kit }) => `${kit?.routesDirectory}/+page.svelte`, - content: ({ content, options }) => { - content = prepareCoreTest(content); - if (options.plugins.includes('typography')) content = prepareTypographyTest(content); - return content; - }, - condition: ({ kit }) => Boolean(kit) - }, - { - name: () => 'src/App.svelte', - content: ({ content, options }) => { - content = prepareCoreTest(content); - if (options.plugins.includes('typography')) content = prepareTypographyTest(content); - return content; - }, - condition: ({ kit }) => !kit - } - ], - options, - optionValues: [{ plugins: [] }, { plugins: ['typography'] }], - tests: [ - { - name: 'core properties', - run: async ({ expectProperty }) => { - const selector = '#' + divId; - await expectProperty(selector, 'background-color', 'rgb(71, 85, 105)'); - await expectProperty(selector, 'border-color', 'rgb(249, 250, 251)'); - await expectProperty(selector, 'border-width', '4px'); - await expectProperty(selector, 'margin-top', '4px'); - } - }, - { - name: 'typography properties', - condition: ({ plugins }) => plugins.includes('typography'), - run: async ({ expectProperty }) => { - const selector = '#' + typographyDivId; - await expectProperty(selector, 'font-size', '18px'); - await expectProperty(selector, 'line-height', '28px'); - await expectProperty(selector, 'text-align', 'right'); - await expectProperty(selector, 'text-decoration-line', 'line-through'); - } - } - ] -}); - -function prepareCoreTest(content: string) { - const div = `
`; - return content + div; -} - -function prepareTypographyTest(content: string) { - const p = `

`; - return content + p; -} diff --git a/packages/adders/vitest/index.ts b/packages/adders/vitest-addon/index.ts similarity index 100% rename from packages/adders/vitest/index.ts rename to packages/adders/vitest-addon/index.ts diff --git a/packages/adders/vitest/logo.svg b/packages/adders/vitest-addon/logo.svg similarity index 100% rename from packages/adders/vitest/logo.svg rename to packages/adders/vitest-addon/logo.svg diff --git a/packages/adders/vitest.config.ts b/packages/adders/vitest.config.ts new file mode 100644 index 00000000..9f43ca88 --- /dev/null +++ b/packages/adders/vitest.config.ts @@ -0,0 +1,15 @@ +import { env } from 'node:process'; +import { defineConfig } from 'vitest/config'; + +const ONE_MINUTE = 1000 * 60; + +export default defineConfig({ + test: { + name: 'adders', + include: ['_tests/**/test.{js,ts}'], + globalSetup: ['_tests/_setup/global.ts'], + testTimeout: ONE_MINUTE * 3, + hookTimeout: ONE_MINUTE * 3, + retry: env.CI ? 3 : 0 + } +}); diff --git a/packages/adders/vitest/tests.ts b/packages/adders/vitest/tests.ts deleted file mode 100644 index 764975ed..00000000 --- a/packages/adders/vitest/tests.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineAdderTests } from '@sveltejs/cli-core'; - -export const tests = defineAdderTests({ - files: [], - options: {}, - optionValues: [], - tests: [] -}); diff --git a/packages/cli/bin.ts b/packages/cli/bin.ts index 4a4c8924..838dda5d 100644 --- a/packages/cli/bin.ts +++ b/packages/cli/bin.ts @@ -6,7 +6,7 @@ import { add } from './commands/add/index.ts'; import { create } from './commands/create.ts'; import { migrate } from './commands/migrate.ts'; import { check } from './commands/check.ts'; -import { helpConfig } from './common.ts'; +import { helpConfig } from './utils/common.ts'; program.name(pkg.name).version(pkg.version, '-v, --version').configureHelp(helpConfig); program.addCommand(create).addCommand(add).addCommand(migrate).addCommand(check); diff --git a/packages/cli/utils/fetch-packages.ts b/packages/cli/commands/add/fetch-packages.ts similarity index 98% rename from packages/cli/utils/fetch-packages.ts rename to packages/cli/commands/add/fetch-packages.ts index 9bb3e8ff..d14be995 100644 --- a/packages/cli/utils/fetch-packages.ts +++ b/packages/cli/commands/add/fetch-packages.ts @@ -7,7 +7,7 @@ import { fileURLToPath } from 'node:url'; import type { AdderWithoutExplicitArgs } from '@sveltejs/cli-core'; // path to the `node_modules` directory of `sv` -const NODE_MODULES = path.join(fileURLToPath(import.meta.url), '..', '..', 'node_modules'); +const NODE_MODULES = fileURLToPath(new URL('../node_modules', import.meta.url)); const REGISTRY = 'https://registry.npmjs.org'; export const Directive = { file: 'file:', npm: 'npm:' }; diff --git a/packages/cli/commands/add/index.ts b/packages/cli/commands/add/index.ts index a91ea35c..de05a29b 100644 --- a/packages/cli/commands/add/index.ts +++ b/packages/cli/commands/add/index.ts @@ -15,11 +15,13 @@ import { getCommunityAdder } from '@sveltejs/adders'; import type { AdderWithoutExplicitArgs, OptionValues } from '@sveltejs/cli-core'; -import * as common from '../../common.ts'; -import { Directive, downloadPackage, getPackageJSON } from '../../utils/fetch-packages.ts'; +import * as common from '../../utils/common.ts'; import { createWorkspace } from './workspace.ts'; -import { getHighlighter, installPackages } from './utils.ts'; import { createOrUpdateFiles } from './processor.ts'; +import { getGlobalPreconditions } from './preconditions.ts'; +import { formatFiles, getHighlighter, installPackages } from './utils.ts'; +import { Directive, downloadPackage, getPackageJSON } from './fetch-packages.ts'; +import { installDependencies, packageManagerPrompt } from '../../utils/package-manager.ts'; const AddersSchema = v.array(v.string()); const AdderOptionFlagsSchema = v.object({ @@ -333,7 +335,7 @@ export async function runAddCommand( const { kit } = createWorkspace({ cwd: options.cwd }); const projectType = kit ? 'kit' : 'svelte'; const adders = selectedAdders.map(({ adder }) => adder); - const { preconditions } = common.getGlobalPreconditions(options.cwd, projectType, adders); + const { preconditions } = getGlobalPreconditions(options.cwd, projectType, adders); const fails: Array<{ name: string; message?: string }> = []; for (const condition of preconditions) { @@ -425,7 +427,7 @@ export async function runAddCommand( // prompt for package manager let packageManager: AgentName | undefined; if (options.install) { - packageManager = await common.packageManagerPrompt(options.cwd); + packageManager = await packageManagerPrompt(options.cwd); } // apply adders @@ -434,7 +436,7 @@ export async function runAddCommand( // install dependencies if (packageManager && options.install) { - await common.installDependencies(packageManager, options.cwd); + await installDependencies(packageManager, options.cwd); } // format modified/created files with prettier (if available) @@ -443,7 +445,7 @@ export async function runAddCommand( const { start, stop } = p.spinner(); start('Formatting modified files'); try { - await common.formatFiles({ packageManager, cwd: options.cwd, paths: filesToFormat }); + await formatFiles({ packageManager, cwd: options.cwd, paths: filesToFormat }); stop('Successfully formatted modified files'); } catch (e) { stop('Failed to format files'); @@ -545,7 +547,10 @@ async function runAdders({ if (workspace.packageManager === 'npm') args.unshift('--yes'); try { - await exec(command, args, { nodeOptions: { cwd: workspace.cwd, stdio: script.stdio } }); + await exec(command, args, { + nodeOptions: { cwd: workspace.cwd, stdio: script.stdio }, + throwOnError: true + }); } catch (error) { const typedError = error as Error; throw new Error( diff --git a/packages/cli/commands/add/preconditions.ts b/packages/cli/commands/add/preconditions.ts new file mode 100644 index 00000000..50f90098 --- /dev/null +++ b/packages/cli/commands/add/preconditions.ts @@ -0,0 +1,66 @@ +import { exec } from 'tinyexec'; +import type { AdderWithoutExplicitArgs, Precondition } from '@sveltejs/cli-core'; + +type PreconditionCheck = { name: string; preconditions: Precondition[] }; +export function getGlobalPreconditions( + cwd: string, + projectType: 'svelte' | 'kit', + adders: AdderWithoutExplicitArgs[] +): PreconditionCheck { + return { + name: 'global checks', + preconditions: [ + { + name: 'clean working directory', + run: async () => { + try { + // If a user has pending git changes the output of the following command will list + // all files that have been added/modified/deleted and thus the output will not be empty. + // In case the output of the command below is an empty text, we can safely assume + // there are no pending changes. If the below command is run outside of a git repository, + // git will exit with a failing exit code, which will trigger the catch statement. + // also see https://remarkablemark.org/blog/2017/10/12/check-git-dirty/#git-status + const { stdout } = await exec('git', ['status', '--short'], { + nodeOptions: { cwd }, + throwOnError: true + }); + + if (stdout) { + return { success: false, message: 'Found modified files' }; + } + + return { success: true, message: undefined }; + } catch { + return { success: true, message: 'Not a git repository' }; + } + } + }, + { + name: 'supported environments', + run: () => { + const addersForInvalidEnvironment = adders.filter((a) => { + const supportedEnvironments = a.environments; + if (projectType === 'kit' && !supportedEnvironments.kit) return true; + if (projectType === 'svelte' && !supportedEnvironments.svelte) return true; + + return false; + }); + + if (addersForInvalidEnvironment.length === 0) { + return { success: true, message: undefined }; + } + + const messages = addersForInvalidEnvironment.map((a) => { + if (projectType === 'kit') { + return `'${a.id}' does not support SvelteKit`; + } else { + return `'${a.id}' requires SvelteKit`; + } + }); + + throw new Error(messages.join('\n')); + } + } + ] + }; +} diff --git a/packages/cli/commands/add/processor.ts b/packages/cli/commands/add/processor.ts index 8f635243..46c3e7c8 100644 --- a/packages/cli/commands/add/processor.ts +++ b/packages/cli/commands/add/processor.ts @@ -21,12 +21,14 @@ export function createOrUpdateFiles( let content = exists ? readFile(workspace.cwd, fileDetails.name(workspace)) : ''; // process file content = fileDetails.content({ content, ...workspace }); + if (!content) continue; writeFile(workspace, fileDetails.name(workspace), content); changedFiles.push(fileDetails.name(workspace)); } catch (e) { - if (e instanceof Error) + if (e instanceof Error) { throw new Error(`Unable to process '${fileDetails.name(workspace)}'. Reason: ${e.message}`); + } throw e; } } diff --git a/packages/cli/commands/add/utils.ts b/packages/cli/commands/add/utils.ts index 0651fadf..55051644 100644 --- a/packages/cli/commands/add/utils.ts +++ b/packages/cli/commands/add/utils.ts @@ -1,8 +1,10 @@ import fs from 'node:fs'; import path from 'node:path'; import pc from 'picocolors'; +import { exec } from 'tinyexec'; import { parseJson } from '@sveltejs/cli-core/parsers'; import type { Adder, Highlighter, Workspace } from '@sveltejs/cli-core'; +import { resolveCommand, type AgentName } from 'package-manager-detector'; export type Package = { name: string; @@ -15,7 +17,11 @@ export type Package = { workspaces?: string[]; }; -export function getPackageJson(cwd: string) { +export function getPackageJson(cwd: string): { + source: string; + data: Package; + generateCode: () => string; +} { const packageText = readFile(cwd, commonFilePaths.packageJson); if (!packageText) { const pkgPath = path.join(cwd, commonFilePaths.packageJson); @@ -26,8 +32,21 @@ export function getPackageJson(cwd: string) { return { source: packageText, data: data as Package, generateCode }; } +export async function formatFiles(options: { + packageManager: AgentName; + cwd: string; + paths: string[]; +}): Promise { + const args = ['prettier', '--write', '--ignore-unknown', ...options.paths]; + const cmd = resolveCommand(options.packageManager, 'execute-local', args)!; + await exec(cmd.command, cmd.args, { + nodeOptions: { cwd: options.cwd, stdio: 'pipe' }, + throwOnError: true + }); +} + export function readFile(cwd: string, filePath: string): string { - const fullFilePath = getFilePath(cwd, filePath); + const fullFilePath = path.resolve(cwd, filePath); if (!fileExists(cwd, filePath)) { return ''; @@ -72,7 +91,7 @@ function alphabetizeProperties(obj: Record) { } export function writeFile(workspace: Workspace, filePath: string, content: string): void { - const fullFilePath = getFilePath(workspace.cwd, filePath); + const fullFilePath = path.resolve(workspace.cwd, filePath); const fullDirectoryPath = path.dirname(fullFilePath); if (content && !content.endsWith('\n')) content += '\n'; @@ -85,14 +104,10 @@ export function writeFile(workspace: Workspace, filePath: string, content: } export function fileExists(cwd: string, filePath: string): boolean { - const fullFilePath = getFilePath(cwd, filePath); + const fullFilePath = path.resolve(cwd, filePath); return fs.existsSync(fullFilePath); } -export function getFilePath(cwd: string, fileName: string): string { - return path.join(cwd, fileName); -} - export const commonFilePaths = { packageJson: 'package.json', svelteConfig: 'svelte.config.js', diff --git a/packages/cli/commands/add/workspace.ts b/packages/cli/commands/add/workspace.ts index 6e93d7e5..ac4d396f 100644 --- a/packages/cli/commands/add/workspace.ts +++ b/packages/cli/commands/add/workspace.ts @@ -3,11 +3,11 @@ import path from 'node:path'; import * as find from 'empathic/find'; import { common, object, type AstTypes } from '@sveltejs/cli-core/js'; import { parseScript } from '@sveltejs/cli-core/parsers'; -import { TESTING } from '../../env.ts'; -import { getUserAgent } from '../../common.ts'; -import { commonFilePaths, getPackageJson, readFile } from './utils.ts'; import type { Workspace } from '@sveltejs/cli-core'; import type { AgentName } from 'package-manager-detector'; +import { TESTING } from '../../utils/env.ts'; +import { commonFilePaths, getPackageJson, readFile } from './utils.ts'; +import { getUserAgent } from '../../utils/package-manager.ts'; type CreateWorkspaceOptions = { cwd: string; packageManager?: AgentName }; export function createWorkspace({ cwd, packageManager }: CreateWorkspaceOptions): Workspace { diff --git a/packages/cli/commands/check.ts b/packages/cli/commands/check.ts index eb925103..23797d20 100644 --- a/packages/cli/commands/check.ts +++ b/packages/cli/commands/check.ts @@ -1,10 +1,10 @@ -import { execSync } from 'node:child_process'; import process from 'node:process'; +import { execSync } from 'node:child_process'; import pc from 'picocolors'; -import * as resolve from 'empathic/resolve'; import { Command } from 'commander'; +import * as resolve from 'empathic/resolve'; import { resolveCommand } from 'package-manager-detector/commands'; -import { getUserAgent } from '../common.ts'; +import { getUserAgent } from '../utils/package-manager.ts'; export const check = new Command('check') .description('a CLI for checking your Svelte code') diff --git a/packages/cli/commands/create.ts b/packages/cli/commands/create.ts index 8f1f0130..dd93c4f1 100644 --- a/packages/cli/commands/create.ts +++ b/packages/cli/commands/create.ts @@ -11,9 +11,14 @@ import { type LanguageType, type TemplateType } from '@sveltejs/create'; -import * as common from '../common.js'; +import * as common from '../utils/common.ts'; import { runAddCommand } from './add/index.ts'; import { detectSync, type AgentName } from 'package-manager-detector'; +import { + getUserAgent, + installDependencies, + packageManagerPrompt +} from '../utils/package-manager.ts'; const langs = ['ts', 'jsdoc'] as const; const langMap: Record = { @@ -59,8 +64,7 @@ export const create = new Command('create') let i = 1; const initialSteps: string[] = []; const relative = path.relative(process.cwd(), directory); - const pm = - packageManager ?? detectSync({ cwd: directory })?.name ?? common.getUserAgent() ?? 'npm'; + const pm = packageManager ?? detectSync({ cwd: directory })?.name ?? getUserAgent() ?? 'npm'; if (relative !== '') { const pathHasSpaces = relative.includes(' '); initialSteps.push( @@ -157,8 +161,8 @@ async function createProject(cwd: ProjectPath, options: Options) { let packageManager: AgentName | undefined | null; let addOnNextSteps: string | undefined; const installDeps = async () => { - packageManager = await common.packageManagerPrompt(projectPath); - if (packageManager) await common.installDependencies(packageManager, projectPath); + packageManager = await packageManagerPrompt(projectPath); + if (packageManager) await installDependencies(packageManager, projectPath); }; if (options.addOns) { diff --git a/packages/cli/commands/migrate.ts b/packages/cli/commands/migrate.ts index 88a5dd7c..b3fecb36 100644 --- a/packages/cli/commands/migrate.ts +++ b/packages/cli/commands/migrate.ts @@ -2,7 +2,7 @@ import { execSync } from 'node:child_process'; import process from 'node:process'; import { Command } from 'commander'; import { resolveCommand } from 'package-manager-detector'; -import { getUserAgent } from '../common.ts'; +import { getUserAgent } from '../utils/package-manager.ts'; export const migrate = new Command('migrate') .description('a CLI for migrating Svelte(Kit) codebases') diff --git a/packages/cli/common.ts b/packages/cli/common.ts deleted file mode 100644 index de39f0a2..00000000 --- a/packages/cli/common.ts +++ /dev/null @@ -1,200 +0,0 @@ -import process from 'node:process'; -import pc from 'picocolors'; -import pkg from './package.json'; -import { exec } from 'tinyexec'; -import * as p from '@sveltejs/clack-prompts'; -import { AGENTS, type AgentName, detectSync } from 'package-manager-detector'; -import { COMMANDS, constructCommand, resolveCommand } from 'package-manager-detector/commands'; -import type { Argument, HelpConfiguration, Option } from 'commander'; -import type { AdderWithoutExplicitArgs, Precondition } from '@sveltejs/cli-core'; - -const NO_PREFIX = '--no-'; -let options: readonly Option[] = []; - -function getLongFlag(flags: string) { - return flags - .split(',') - .map((f) => f.trim()) - .find((f) => f.startsWith('--')); -} - -export const helpConfig: HelpConfiguration = { - argumentDescription: formatDescription, - optionDescription: formatDescription, - visibleOptions(cmd) { - // hack so that we can access existing options in `optionTerm` - options = cmd.options; - - const visible = cmd.options.filter((o) => !o.hidden); - const show: Option[] = []; - // hide any `--no-` flag variants if there's an existing flag of a similar name - // e.g. `--types` and `--no-types` will combine into a single `--[no-]types` flag - for (const option of visible) { - const flag = getLongFlag(option.flags); - if (flag?.startsWith(NO_PREFIX)) { - const stripped = flag.slice(NO_PREFIX.length); - const isNoVariant = visible.some((o) => getLongFlag(o.flags)?.startsWith(`--${stripped}`)); - if (isNoVariant) continue; - } - show.push(option); - } - return show; - }, - optionTerm(option) { - const longFlag = getLongFlag(option.flags); - const flag = longFlag?.split(' ').at(0); - if (!flag || !longFlag) return option.flags; - - // check if there's a `--no-{flag}` variant - const noVariant = `--no-${flag.slice(2)}`; - const hasVariant = options.some((o) => getLongFlag(o.flags) === noVariant); - if (hasVariant) { - return `--[no-]${longFlag.slice(2)}`; - } - - return option.flags; - } -}; - -function formatDescription(arg: Option | Argument): string { - let output = arg.description; - if (arg.defaultValue !== undefined && String(arg.defaultValue)) { - output += pc.dim(` (default: ${JSON.stringify(arg.defaultValue)})`); - } - if (arg.argChoices !== undefined && String(arg.argChoices)) { - output += pc.dim(` (choices: ${arg.argChoices.join(', ')})`); - } - return output; -} - -type MaybePromise = () => Promise | void; - -export async function runCommand(action: MaybePromise) { - try { - p.intro(`Welcome to the Svelte CLI! ${pc.gray(`(v${pkg.version})`)}`); - await action(); - p.outro("You're all set!"); - } catch (e) { - p.cancel('Operation failed.'); - if (e instanceof Error) { - console.error(e.stack ?? e); - } - } -} - -export async function formatFiles(options: { - packageManager: AgentName; - cwd: string; - paths: string[]; -}): Promise { - const args = ['prettier', '--write', '--ignore-unknown', ...options.paths]; - const cmd = resolveCommand(options.packageManager, 'execute-local', args)!; - await exec(cmd.command, cmd.args, { nodeOptions: { cwd: options.cwd, stdio: 'pipe' } }); -} - -const agents = AGENTS.filter((agent): agent is AgentName => !agent.includes('@')); -const agentOptions: PackageManagerOptions = agents.map((pm) => ({ value: pm, label: pm })); -agentOptions.unshift({ label: 'None', value: undefined }); - -type PackageManagerOptions = Array<{ value: AgentName | undefined; label: AgentName | 'None' }>; -export async function packageManagerPrompt(cwd: string): Promise { - const detected = detectSync({ cwd }); - const agent = detected?.name ?? getUserAgent(); - - const pm = await p.select({ - message: 'Which package manager do you want to install dependencies with?', - options: agentOptions, - initialValue: agent - }); - if (p.isCancel(pm)) { - p.cancel('Operation cancelled.'); - process.exit(1); - } - - return pm; -} - -export async function installDependencies(agent: AgentName, cwd: string) { - const spinner = p.spinner(); - spinner.start('Installing dependencies...'); - try { - const { command, args } = constructCommand(COMMANDS[agent].install, [])!; - await exec(command, args, { nodeOptions: { cwd } }); - - spinner.stop('Successfully installed dependencies'); - } catch (error) { - spinner.stop('Failed to install dependencies', 2); - throw error; - } -} - -export function getUserAgent(): AgentName | undefined { - const userAgent = process.env.npm_config_user_agent; - if (!userAgent) return undefined; - - const pmSpec = userAgent.split(' ')[0]!; - const separatorPos = pmSpec.lastIndexOf('/'); - const name = pmSpec.substring(0, separatorPos) as AgentName; - return AGENTS.includes(name) ? name : undefined; -} - -type PreconditionCheck = { name: string; preconditions: Precondition[] }; -export function getGlobalPreconditions( - cwd: string, - projectType: 'svelte' | 'kit', - adders: AdderWithoutExplicitArgs[] -): PreconditionCheck { - return { - name: 'global checks', - preconditions: [ - { - name: 'clean working directory', - run: async () => { - try { - // If a user has pending git changes the output of the following command will list - // all files that have been added/modified/deleted and thus the output will not be empty. - // In case the output of the command below is an empty text, we can safely assume - // there are no pending changes. If the below command is run outside of a git repository, - // git will exit with a failing exit code, which will trigger the catch statement. - // also see https://remarkablemark.org/blog/2017/10/12/check-git-dirty/#git-status - const { stdout } = await exec('git', ['status', '--short'], { nodeOptions: { cwd } }); - - if (stdout) { - return { success: false, message: 'Found modified files' }; - } - - return { success: true, message: undefined }; - } catch { - return { success: true, message: 'Not a git repository' }; - } - } - }, - { - name: 'supported environments', - run: () => { - const addersForInvalidEnvironment = adders.filter((a) => { - const supportedEnvironments = a.environments; - if (projectType === 'kit' && !supportedEnvironments.kit) return true; - if (projectType === 'svelte' && !supportedEnvironments.svelte) return true; - - return false; - }); - - if (addersForInvalidEnvironment.length === 0) { - return { success: true, message: undefined }; - } - - const messages = addersForInvalidEnvironment.map((a) => { - if (projectType === 'kit') { - return `'${a.id}' does not support SvelteKit`; - } else { - return `'${a.id}' requires SvelteKit`; - } - }); - - throw new Error(messages.join('\n')); - } - } - ] - }; -} diff --git a/packages/cli/env.ts b/packages/cli/env.ts deleted file mode 100644 index d482918b..00000000 --- a/packages/cli/env.ts +++ /dev/null @@ -1,3 +0,0 @@ -import process from 'node:process'; - -export const TESTING: boolean = process.env.CI?.toLowerCase() === 'true'; diff --git a/packages/cli/index.ts b/packages/cli/index.ts deleted file mode 100644 index 50f83ec1..00000000 --- a/packages/cli/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { create } from '@sveltejs/create'; - -export { create }; diff --git a/packages/cli/lib/index.ts b/packages/cli/lib/index.ts new file mode 100644 index 00000000..13aa9292 --- /dev/null +++ b/packages/cli/lib/index.ts @@ -0,0 +1,3 @@ +export { create } from '@sveltejs/create'; +export { installAddon } from './install.ts'; +export type { AddonMap, InstallOptions, OptionMap } from './install.ts'; diff --git a/packages/cli/lib/install.ts b/packages/cli/lib/install.ts new file mode 100644 index 00000000..555da7e8 --- /dev/null +++ b/packages/cli/lib/install.ts @@ -0,0 +1,95 @@ +import { exec } from 'tinyexec'; +import { resolveCommand } from 'package-manager-detector'; +import type { Adder, Workspace, PackageManager, OptionValues, Question } from '@sveltejs/cli-core'; +import { installPackages } from '../commands/add/utils.ts'; +import { createWorkspace } from '../commands/add/workspace.ts'; +import { createOrUpdateFiles } from '../commands/add/processor.ts'; + +type Addon = Adder; +export type InstallOptions = { + cwd: string; + addons: Addons; + options: OptionMap; + packageManager: PackageManager; +}; + +export type AddonMap = Record; +export type OptionMap = { + [K in keyof Addons]: Partial>; +}; + +export async function installAddon({ + addons, + cwd, + options, + packageManager = 'npm' +}: InstallOptions): Promise { + const filesToFormat = new Set(); + + const mapped = Object.entries(addons).map(([, addon]) => addon); + const ordered = orderAddons(mapped); + + for (const addon of ordered) { + const workspace = createWorkspace({ cwd, packageManager }); + workspace.options = options[addon.id]; + + const files = await runAddon(workspace, addon); + files.forEach((f) => filesToFormat.add(f)); + } + + return Array.from(filesToFormat); +} + +async function runAddon( + workspace: Workspace, + addon: Adder> +): Promise { + const files = new Set(); + + // apply default adder options + for (const [, question] of Object.entries(addon.options)) { + // we'll only apply defaults to options that don't explicitly fail their conditions + if (question.condition?.(workspace.options) !== false) { + workspace.options ??= question.default; + } + } + + await addon.preInstall?.(workspace); + const pkgPath = installPackages(addon, workspace); + files.add(pkgPath); + const changedFiles = createOrUpdateFiles(addon.files, workspace); + changedFiles.forEach((file) => files.add(file)); + await addon.postInstall?.(workspace); + + for (const script of addon.scripts ?? []) { + if (script.condition?.(workspace) === false) continue; + + try { + const { args, command } = resolveCommand(workspace.packageManager, 'execute', script.args)!; + if (workspace.packageManager === 'npm') args.unshift('--yes'); + await exec(command, args, { + nodeOptions: { cwd: workspace.cwd, stdio: 'pipe' }, + throwOnError: true + }); + } catch (error) { + const typedError = error as Error; + throw new Error(`Failed to execute scripts '${script.description}': ` + typedError.message); + } + } + + return Array.from(files); +} + +// sorts them to their execution order +function orderAddons(addons: Addon[]) { + return Array.from(addons).sort((a, b) => { + if (!a.dependsOn && !b.dependsOn) return 0; + if (!a.dependsOn) return -1; + if (!b.dependsOn) return 1; + + if (a.dependsOn.includes(b.id)) return 1; + if (b.dependsOn.includes(a.id)) return -1; + + return 0; + }); +} diff --git a/packages/cli/lib/testing.ts b/packages/cli/lib/testing.ts new file mode 100644 index 00000000..62857525 --- /dev/null +++ b/packages/cli/lib/testing.ts @@ -0,0 +1,151 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import degit from 'degit'; +import { exec } from 'tinyexec'; +import { create } from '@sveltejs/create'; +import pstree, { type PS } from 'ps-tree'; + +export type ProjectVariant = 'kit-js' | 'kit-ts' | 'vite-js' | 'vite-ts'; + +const TEMPLATES_DIR = '.templates'; + +export type CreateProject = (options: { + testId: string; + variant: ProjectVariant; + /** @default true */ + clean?: boolean; +}) => string; + +type SetupOptions = { + cwd: string; + variants: readonly ProjectVariant[]; + /** @default false */ + clean?: boolean; +}; +export async function setup({ + cwd, + clean = false, + variants +}: SetupOptions): Promise<{ templatesDir: string }> { + const workingDir = path.resolve(cwd); + if (clean && fs.existsSync(workingDir)) { + fs.rmSync(workingDir, { force: true, recursive: true }); + } + + // fetch the project types + const templatesDir = path.resolve(workingDir, TEMPLATES_DIR); + fs.mkdirSync(templatesDir, { recursive: true }); + for (const variant of variants) { + const templatePath = path.resolve(templatesDir, variant); + if (fs.existsSync(templatePath)) continue; + + if (variant === 'kit-js') { + create(templatePath, { name: variant, template: 'minimal', types: 'checkjs' }); + } else if (variant === 'kit-ts') { + create(templatePath, { name: variant, template: 'minimal', types: 'typescript' }); + } else if (variant === 'vite-js' || variant === 'vite-ts') { + const name = `template-svelte${variant === 'vite-ts' ? '-ts' : ''}`; + // TODO: should probably point this to a specific commit hash (ex: `#1234abcd`) + const template = degit(`vitejs/vite/packages/create-vite/${name}`, { force: true }); + await template.clone(templatePath); + + // vite templates have their gitignore file named as `_gitignore` + const gitignorePath = path.resolve(templatePath, '_gitignore'); + if (fs.existsSync(gitignorePath)) { + const fixedPath = path.resolve(templatePath, '.gitignore'); + fs.renameSync(gitignorePath, fixedPath); + } + } else { + throw new Error(`Unknown project variant: ${variant}`); + } + } + + return { templatesDir }; +} + +type CreateOptions = { cwd: string; testName: string; templatesDir: string }; +export function createProject({ cwd, testName, templatesDir }: CreateOptions): CreateProject { + // create the reference dir + const testDir = path.resolve(cwd, testName); + fs.mkdirSync(testDir, { recursive: true }); + return ({ testId, variant, clean = true }) => { + const targetDir = path.resolve(testDir, testId); + if (clean && fs.existsSync(targetDir)) { + fs.rmSync(targetDir, { force: true, recursive: true }); + } + const templatePath = path.resolve(templatesDir, variant); + fs.cpSync(templatePath, targetDir, { recursive: true, force: true }); + return targetDir; + }; +} + +type PreviewOptions = { cwd: string; command?: string }; +export async function startPreview({ + cwd, + command = 'npm run preview' +}: PreviewOptions): Promise<{ url: string; close: () => Promise }> { + const [cmd, ...args] = command.split(' '); + const proc = exec(cmd, args, { + nodeOptions: { cwd, stdio: 'pipe' }, + throwOnError: true, + timeout: 60_000 + }); + + const close = async () => { + if (!proc.pid) return; + await terminate(proc.pid); + }; + + return await new Promise((resolve, reject) => { + if (!proc.process?.stdout) return reject('impossible state'); + + proc.process.stdout.on('data', (data: Buffer) => { + const value = data.toString(); + + // extract dev server url from console output + const regexUnicode = /[^\x20-\xaf]+/g; + const withoutUnicode = value.replace(regexUnicode, ''); + + const regexUnicodeDigits = /\[[0-9]{1,2}m/g; + const withoutColors = withoutUnicode.replace(regexUnicodeDigits, ''); + + const regexUrl = /http:\/\/[^:\s]+:[0-9]+\//g; + const urls = withoutColors.match(regexUrl); + + if (urls && urls.length > 0) { + const url = urls[0]; + resolve({ url, close }); + } + }); + }); +} + +async function getProcessTree(pid: number) { + return new Promise((res, rej) => { + pstree(pid, (err, children) => { + if (err) rej(err); + res(children); + }); + }); +} + +async function terminate(pid: number) { + const children = await getProcessTree(pid); + // the process tree is ordered from parents -> children, + // so we'll iterate in the reverse order to terminate the children first + for (let i = children.length - 1; i >= 0; i--) { + const child = children[i]; + const pid = Number(child.PID); + kill(pid); + } + kill(pid); +} + +function kill(pid: number) { + try { + process.kill(pid); + } catch { + // this can happen if a process has been automatically terminated. + } +} diff --git a/packages/cli/package.json b/packages/cli/package.json index 4628db83..291f8afc 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -21,8 +21,12 @@ "bin": "./dist/bin.js", "exports": { ".": { - "types": "./dist/index.d.ts", + "types": "./dist/lib/index.d.ts", "default": "./dist/index.js" + }, + "./testing": { + "types": "./dist/lib/testing.d.ts", + "default": "./dist/testing.js" } }, "devDependencies": { @@ -30,13 +34,17 @@ "@sveltejs/clack-prompts": "workspace:*", "@sveltejs/cli-core": "workspace:*", "@sveltejs/create": "workspace:*", + "@types/degit": "^2.8.6", + "@types/ps-tree": "^1.1.6", "@types/tar-fs": "^2.0.4", "commander": "^12.1.0", + "degit": "^2.8.4", "empathic": "^1.0.0", "package-manager-detector": "^0.2.2", "picocolors": "^1.1.0", + "ps-tree": "^1.2.0", "tar-fs": "^3.0.6", - "tinyexec": "^0.3.0", + "tinyexec": "^0.3.1", "valibot": "^0.41.0" }, "keywords": [ diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json index 6f800349..54c4c150 100644 --- a/packages/cli/tsconfig.json +++ b/packages/cli/tsconfig.json @@ -6,5 +6,5 @@ "declaration": true }, // we'll only want to enforce `isolatedDeclarations` on the library portion of the CLI - "include": ["index.ts"] + "include": ["lib/index.ts", "lib/testing.ts"] } diff --git a/packages/cli/utils/common.ts b/packages/cli/utils/common.ts new file mode 100644 index 00000000..bfcbfd16 --- /dev/null +++ b/packages/cli/utils/common.ts @@ -0,0 +1,78 @@ +import pc from 'picocolors'; +import pkg from '../package.json'; +import * as p from '@sveltejs/clack-prompts'; +import type { Argument, HelpConfiguration, Option } from 'commander'; + +const NO_PREFIX = '--no-'; +let options: readonly Option[] = []; + +function getLongFlag(flags: string) { + return flags + .split(',') + .map((f) => f.trim()) + .find((f) => f.startsWith('--')); +} + +export const helpConfig: HelpConfiguration = { + argumentDescription: formatDescription, + optionDescription: formatDescription, + visibleOptions(cmd) { + // hack so that we can access existing options in `optionTerm` + options = cmd.options; + + const visible = cmd.options.filter((o) => !o.hidden); + const show: Option[] = []; + // hide any `--no-` flag variants if there's an existing flag of a similar name + // e.g. `--types` and `--no-types` will combine into a single `--[no-]types` flag + for (const option of visible) { + const flag = getLongFlag(option.flags); + if (flag?.startsWith(NO_PREFIX)) { + const stripped = flag.slice(NO_PREFIX.length); + const isNoVariant = visible.some((o) => getLongFlag(o.flags)?.startsWith(`--${stripped}`)); + if (isNoVariant) continue; + } + show.push(option); + } + return show; + }, + optionTerm(option) { + const longFlag = getLongFlag(option.flags); + const flag = longFlag?.split(' ').at(0); + if (!flag || !longFlag) return option.flags; + + // check if there's a `--no-{flag}` variant + const noVariant = `--no-${flag.slice(2)}`; + const hasVariant = options.some((o) => getLongFlag(o.flags) === noVariant); + if (hasVariant) { + return `--[no-]${longFlag.slice(2)}`; + } + + return option.flags; + } +}; + +function formatDescription(arg: Option | Argument): string { + let output = arg.description; + if (arg.defaultValue !== undefined && String(arg.defaultValue)) { + output += pc.dim(` (default: ${JSON.stringify(arg.defaultValue)})`); + } + if (arg.argChoices !== undefined && String(arg.argChoices)) { + output += pc.dim(` (choices: ${arg.argChoices.join(', ')})`); + } + return output; +} + +type MaybePromise = () => Promise | void; + +export async function runCommand(action: MaybePromise): Promise { + try { + p.intro(`Welcome to the Svelte CLI! ${pc.gray(`(v${pkg.version})`)}`); + await action(); + p.outro("You're all set!"); + } catch (e) { + p.cancel('Operation failed.'); + if (e instanceof Error) { + console.error(e.stack ?? e); + } + } +} diff --git a/packages/cli/utils/env.ts b/packages/cli/utils/env.ts new file mode 100644 index 00000000..4ab46826 --- /dev/null +++ b/packages/cli/utils/env.ts @@ -0,0 +1,3 @@ +import process from 'node:process'; + +export const TESTING: boolean = process.env.NODE_ENV?.toLowerCase() === 'test'; diff --git a/packages/cli/utils/package-manager.ts b/packages/cli/utils/package-manager.ts new file mode 100644 index 00000000..c0226505 --- /dev/null +++ b/packages/cli/utils/package-manager.ts @@ -0,0 +1,56 @@ +import process from 'node:process'; +import { exec } from 'tinyexec'; +import * as p from '@sveltejs/clack-prompts'; +import { + AGENTS, + COMMANDS, + constructCommand, + detectSync, + type AgentName +} from 'package-manager-detector'; + +const agents = AGENTS.filter((agent): agent is AgentName => !agent.includes('@')); +const agentOptions: PackageManagerOptions = agents.map((pm) => ({ value: pm, label: pm })); +agentOptions.unshift({ label: 'None', value: undefined }); + +type PackageManagerOptions = Array<{ value: AgentName | undefined; label: AgentName | 'None' }>; +export async function packageManagerPrompt(cwd: string): Promise { + const detected = detectSync({ cwd }); + const agent = detected?.name ?? getUserAgent(); + + const pm = await p.select({ + message: 'Which package manager do you want to install dependencies with?', + options: agentOptions, + initialValue: agent + }); + if (p.isCancel(pm)) { + p.cancel('Operation cancelled.'); + process.exit(1); + } + + return pm; +} + +export async function installDependencies(agent: AgentName, cwd: string): Promise { + const spinner = p.spinner(); + spinner.start('Installing dependencies...'); + try { + const { command, args } = constructCommand(COMMANDS[agent].install, [])!; + await exec(command, args, { nodeOptions: { cwd }, throwOnError: true }); + + spinner.stop('Successfully installed dependencies'); + } catch (error) { + spinner.stop('Failed to install dependencies', 2); + throw error; + } +} + +export function getUserAgent(): AgentName | undefined { + const userAgent = process.env.npm_config_user_agent; + if (!userAgent) return undefined; + + const pmSpec = userAgent.split(' ')[0]!; + const separatorPos = pmSpec.lastIndexOf('/'); + const name = pmSpec.substring(0, separatorPos) as AgentName; + return AGENTS.includes(name) ? name : undefined; +} diff --git a/packages/core/adder/workspace.ts b/packages/core/adder/workspace.ts index a03f2877..85bb4fcd 100644 --- a/packages/core/adder/workspace.ts +++ b/packages/core/adder/workspace.ts @@ -14,5 +14,7 @@ export type Workspace = { dependencyVersion: (pkg: string) => string | undefined; typescript: boolean; kit: { libDirectory: string; routesDirectory: string } | undefined; - packageManager: 'npm' | 'yarn' | 'pnpm' | 'bun'; + packageManager: PackageManager; }; + +export type PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun'; diff --git a/packages/core/tests/css/common/add-at-rule/input.css b/packages/core/tests/css/common/add-at-rule/input.css index faa4215a..cedf0a6d 100644 --- a/packages/core/tests/css/common/add-at-rule/input.css +++ b/packages/core/tests/css/common/add-at-rule/input.css @@ -1,3 +1,3 @@ .foo { - color: red; + color: red; } diff --git a/packages/core/tests/css/common/add-at-rule/output.css b/packages/core/tests/css/common/add-at-rule/output.css index ae662e2b..e2a2d26f 100644 --- a/packages/core/tests/css/common/add-at-rule/output.css +++ b/packages/core/tests/css/common/add-at-rule/output.css @@ -1,5 +1,5 @@ @tailwind 'lib/path/file.ext'; .foo { - color: red; + color: red; } -@tailwind 'lib/path/file1.ext' +@tailwind 'lib/path/file1.ext'; diff --git a/packages/core/tests/css/common/add-comment/input.css b/packages/core/tests/css/common/add-comment/input.css index faa4215a..cedf0a6d 100644 --- a/packages/core/tests/css/common/add-comment/input.css +++ b/packages/core/tests/css/common/add-comment/input.css @@ -1,3 +1,3 @@ .foo { - color: red; + color: red; } diff --git a/packages/core/tests/css/common/add-comment/output.css b/packages/core/tests/css/common/add-comment/output.css index cc8bc00f..fbb03f63 100644 --- a/packages/core/tests/css/common/add-comment/output.css +++ b/packages/core/tests/css/common/add-comment/output.css @@ -1,4 +1,4 @@ .foo { - color: red; + color: red; } /* foo comment */ diff --git a/packages/core/tests/css/common/add-imports/input.css b/packages/core/tests/css/common/add-imports/input.css index faa4215a..cedf0a6d 100644 --- a/packages/core/tests/css/common/add-imports/input.css +++ b/packages/core/tests/css/common/add-imports/input.css @@ -1,3 +1,3 @@ .foo { - color: red; + color: red; } diff --git a/packages/core/tests/css/common/add-imports/output.css b/packages/core/tests/css/common/add-imports/output.css index e5b67d82..4f96db19 100644 --- a/packages/core/tests/css/common/add-imports/output.css +++ b/packages/core/tests/css/common/add-imports/output.css @@ -1,4 +1,4 @@ @import 'lib/path/file.css'; .foo { - color: red; + color: red; } diff --git a/packages/core/tests/css/common/add-rule/input.css b/packages/core/tests/css/common/add-rule/input.css index faa4215a..cedf0a6d 100644 --- a/packages/core/tests/css/common/add-rule/input.css +++ b/packages/core/tests/css/common/add-rule/input.css @@ -1,3 +1,3 @@ .foo { - color: red; + color: red; } diff --git a/packages/core/tests/css/common/add-rule/output.css b/packages/core/tests/css/common/add-rule/output.css index 5c63305b..c99b655a 100644 --- a/packages/core/tests/css/common/add-rule/output.css +++ b/packages/core/tests/css/common/add-rule/output.css @@ -1,5 +1,6 @@ .foo { - color: red; -}.bar { - color: blue + color: red; +} +.bar { + color: blue; } diff --git a/packages/core/tests/css/index.ts b/packages/core/tests/css/index.ts index 738e1cb8..77a89d83 100644 --- a/packages/core/tests/css/index.ts +++ b/packages/core/tests/css/index.ts @@ -1,12 +1,17 @@ -import { describe, expect, test } from 'vitest'; -import { parseCss, serializeCss } from '@sveltejs/ast-tooling'; import fs from 'node:fs'; import { join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; +import prettier from 'prettier'; +import { describe, expect, test } from 'vitest'; +import { parseCss, serializeCss } from '@sveltejs/ast-tooling'; const baseDir = resolve(fileURLToPath(import.meta.url), '..'); const categoryDirectories = getDirectoryNames(baseDir); +const prettierConfig = await prettier.resolveConfig(import.meta.url); +if (!prettierConfig) throw new Error('Failed to resolve prettier config'); +prettierConfig.filepath = 'output.css'; + for (const categoryDirectory of categoryDirectories) { describe(categoryDirectory, () => { const testNames = getDirectoryNames(join(baseDir, categoryDirectory)); @@ -23,7 +28,8 @@ for (const categoryDirectory of categoryDirectories) { module.run({ ast }); const output = serializeCss(ast); - await expect(output).toMatchFileSnapshot(`${testDirectoryPath}/output.css`); + const formattedOutput = await prettier.format(output, prettierConfig); + await expect(formattedOutput).toMatchFileSnapshot(`${testDirectoryPath}/output.css`); }); } }); diff --git a/packages/core/tests/html/common/create-div/output.html b/packages/core/tests/html/common/create-div/output.html index f9cce455..d68abe73 100644 --- a/packages/core/tests/html/common/create-div/output.html +++ b/packages/core/tests/html/common/create-div/output.html @@ -1,2 +1,3 @@ -
+
+
diff --git a/packages/core/tests/html/common/create-element/output.html b/packages/core/tests/html/common/create-element/output.html index 351470bd..6a6aa0de 100644 --- a/packages/core/tests/html/common/create-element/output.html +++ b/packages/core/tests/html/common/create-element/output.html @@ -1,2 +1,3 @@ -
+ +
diff --git a/packages/core/tests/html/index.ts b/packages/core/tests/html/index.ts index 6719acd4..dfad1d0d 100644 --- a/packages/core/tests/html/index.ts +++ b/packages/core/tests/html/index.ts @@ -1,12 +1,17 @@ -import { describe, expect, test } from 'vitest'; -import { parseHtml, serializeHtml } from '@sveltejs/ast-tooling'; import fs from 'node:fs'; import { join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; +import prettier from 'prettier'; +import { describe, expect, test } from 'vitest'; +import { parseHtml, serializeHtml } from '@sveltejs/ast-tooling'; const baseDir = resolve(fileURLToPath(import.meta.url), '..'); const categoryDirectories = getDirectoryNames(baseDir); +const prettierConfig = await prettier.resolveConfig(import.meta.url); +if (!prettierConfig) throw new Error('Failed to resolve prettier config'); +prettierConfig.filepath = 'output.html'; + for (const categoryDirectory of categoryDirectories) { describe(categoryDirectory, () => { const testNames = getDirectoryNames(join(baseDir, categoryDirectory)); @@ -23,7 +28,8 @@ for (const categoryDirectory of categoryDirectories) { module.run({ ast }); const output = serializeHtml(ast); - await expect(output).toMatchFileSnapshot(`${testDirectoryPath}/output.html`); + const formattedOutput = await prettier.format(output, prettierConfig); + await expect(formattedOutput).toMatchFileSnapshot(`${testDirectoryPath}/output.html`); }); } }); diff --git a/packages/core/tests/js/arrays/object-array/output.ts b/packages/core/tests/js/arrays/object-array/output.ts index c47de750..1fa08802 100644 --- a/packages/core/tests/js/arrays/object-array/output.ts +++ b/packages/core/tests/js/arrays/object-array/output.ts @@ -1,5 +1,8 @@ -const array = [{ - test: true -}, { - test2: 'string' -}]; \ No newline at end of file +const array = [ + { + test: true + }, + { + test2: 'string' + } +]; diff --git a/packages/core/tests/js/arrays/string-array/output.ts b/packages/core/tests/js/arrays/string-array/output.ts index 7d00f941..e7618b3e 100644 --- a/packages/core/tests/js/arrays/string-array/output.ts +++ b/packages/core/tests/js/arrays/string-array/output.ts @@ -1 +1 @@ -const array = ['test', 'test2']; \ No newline at end of file +const array = ['test', 'test2']; diff --git a/packages/core/tests/js/common/jsdoc-comment/input.ts b/packages/core/tests/js/common/jsdoc-comment/input.ts index c4a1447a..a3423c81 100644 --- a/packages/core/tests/js/common/jsdoc-comment/input.ts +++ b/packages/core/tests/js/common/jsdoc-comment/input.ts @@ -1,5 +1,5 @@ function switchToLanguage(newLanguage) { - const canonicalPath = i18n.route($page.url.pathname); - const localisedPath = i18n.resolveRoute(canonicalPath, newLanguage); - goto(localisedPath); + const canonicalPath = i18n.route($page.url.pathname); + const localisedPath = i18n.resolveRoute(canonicalPath, newLanguage); + goto(localisedPath); } diff --git a/packages/core/tests/js/common/jsdoc-comment/output.ts b/packages/core/tests/js/common/jsdoc-comment/output.ts index d97338ba..2394044f 100644 --- a/packages/core/tests/js/common/jsdoc-comment/output.ts +++ b/packages/core/tests/js/common/jsdoc-comment/output.ts @@ -2,7 +2,7 @@ * @param {import("$lib/paraglide/runtime").AvailableLanguageTag} newLanguage */ function switchToLanguage(newLanguage) { - const canonicalPath = i18n.route($page.url.pathname); - const localisedPath = i18n.resolveRoute(canonicalPath, newLanguage); - goto(localisedPath); + const canonicalPath = i18n.route($page.url.pathname); + const localisedPath = i18n.resolveRoute(canonicalPath, newLanguage); + goto(localisedPath); } diff --git a/packages/core/tests/js/exports/default-export-with-variable/output.ts b/packages/core/tests/js/exports/default-export-with-variable/output.ts index e3eafc9d..920afac1 100644 --- a/packages/core/tests/js/exports/default-export-with-variable/output.ts +++ b/packages/core/tests/js/exports/default-export-with-variable/output.ts @@ -1,5 +1,5 @@ const object = { - test: 'string' + test: 'string' }; -export default object; \ No newline at end of file +export default object; diff --git a/packages/core/tests/js/exports/default-export/output.ts b/packages/core/tests/js/exports/default-export/output.ts index 76088cc4..d2516b3e 100644 --- a/packages/core/tests/js/exports/default-export/output.ts +++ b/packages/core/tests/js/exports/default-export/output.ts @@ -1,3 +1,3 @@ export default { - test: 'string' -}; \ No newline at end of file + test: 'string' +}; diff --git a/packages/core/tests/js/exports/named-export-with-existing/output.ts b/packages/core/tests/js/exports/named-export-with-existing/output.ts index 9bcf50f5..3cc72fee 100644 --- a/packages/core/tests/js/exports/named-export-with-existing/output.ts +++ b/packages/core/tests/js/exports/named-export-with-existing/output.ts @@ -1,4 +1,4 @@ export const named = { - test: 'string', - test2: "string2" -}; \ No newline at end of file + test: 'string', + test2: 'string2' +}; diff --git a/packages/core/tests/js/exports/named-export/output.ts b/packages/core/tests/js/exports/named-export/output.ts index c8a12a18..fec3056c 100644 --- a/packages/core/tests/js/exports/named-export/output.ts +++ b/packages/core/tests/js/exports/named-export/output.ts @@ -1,7 +1,7 @@ export const variable = { - test: 'string' + test: 'string' }; export const variable2 = { - test2: 'string2' -}; \ No newline at end of file + test2: 'string2' +}; diff --git a/packages/core/tests/js/functions/arrow-function/output.ts b/packages/core/tests/js/functions/arrow-function/output.ts index c74b611e..1dc5293f 100644 --- a/packages/core/tests/js/functions/arrow-function/output.ts +++ b/packages/core/tests/js/functions/arrow-function/output.ts @@ -1,6 +1,6 @@ () => console.log('foo'); () => { - console.log('foo'); - console.log('bar'); -}; \ No newline at end of file + console.log('foo'); + console.log('bar'); +}; diff --git a/packages/core/tests/js/functions/function-call/output.ts b/packages/core/tests/js/functions/function-call/output.ts index 6a886f44..69b852d5 100644 --- a/packages/core/tests/js/functions/function-call/output.ts +++ b/packages/core/tests/js/functions/function-call/output.ts @@ -1,4 +1,4 @@ function foo(bar: string) { console.log(bar); } -foo("bar"); \ No newline at end of file +foo('bar'); diff --git a/packages/core/tests/js/imports/default-import/output.ts b/packages/core/tests/js/imports/default-import/output.ts index 9203d582..0f58f59e 100644 --- a/packages/core/tests/js/imports/default-import/output.ts +++ b/packages/core/tests/js/imports/default-import/output.ts @@ -1 +1 @@ -import MyPackage from 'package'; \ No newline at end of file +import MyPackage from 'package'; diff --git a/packages/core/tests/js/imports/empty-import/output.ts b/packages/core/tests/js/imports/empty-import/output.ts index 47f21090..bf92fd96 100644 --- a/packages/core/tests/js/imports/empty-import/output.ts +++ b/packages/core/tests/js/imports/empty-import/output.ts @@ -1,2 +1,2 @@ import 'package/file.css'; -import './relativ/file.css'; \ No newline at end of file +import './relativ/file.css'; diff --git a/packages/core/tests/js/imports/named-import-merging/input.ts b/packages/core/tests/js/imports/named-import-merging/input.ts index 67f0c3d9..f4d71375 100644 --- a/packages/core/tests/js/imports/named-import-merging/input.ts +++ b/packages/core/tests/js/imports/named-import-merging/input.ts @@ -1 +1 @@ -import { namedOne } from "package"; +import { namedOne } from 'package'; diff --git a/packages/core/tests/js/imports/named-import-merging/output.ts b/packages/core/tests/js/imports/named-import-merging/output.ts index 772a0f86..7e5affa6 100644 --- a/packages/core/tests/js/imports/named-import-merging/output.ts +++ b/packages/core/tests/js/imports/named-import-merging/output.ts @@ -1 +1 @@ -import { namedOne, namedTwo } from "package"; \ No newline at end of file +import { namedOne, namedTwo } from 'package'; diff --git a/packages/core/tests/js/imports/named-import/output.ts b/packages/core/tests/js/imports/named-import/output.ts index 1a3abd90..640312d9 100644 --- a/packages/core/tests/js/imports/named-import/output.ts +++ b/packages/core/tests/js/imports/named-import/output.ts @@ -1,2 +1,2 @@ import { Handle } from '@sveltejs/kit'; -import { namedOne } from 'package'; \ No newline at end of file +import { namedOne } from 'package'; diff --git a/packages/core/tests/js/imports/namespaced-import/output.ts b/packages/core/tests/js/imports/namespaced-import/output.ts index 56eda1b3..89dc72a7 100644 --- a/packages/core/tests/js/imports/namespaced-import/output.ts +++ b/packages/core/tests/js/imports/namespaced-import/output.ts @@ -1,2 +1,2 @@ import * as bar from './some-file'; -import * as foo from 'package'; \ No newline at end of file +import * as foo from 'package'; diff --git a/packages/core/tests/js/index.ts b/packages/core/tests/js/index.ts index fc93e163..8cf489a4 100644 --- a/packages/core/tests/js/index.ts +++ b/packages/core/tests/js/index.ts @@ -1,12 +1,17 @@ -import { describe, expect, test } from 'vitest'; -import { parseScript, serializeScript } from '@sveltejs/ast-tooling'; import fs from 'node:fs'; import { join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; +import prettier from 'prettier'; +import { describe, expect, test } from 'vitest'; +import { parseScript, serializeScript } from '@sveltejs/ast-tooling'; const baseDir = resolve(fileURLToPath(import.meta.url), '..'); const categoryDirectories = getDirectoryNames(baseDir); +const prettierConfig = await prettier.resolveConfig(import.meta.url); +if (!prettierConfig) throw new Error('Failed to resolve prettier config'); +prettierConfig.filepath = 'output.ts'; + for (const categoryDirectory of categoryDirectories) { describe(categoryDirectory, () => { const testNames = getDirectoryNames(join(baseDir, categoryDirectory)); @@ -23,7 +28,8 @@ for (const categoryDirectory of categoryDirectories) { module.run({ ast }); const output = serializeScript(ast, input); - await expect(output).toMatchFileSnapshot(`${testDirectoryPath}/output.ts`); + const formattedOutput = await prettier.format(output, prettierConfig); + await expect(formattedOutput).toMatchFileSnapshot(`${testDirectoryPath}/output.ts`); }); } }); diff --git a/packages/core/tests/js/object/create/output.ts b/packages/core/tests/js/object/create/output.ts index a31bc6cf..b8a403ca 100644 --- a/packages/core/tests/js/object/create/output.ts +++ b/packages/core/tests/js/object/create/output.ts @@ -1,6 +1,6 @@ const empty = {}; const created = { - foo: 1, - bar: 'string' -}; \ No newline at end of file + foo: 1, + bar: 'string' +}; diff --git a/packages/core/tests/js/object/override-property/input.ts b/packages/core/tests/js/object/override-property/input.ts index 42413f9b..72b9d208 100644 --- a/packages/core/tests/js/object/override-property/input.ts +++ b/packages/core/tests/js/object/override-property/input.ts @@ -1,5 +1,5 @@ const test = { - foo: 1, - bar: 'string', - lorem: true -} + foo: 1, + bar: 'string', + lorem: true +}; diff --git a/packages/core/tests/js/object/override-property/output.ts b/packages/core/tests/js/object/override-property/output.ts index d759f951..0069e775 100644 --- a/packages/core/tests/js/object/override-property/output.ts +++ b/packages/core/tests/js/object/override-property/output.ts @@ -1,5 +1,5 @@ const test = { - foo: 2, - bar: "string2", - lorem: false -} \ No newline at end of file + foo: 2, + bar: 'string2', + lorem: false +}; diff --git a/packages/core/tests/js/object/property/input.ts b/packages/core/tests/js/object/property/input.ts index 2e7612f4..8d0b560b 100644 --- a/packages/core/tests/js/object/property/input.ts +++ b/packages/core/tests/js/object/property/input.ts @@ -1,3 +1,3 @@ const test = { - foo: 1 -} + foo: 1 +}; diff --git a/packages/core/tests/js/object/property/output.ts b/packages/core/tests/js/object/property/output.ts index 022a2a8b..3967f063 100644 --- a/packages/core/tests/js/object/property/output.ts +++ b/packages/core/tests/js/object/property/output.ts @@ -1,4 +1,4 @@ const test = { - foo: 1, - bar: "string" -} \ No newline at end of file + foo: 1, + bar: 'string' +}; diff --git a/packages/core/tests/js/object/remove-property/input.ts b/packages/core/tests/js/object/remove-property/input.ts index 2ff5dd43..3967f063 100644 --- a/packages/core/tests/js/object/remove-property/input.ts +++ b/packages/core/tests/js/object/remove-property/input.ts @@ -1,4 +1,4 @@ const test = { - foo: 1, - bar: 'string' -} + foo: 1, + bar: 'string' +}; diff --git a/packages/core/tests/js/object/remove-property/output.ts b/packages/core/tests/js/object/remove-property/output.ts index e51fe4a1..f3129ed1 100644 --- a/packages/core/tests/js/object/remove-property/output.ts +++ b/packages/core/tests/js/object/remove-property/output.ts @@ -1 +1 @@ -const test = {} +const test = {}; diff --git a/packages/core/tests/js/variables/declaration/output.ts b/packages/core/tests/js/variables/declaration/output.ts index 2863841c..e96c602e 100644 --- a/packages/core/tests/js/variables/declaration/output.ts +++ b/packages/core/tests/js/variables/declaration/output.ts @@ -1,5 +1,5 @@ const testNumber = 2; const testObject = { - foo: 'bar' -}; \ No newline at end of file + foo: 'bar' +}; diff --git a/packages/core/tests/js/variables/type-annotate-declarator/input.ts b/packages/core/tests/js/variables/type-annotate-declarator/input.ts index c064160a..9726ffde 100644 --- a/packages/core/tests/js/variables/type-annotate-declarator/input.ts +++ b/packages/core/tests/js/variables/type-annotate-declarator/input.ts @@ -1 +1 @@ -const str = "123"; +const str = '123'; diff --git a/packages/core/tests/js/variables/type-annotate-declarator/output.ts b/packages/core/tests/js/variables/type-annotate-declarator/output.ts index 82e25885..99232ae3 100644 --- a/packages/core/tests/js/variables/type-annotate-declarator/output.ts +++ b/packages/core/tests/js/variables/type-annotate-declarator/output.ts @@ -1 +1 @@ -const str: string = "123"; +const str: string = '123'; diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index a1fcf6c9..9f06a6bc 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -4,5 +4,6 @@ "checkJs": false, "isolatedDeclarations": true, "declaration": true - } + }, + "include": ["index.ts"] } diff --git a/packages/core/vitest.config.ts b/packages/core/vitest.config.ts index 5387a327..5940c172 100644 --- a/packages/core/vitest.config.ts +++ b/packages/core/vitest.config.ts @@ -1,5 +1,8 @@ -import { defineConfig, type UserConfig } from 'vitest/config'; +import { defineConfig } from 'vitest/config'; export default defineConfig({ - test: { dir: './tests', include: ['./**/index.ts'] } -}) as UserConfig; + test: { + name: 'core', + include: ['./tests/**/index.ts'] + } +}); diff --git a/packages/create/.gitignore b/packages/create/.gitignore index 14b63618..e7e5bfa8 100644 --- a/packages/create/.gitignore +++ b/packages/create/.gitignore @@ -1,5 +1,4 @@ /dist -/.test-tmp # re-enable this once we're out of prerelease /cli/versions.js diff --git a/packages/create/package.json b/packages/create/package.json index c0560933..762372ba 100644 --- a/packages/create/package.json +++ b/packages/create/package.json @@ -16,7 +16,7 @@ "check": "tsc", "format": "pnpm lint --write", "lint": "prettier --check . --config ../../prettier.config.js --ignore-path ../../.gitignore --ignore-path .gitignore --ignore-path ../../.prettierignore", - "test": "pnpm build:dist && vitest run", + "test": "vitest run", "update-template-repo": "pnpm build:dist && echo \"Updating template repo\" && bash ./scripts/update-template-repo.sh" }, "files": [ diff --git a/packages/create/test/check.ts b/packages/create/test/check.ts index 8beb3dba..ba807aa3 100644 --- a/packages/create/test/check.ts +++ b/packages/create/test/check.ts @@ -1,9 +1,8 @@ -import { exec } from 'node:child_process'; import fs from 'node:fs'; import path from 'node:path'; -import { fileURLToPath } from 'node:url'; import { promisify } from 'node:util'; -import glob from 'tiny-glob/sync.js'; +import { fileURLToPath } from 'node:url'; +import { exec, type PromiseWithChild } from 'node:child_process'; import { beforeAll, describe, test } from 'vitest'; import { create, type LanguageType, type TemplateType } from '../index.ts'; @@ -11,38 +10,11 @@ import { create, type LanguageType, type TemplateType } from '../index.ts'; const resolve_path = (path: string) => fileURLToPath(new URL(path, import.meta.url)); // use a directory outside of packages to ensure it isn't added to the pnpm workspace -const test_workspace_dir = resolve_path('../../../.test-tmp/create-svelte/'); - -const existing_workspace_overrides = JSON.parse( - fs.readFileSync(resolve_path('../../../package.json'), 'utf-8') -).pnpm?.overrides; - -const overrides = { ...existing_workspace_overrides }; - -for (const pkg_path of glob(resolve_path('../../../packages/*/package.json'))) { - const name = JSON.parse(fs.readFileSync(pkg_path, 'utf-8')).name; - // use `file:` protocol for opting into stricter resolve logic which catches more bugs - overrides[name] = `file:${path.dirname(path.resolve(pkg_path))}`; -} +const test_workspace_dir = resolve_path('../../../.test-output/create/'); // prepare test pnpm workspace fs.rmSync(test_workspace_dir, { recursive: true, force: true }); fs.mkdirSync(test_workspace_dir, { recursive: true }); -const workspace = { - name: 'svelte-check-test-fake-pnpm-workspace', - private: true, - version: '0.0.0', - pnpm: { overrides }, - // convert override query "@foo/bar@>x [query.replace(/(@?[^@]+)@.*$/, '$1'), range]) - ) -}; - -fs.writeFileSync( - path.join(test_workspace_dir, 'package.json'), - JSON.stringify(workspace, null, '\t') -); fs.writeFileSync(path.join(test_workspace_dir, 'pnpm-workspace.yaml'), 'packages:\n - ./*\n'); @@ -54,37 +26,13 @@ beforeAll(async () => { }); }, 60000); -function patch_package_json(pkg: any) { - Object.entries(overrides).forEach(([key, value]) => { - if (pkg.devDependencies?.[key]) { - pkg.devDependencies[key] = value; - } - - if (pkg.dependencies?.[key]) { - pkg.dependencies[key] = value; - } - - if (!pkg.pnpm) { - pkg.pnpm = {}; - } - - if (!pkg.pnpm.overrides) { - pkg.pnpm.overrides = {}; - } - - pkg.pnpm.overrides = { ...pkg.pnpm.overrides, ...overrides }; - }); - pkg.private = true; -} - /** * Tests in different templates can be run concurrently for a nice speedup locally, but tests within a template must be run sequentially. * It'd be better to group tests by template, but vitest doesn't support that yet. - * @type {Map import('node:child_process').PromiseWithChild][]>} */ -const script_test_map = new Map(); +const script_test_map = new Map PromiseWithChild]>>(); -const templates = fs.readdirSync('templates') as TemplateType[]; +const templates = fs.readdirSync(resolve_path('../templates/')) as TemplateType[]; for (const template of templates) { if (template[0] === '.') continue; @@ -93,16 +41,9 @@ for (const template of templates) { const cwd = path.join(test_workspace_dir, `${template}-${types}`); fs.rmSync(cwd, { recursive: true, force: true }); - create(cwd, { - name: `create-svelte-test-${template}-${types}`, - template, - types - }); + create(cwd, { name: `create-svelte-test-${template}-${types}`, template, types }); const pkg = JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf-8')); - patch_package_json(pkg); - - fs.writeFileSync(path.join(cwd, 'package.json'), JSON.stringify(pkg, null, '\t') + '\n'); // run provided scripts that are non-blocking. All of them should exit with 0 // package script requires lib dir @@ -120,13 +61,9 @@ for (const template of templates) { } for (const [script, tests] of script_test_map) { - describe.concurrent( - script, - () => { - for (const [name, task] of tests) { - test(name, task); - } - }, - { timeout: 60000 } - ); + describe.concurrent(script, { timeout: 60000 }, () => { + for (const [name, task] of tests) { + test(name, task); + } + }); } diff --git a/packages/create/tsconfig.json b/packages/create/tsconfig.json index 770dd836..c7f6b862 100644 --- a/packages/create/tsconfig.json +++ b/packages/create/tsconfig.json @@ -6,5 +6,5 @@ "declaration": true }, // overrides the root tsconfig `exclude` field so we're not ignoring the `test` dir - "exclude": ["templates/**", "shared/**", "dist/**"] + "exclude": ["templates/**", "shared/**", "dist/**", "vitest.config.ts"] } diff --git a/packages/create/vitest.config.ts b/packages/create/vitest.config.ts index 78e3ca4a..f29b5427 100644 --- a/packages/create/vitest.config.ts +++ b/packages/create/vitest.config.ts @@ -1,7 +1,10 @@ -import { defineConfig, type UserConfig } from 'vitest/config'; +import { env } from 'node:process'; +import { defineConfig } from 'vitest/config'; -const config: UserConfig = defineConfig({ - test: { dir: './test', include: ['*.ts'] } +export default defineConfig({ + test: { + name: 'create', + include: ['test/*.ts'], + retry: env.CI ? 3 : 0 + } }); - -export default config; diff --git a/packages/migrate/package.json b/packages/migrate/package.json index 1301f58c..c856a64b 100644 --- a/packages/migrate/package.json +++ b/packages/migrate/package.json @@ -14,7 +14,7 @@ "check": "tsc", "format": "pnpm lint --write", "lint": "prettier --check .", - "test": "vitest run --silent" + "test": "vitest run" }, "files": [ "bin.js", @@ -41,8 +41,7 @@ "@types/node": "^18.19.48", "@types/prompts": "^2.4.9", "@types/semver": "^7.5.6", - "svelte": "^4.2.10", - "vitest": "^2.0.1" + "svelte": "^4.2.10" }, "keywords": [ "migration", diff --git a/packages/migrate/vitest.config.ts b/packages/migrate/vitest.config.ts new file mode 100644 index 00000000..22afa1cf --- /dev/null +++ b/packages/migrate/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + name: 'migrate' + } +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf920c59..bb9ceae1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@changesets/cli': specifier: ^2.27.9 version: 2.27.9 + '@playwright/test': + specifier: ^1.48.2 + version: 1.48.2 '@rollup/plugin-commonjs': specifier: ^26.0.1 version: 26.0.1(rollup@4.21.2) @@ -28,16 +31,16 @@ importers: version: link:packages/create '@sveltejs/eslint-config': specifier: ^8.1.0 - version: 8.1.0(@stylistic/eslint-plugin-js@2.8.0(eslint@9.10.0))(eslint-config-prettier@9.1.0(eslint@9.10.0))(eslint-plugin-n@17.10.2(eslint@9.10.0))(eslint-plugin-svelte@2.43.0(eslint@9.10.0)(svelte@5.0.0))(eslint@9.10.0)(typescript-eslint@8.5.0(eslint@9.10.0)(typescript@5.6.2))(typescript@5.6.2) + version: 8.1.0(@stylistic/eslint-plugin-js@2.10.1(eslint@9.10.0))(eslint-config-prettier@9.1.0(eslint@9.10.0))(eslint-plugin-n@17.13.1(eslint@9.10.0))(eslint-plugin-svelte@2.46.0(eslint@9.10.0)(svelte@5.0.0))(eslint@9.10.0)(typescript-eslint@8.5.0(eslint@9.10.0)(typescript@5.6.3))(typescript@5.6.3) '@svitejs/changesets-changelog-github-compact': specifier: ^1.1.0 version: 1.1.0 '@types/node': specifier: ^22.3.0 - version: 22.5.4 + version: 22.9.0 '@vitest/ui': - specifier: ^2.0.5 - version: 2.0.5(vitest@2.0.5) + specifier: ^2.1.4 + version: 2.1.4(vitest@2.1.4) eslint: specifier: ^9.10.0 version: 9.10.0 @@ -58,7 +61,7 @@ importers: version: 4.21.2 rollup-plugin-esbuild: specifier: ^6.1.1 - version: 6.1.1(esbuild@0.21.5)(rollup@4.21.2) + version: 6.1.1(esbuild@0.24.0)(rollup@4.21.2) rollup-plugin-preserve-shebangs: specifier: ^0.2.0 version: 0.2.0(rollup@4.21.2) @@ -70,16 +73,16 @@ importers: version: 5.0.0 typescript: specifier: ^5.6.2 - version: 5.6.2 + version: 5.6.3 typescript-eslint: specifier: ^8.5.0 - version: 8.5.0(eslint@9.10.0)(typescript@5.6.2) + version: 8.5.0(eslint@9.10.0)(typescript@5.6.3) unplugin-isolated-decl: specifier: ^0.6.5 - version: 0.6.5(rollup@4.21.2)(typescript@5.6.2)(webpack-sources@3.2.3) + version: 0.6.5(rollup@4.21.2)(typescript@5.6.3)(webpack-sources@3.2.3) vitest: - specifier: ^2.0.5 - version: 2.0.5(@types/node@22.5.4)(@vitest/ui@2.0.5) + specifier: ^2.1.4 + version: 2.1.4(@types/node@22.9.0)(@vitest/ui@2.1.4) community-adder-template: dependencies: @@ -87,9 +90,15 @@ importers: specifier: workspace:* version: link:../packages/core devDependencies: + '@playwright/test': + specifier: ^1.48.2 + version: 1.48.2 sv: specifier: workspace:* version: link:../packages/cli + vitest: + specifier: ^2.1.4 + version: 2.1.4(@types/node@22.9.0)(@vitest/ui@2.1.4) packages/adders: dependencies: @@ -119,7 +128,7 @@ importers: version: 9.1.0 postcss: specifier: ^8.4.38 - version: 8.4.45 + version: 8.4.47 recast: specifier: ^0.23.7 version: 0.23.9 @@ -134,7 +143,7 @@ importers: devDependencies: picocolors: specifier: ^1.1.0 - version: 1.1.0 + version: 1.1.1 sisteransi: specifier: ^1.0.5 version: 1.0.5 @@ -152,7 +161,7 @@ importers: version: 1.3.0 picocolors: specifier: ^1.1.0 - version: 1.1.0 + version: 1.1.1 sisteransi: specifier: ^1.0.5 version: 1.0.5 @@ -171,12 +180,21 @@ importers: '@sveltejs/create': specifier: workspace:* version: link:../create + '@types/degit': + specifier: ^2.8.6 + version: 2.8.6 + '@types/ps-tree': + specifier: ^1.1.6 + version: 1.1.6 '@types/tar-fs': specifier: ^2.0.4 version: 2.0.4 commander: specifier: ^12.1.0 version: 12.1.0 + degit: + specifier: ^2.8.4 + version: 2.8.4 empathic: specifier: ^1.0.0 version: 1.0.0 @@ -185,16 +203,19 @@ importers: version: 0.2.2 picocolors: specifier: ^1.1.0 - version: 1.1.0 + version: 1.1.1 + ps-tree: + specifier: ^1.2.0 + version: 1.2.0 tar-fs: specifier: ^3.0.6 version: 3.0.6 tinyexec: - specifier: ^0.3.0 - version: 0.3.0 + specifier: ^0.3.1 + version: 0.3.1 valibot: specifier: ^0.41.0 - version: 0.41.0(typescript@5.6.2) + version: 0.41.0(typescript@5.6.3) packages/core: dependencies: @@ -216,7 +237,7 @@ importers: version: 0.30.12 picocolors: specifier: ^1.1.0 - version: 1.1.0 + version: 1.1.1 packages/create: devDependencies: @@ -258,7 +279,7 @@ importers: version: 24.0.0 typescript: specifier: ^5.3.3 - version: 5.6.2 + version: 5.6.3 zimmerframe: specifier: ^1.1.2 version: 1.1.2 @@ -275,9 +296,6 @@ importers: svelte: specifier: ^4.2.10 version: 4.2.19 - vitest: - specifier: ^2.0.1 - version: 2.0.5(@types/node@18.19.64)(@vitest/ui@2.0.5) packages: @@ -370,146 +388,290 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.24.0': + resolution: {integrity: sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.21.5': resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.24.0': + resolution: {integrity: sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.21.5': resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.24.0': + resolution: {integrity: sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.21.5': resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.24.0': + resolution: {integrity: sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.21.5': resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.24.0': + resolution: {integrity: sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.21.5': resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.24.0': + resolution: {integrity: sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.21.5': resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.24.0': + resolution: {integrity: sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.21.5': resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.24.0': + resolution: {integrity: sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.21.5': resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.24.0': + resolution: {integrity: sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.21.5': resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.24.0': + resolution: {integrity: sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.21.5': resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.24.0': + resolution: {integrity: sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.21.5': resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.24.0': + resolution: {integrity: sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.21.5': resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.24.0': + resolution: {integrity: sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.21.5': resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.24.0': + resolution: {integrity: sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.21.5': resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.24.0': + resolution: {integrity: sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.21.5': resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.24.0': + resolution: {integrity: sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.21.5': resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.24.0': + resolution: {integrity: sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-x64@0.21.5': resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.24.0': + resolution: {integrity: sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.24.0': + resolution: {integrity: sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.21.5': resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.24.0': + resolution: {integrity: sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/sunos-x64@0.21.5': resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.24.0': + resolution: {integrity: sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.21.5': resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.24.0': + resolution: {integrity: sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.21.5': resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.24.0': + resolution: {integrity: sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.21.5': resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.4.0': - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + '@esbuild/win32-x64@0.24.0': + resolution: {integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.4.1': + resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.11.0': - resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} '@eslint/config-array@0.18.0': @@ -628,6 +790,11 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@playwright/test@1.48.2': + resolution: {integrity: sha512-54w1xCWfXuax7dz4W2M9uw0gDyh+ti/0K/MxcCUxChFh37kkdxPdfZDw5QBbuPUJHr1CiHJ1hXgSs+GgeQc5Zw==} + engines: {node: '>=18'} + hasBin: true + '@polka/url@1.0.0-next.25': resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} @@ -756,8 +923,8 @@ packages: cpu: [x64] os: [win32] - '@stylistic/eslint-plugin-js@2.8.0': - resolution: {integrity: sha512-/e7pSzVMrwBd6yzSDsKHwax3TS96+pd/xSKzELaTkOuYqUhYfj/becWdfDbFSBGQD7BBBCiiE4L8L2cUfu5h+A==} + '@stylistic/eslint-plugin-js@2.10.1': + resolution: {integrity: sha512-IikL/RKy9Sk2UMDUUpqrEcwDeYzUEt6SaL2/UVCFuVQxKACHSgStT0NxXkxZmBOUforaU52FPf2Su07FYH5s5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: '>=8.40.0' @@ -780,6 +947,9 @@ packages: '@ts-morph/common@0.25.0': resolution: {integrity: sha512-kMnZz+vGGHi4GoHnLmMhGNjm44kGtKUXGnOvrKmMwAuvNjM/PgKVGfUnL7IDvK7Jb2QQ82jq3Zmp04Gy+r3Dkg==} + '@types/degit@2.8.6': + resolution: {integrity: sha512-y0M7sqzsnHB6cvAeTCBPrCQNQiZe8U4qdzf8uBVmOWYap5MMTN/gB2iEqrIqFiYcsyvP74GnGD5tgsHttielFw==} + '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} @@ -792,12 +962,15 @@ packages: '@types/node@18.19.64': resolution: {integrity: sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==} - '@types/node@22.5.4': - resolution: {integrity: sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==} + '@types/node@22.9.0': + resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==} '@types/prompts@2.4.9': resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==} + '@types/ps-tree@1.1.6': + resolution: {integrity: sha512-PtrlVaOaI44/3pl3cvnlK+GxOM3re2526TJvPvh7W+keHIXdV4TE0ylpPBAcvFQCbGitaTXwL9u+RF7qtVeazQ==} + '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} @@ -867,28 +1040,39 @@ packages: resolution: {integrity: sha512-yTPqMnbAZJNy2Xq2XU8AdtOW9tJIr+UQb64aXB9f3B1498Zx9JorVgFJcZpEc9UBuCCrdzKID2RGAMkYcDtZOw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@vitest/expect@2.0.5': - resolution: {integrity: sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==} + '@vitest/expect@2.1.4': + resolution: {integrity: sha512-DOETT0Oh1avie/D/o2sgMHGrzYUFFo3zqESB2Hn70z6QB1HrS2IQ9z5DfyTqU8sg4Bpu13zZe9V4+UTNQlUeQA==} - '@vitest/pretty-format@2.0.5': - resolution: {integrity: sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==} + '@vitest/mocker@2.1.4': + resolution: {integrity: sha512-Ky/O1Lc0QBbutJdW0rqLeFNbuLEyS+mIPiNdlVlp2/yhJ0SbyYqObS5IHdhferJud8MbbwMnexg4jordE5cCoQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true - '@vitest/runner@2.0.5': - resolution: {integrity: sha512-TfRfZa6Bkk9ky4tW0z20WKXFEwwvWhRY+84CnSEtq4+3ZvDlJyY32oNTJtM7AW9ihW90tX/1Q78cb6FjoAs+ig==} + '@vitest/pretty-format@2.1.4': + resolution: {integrity: sha512-L95zIAkEuTDbUX1IsjRl+vyBSLh3PwLLgKpghl37aCK9Jvw0iP+wKwIFhfjdUtA2myLgjrG6VU6JCFLv8q/3Ww==} - '@vitest/snapshot@2.0.5': - resolution: {integrity: sha512-SgCPUeDFLaM0mIUHfaArq8fD2WbaXG/zVXjRupthYfYGzc8ztbFbu6dUNOblBG7XLMR1kEhS/DNnfCZ2IhdDew==} + '@vitest/runner@2.1.4': + resolution: {integrity: sha512-sKRautINI9XICAMl2bjxQM8VfCMTB0EbsBc/EDFA57V6UQevEKY/TOPOF5nzcvCALltiLfXWbq4MaAwWx/YxIA==} - '@vitest/spy@2.0.5': - resolution: {integrity: sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==} + '@vitest/snapshot@2.1.4': + resolution: {integrity: sha512-3Kab14fn/5QZRog5BPj6Rs8dc4B+mim27XaKWFWHWA87R56AKjHTGcBFKpvZKDzC4u5Wd0w/qKsUIio3KzWW4Q==} - '@vitest/ui@2.0.5': - resolution: {integrity: sha512-m+ZpVt/PVi/nbeRKEjdiYeoh0aOfI9zr3Ria9LO7V2PlMETtAXJS3uETEZkc8Be2oOl8mhd7Ew+5SRBXRYncNw==} + '@vitest/spy@2.1.4': + resolution: {integrity: sha512-4JOxa+UAizJgpZfaCPKK2smq9d8mmjZVPMt2kOsg/R8QkoRzydHH1qHxIYNvr1zlEaFj4SXiaaJWxq/LPLKaLg==} + + '@vitest/ui@2.1.4': + resolution: {integrity: sha512-Zd9e5oU063c+j9N9XzGJagCLNvG71x/2tOme3Js4JEZKX55zsgxhJwUgLI8hkN6NjMLpdJO8d7nVUUuPGAA58Q==} peerDependencies: - vitest: 2.0.5 + vitest: 2.1.4 - '@vitest/utils@2.0.5': - resolution: {integrity: sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==} + '@vitest/utils@2.1.4': + resolution: {integrity: sha512-MXDnZn0Awl2S86PSNIim5PWXgIAx8CIkzu35mBdSApUip6RFOGXBCf3YFyeEu8n1IHk4bWD46DeYFu9mQlFIRg==} acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} @@ -900,8 +1084,8 @@ packages: peerDependencies: acorn: '>=8.9.0' - acorn@8.12.1: - resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} engines: {node: '>=0.4.0'} hasBin: true @@ -1008,8 +1192,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - chai@5.1.1: - resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} + chai@5.1.2: + resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} engines: {node: '>=12'} chalk@4.1.2: @@ -1052,7 +1236,7 @@ packages: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} concat-map@0.0.1: - resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} cross-spawn@5.1.0: resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} @@ -1105,6 +1289,11 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + degit@2.8.4: + resolution: {integrity: sha512-vqYuzmSA5I50J882jd+AbAhQtgK6bdKUJIex1JNfEUPENCgYsxugzKVZlFyMwV4i06MmnV47/Iqi5Io86zf3Ng==} + engines: {node: '>=8.0.0'} + hasBin: true + detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -1138,6 +1327,9 @@ packages: resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} + duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -1174,6 +1366,11 @@ packages: engines: {node: '>=12'} hasBin: true + esbuild@0.24.0: + resolution: {integrity: sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==} + engines: {node: '>=18'} + hasBin: true + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -1196,18 +1393,18 @@ packages: peerDependencies: eslint: '>=8' - eslint-plugin-n@17.10.2: - resolution: {integrity: sha512-e+s4eAf5NtJaxPhTNu3qMO0Iz40WANS93w9LQgYcvuljgvDmWi/a3rh+OrNyMHeng6aOWGJO0rCg5lH4zi8yTw==} + eslint-plugin-n@17.13.1: + resolution: {integrity: sha512-97qzhk1z3DdSJNCqT45EslwCu5+LB9GDadSyBItgKUfGsXAmN/aa7LRQ0ZxHffUxUzvgbTPJL27/pE9ZQWHy7A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: '>=8.23.0' - eslint-plugin-svelte@2.43.0: - resolution: {integrity: sha512-REkxQWvg2pp7QVLxQNa+dJ97xUqRe7Y2JJbSWkHSuszu0VcblZtXkPBPckkivk99y5CdLw4slqfPylL2d/X4jQ==} + eslint-plugin-svelte@2.46.0: + resolution: {integrity: sha512-1A7iEMkzmCZ9/Iz+EAfOGYL8IoIG6zeKEq1SmpxGeM5SXmoQq+ZNnCpXFVJpsxPWYx8jIVGMerQMzX20cqUl0g==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0-0 || ^9.0.0-0 - svelte: ^3.37.0 || ^4.0.0 || ^5.0.0-next.191 + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 peerDependenciesMeta: svelte: optional: true @@ -1224,8 +1421,8 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint-visitor-keys@4.0.0: - resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} + eslint-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} eslint@9.10.0: @@ -1241,8 +1438,8 @@ packages: esm-env@1.0.0: resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==} - espree@10.1.0: - resolution: {integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==} + espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} espree@9.6.1: @@ -1279,9 +1476,12 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} + event-stream@3.3.4: + resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} + + expect-type@1.1.0: + resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} + engines: {node: '>=12.0.0'} extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} @@ -1347,6 +1547,9 @@ packages: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} + from@0.1.7: + resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} + fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -1355,6 +1558,11 @@ packages: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1363,19 +1571,12 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - get-func-name@2.0.2: - resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - get-stdin@9.0.0: resolution: {integrity: sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==} engines: {node: '>=12'} - get-stream@8.0.1: - resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} - engines: {node: '>=16'} - - get-tsconfig@4.8.0: - resolution: {integrity: sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw==} + get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} git-hooks-list@3.1.0: resolution: {integrity: sha512-LF8VeHeR7v+wAbXqfgRlTSX/1BJR9Q1vEMR8JAz1cEg6GX07+zyj3sAdDvYjj/xnlIfVuGgj4qBei1K3hKH+PA==} @@ -1400,8 +1601,8 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} - globals@15.9.0: - resolution: {integrity: sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==} + globals@15.12.0: + resolution: {integrity: sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==} engines: {node: '>=18'} globalyzer@0.1.0: @@ -1438,10 +1639,6 @@ packages: human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} - human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} - iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -1502,10 +1699,6 @@ packages: is-reference@3.0.2: resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} - is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - is-subdir@1.2.0: resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} engines: {node: '>=4'} @@ -1555,8 +1748,8 @@ packages: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} - known-css-properties@0.34.0: - resolution: {integrity: sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ==} + known-css-properties@0.35.0: + resolution: {integrity: sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==} levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} @@ -1586,8 +1779,8 @@ packages: lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} - loupe@3.1.1: - resolution: {integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==} + loupe@3.1.2: + resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -1601,12 +1794,12 @@ packages: magic-string@0.30.12: resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==} + map-stream@0.1.0: + resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} + mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1615,10 +1808,6 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1661,10 +1850,6 @@ packages: encoding: optional: true - npm-run-path@5.3.0: - resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -1672,10 +1857,6 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} - optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -1739,10 +1920,6 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} @@ -1761,11 +1938,14 @@ packages: resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} engines: {node: '>= 14.16'} + pause-stream@0.0.11: + resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} + periscopic@3.1.0: resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} - picocolors@1.1.0: - resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -1783,6 +1963,16 @@ packages: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} + playwright-core@1.48.2: + resolution: {integrity: sha512-sjjw+qrLFlriJo64du+EK0kJgZzoQPsabGF4lBvsid+3CNIZIYLgnMj9V6JY5VhM2Peh20DJWIVpVljLLnlawA==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.48.2: + resolution: {integrity: sha512-NjYvYgp4BPmiwfe31j4gHLa3J7bD2WiBz8Lk2RoSsmX38SVIARZ18VYjxLjAcDsAhA+F4iSEXTSGgjua0rrlgQ==} + engines: {node: '>=18'} + hasBin: true + postcss-load-config@3.1.4: resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} engines: {node: '>= 10'} @@ -1811,8 +2001,8 @@ packages: resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} engines: {node: '>=4'} - postcss@8.4.45: - resolution: {integrity: sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==} + postcss@8.4.47: + resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: @@ -1847,6 +2037,11 @@ packages: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} + ps-tree@1.2.0: + resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} + engines: {node: '>= 0.10'} + hasBin: true + pseudomap@1.0.2: resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} @@ -1950,9 +2145,9 @@ packages: silver-fleece@1.2.1: resolution: {integrity: sha512-GwiBh7LzX4aKWb3LH1tPu8et2zZqe1cwXn+/uwIUK+H1Y2k119qpvPelVdRKG/6+RQvtUdRep4mBOOVf80VYDA==} - sirv@2.0.4: - resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==} - engines: {node: '>= 10'} + sirv@3.0.0: + resolution: {integrity: sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==} + engines: {node: '>=18'} sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -1987,6 +2182,9 @@ packages: spawndamnit@2.0.0: resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==} + split@0.3.3: + resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} + sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} @@ -1996,6 +2194,9 @@ packages: std-env@3.7.0: resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + stream-combiner@0.0.4: + resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} + streamx@2.20.1: resolution: {integrity: sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==} @@ -2019,10 +2220,6 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -2040,11 +2237,11 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - svelte-eslint-parser@0.41.0: - resolution: {integrity: sha512-L6f4hOL+AbgfBIB52Z310pg1d2QjRqm7wy3kI1W6hhdhX5bvu7+f0R6w4ykp5HoDdzq+vGhIJmsisaiJDGmVfA==} + svelte-eslint-parser@0.43.0: + resolution: {integrity: sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: - svelte: ^3.37.0 || ^4.0.0 || ^5.0.0-next.191 + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 peerDependenciesMeta: svelte: optional: true @@ -2088,6 +2285,9 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + tiny-glob@0.2.9: resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} @@ -2097,8 +2297,8 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@0.3.0: - resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==} + tinyexec@0.3.1: + resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==} tinyglobby@0.2.10: resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} @@ -2163,8 +2363,8 @@ packages: typescript: optional: true - typescript@5.6.2: - resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} hasBin: true @@ -2216,13 +2416,13 @@ packages: typescript: optional: true - vite-node@2.0.5: - resolution: {integrity: sha512-LdsW4pxj0Ot69FAoXZ1yTnA9bjGohr2yNBU7QKRxpz8ITSkhuDl6h3zS/tvgz4qrNjeRnvrWeXQ8ZF7Um4W00Q==} + vite-node@2.1.4: + resolution: {integrity: sha512-kqa9v+oi4HwkG6g8ufRnb5AeplcRw8jUF6/7/Qz1qRQOXHImG8YnLbB+LLszENwFnoBl9xIf9nVdCFzNd7GQEg==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite@5.4.3: - resolution: {integrity: sha512-IH+nl64eq9lJjFqU+/yrRnrHPVTlgy42/+IzbOdaFDVlyLgI/wDlf+FCobXLX1cT0X5+7LMyH1mIy2xJdLfo8Q==} + vite@5.4.10: + resolution: {integrity: sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -2252,15 +2452,15 @@ packages: terser: optional: true - vitest@2.0.5: - resolution: {integrity: sha512-8GUxONfauuIdeSl5f9GTgVEpg5BTOlplET4WEDaeY2QBiN8wSm68vxN/tb5z405OwppfoCavnwXafiaYBC/xOA==} + vitest@2.1.4: + resolution: {integrity: sha512-eDjxbVAJw1UJJCHr5xr/xM86Zx+YxIEXGAR+bmnEID7z9qWfoxpHw0zdobz+TQAFOLT+nEXz3+gx6nUJ7RgmlQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 2.0.5 - '@vitest/ui': 2.0.5 + '@vitest/browser': 2.1.4 + '@vitest/ui': 2.1.4 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -2412,7 +2612,7 @@ snapshots: mri: 1.2.0 p-limit: 2.3.0 package-manager-detector: 0.2.2 - picocolors: 1.1.0 + picocolors: 1.1.1 resolve-from: 5.0.0 semver: 7.6.3 spawndamnit: 2.0.0 @@ -2436,7 +2636,7 @@ snapshots: dependencies: '@changesets/types': 6.0.0 '@manypkg/get-packages': 1.1.3 - picocolors: 1.1.0 + picocolors: 1.1.1 semver: 7.6.3 '@changesets/get-github-info@0.5.2': @@ -2467,7 +2667,7 @@ snapshots: '@changesets/logger@0.1.1': dependencies: - picocolors: 1.1.0 + picocolors: 1.1.1 '@changesets/parse@0.4.0': dependencies: @@ -2489,7 +2689,7 @@ snapshots: '@changesets/types': 6.0.0 fs-extra: 7.0.1 p-filter: 2.1.0 - picocolors: 1.1.0 + picocolors: 1.1.1 '@changesets/should-skip-package@0.1.1': dependencies: @@ -2510,78 +2710,150 @@ snapshots: '@esbuild/aix-ppc64@0.21.5': optional: true + '@esbuild/aix-ppc64@0.24.0': + optional: true + '@esbuild/android-arm64@0.21.5': optional: true + '@esbuild/android-arm64@0.24.0': + optional: true + '@esbuild/android-arm@0.21.5': optional: true + '@esbuild/android-arm@0.24.0': + optional: true + '@esbuild/android-x64@0.21.5': optional: true + '@esbuild/android-x64@0.24.0': + optional: true + '@esbuild/darwin-arm64@0.21.5': optional: true + '@esbuild/darwin-arm64@0.24.0': + optional: true + '@esbuild/darwin-x64@0.21.5': optional: true + '@esbuild/darwin-x64@0.24.0': + optional: true + '@esbuild/freebsd-arm64@0.21.5': optional: true + '@esbuild/freebsd-arm64@0.24.0': + optional: true + '@esbuild/freebsd-x64@0.21.5': optional: true + '@esbuild/freebsd-x64@0.24.0': + optional: true + '@esbuild/linux-arm64@0.21.5': optional: true + '@esbuild/linux-arm64@0.24.0': + optional: true + '@esbuild/linux-arm@0.21.5': optional: true + '@esbuild/linux-arm@0.24.0': + optional: true + '@esbuild/linux-ia32@0.21.5': optional: true + '@esbuild/linux-ia32@0.24.0': + optional: true + '@esbuild/linux-loong64@0.21.5': optional: true + '@esbuild/linux-loong64@0.24.0': + optional: true + '@esbuild/linux-mips64el@0.21.5': optional: true + '@esbuild/linux-mips64el@0.24.0': + optional: true + '@esbuild/linux-ppc64@0.21.5': optional: true + '@esbuild/linux-ppc64@0.24.0': + optional: true + '@esbuild/linux-riscv64@0.21.5': optional: true + '@esbuild/linux-riscv64@0.24.0': + optional: true + '@esbuild/linux-s390x@0.21.5': optional: true + '@esbuild/linux-s390x@0.24.0': + optional: true + '@esbuild/linux-x64@0.21.5': optional: true + '@esbuild/linux-x64@0.24.0': + optional: true + '@esbuild/netbsd-x64@0.21.5': optional: true + '@esbuild/netbsd-x64@0.24.0': + optional: true + + '@esbuild/openbsd-arm64@0.24.0': + optional: true + '@esbuild/openbsd-x64@0.21.5': optional: true + '@esbuild/openbsd-x64@0.24.0': + optional: true + '@esbuild/sunos-x64@0.21.5': optional: true + '@esbuild/sunos-x64@0.24.0': + optional: true + '@esbuild/win32-arm64@0.21.5': optional: true + '@esbuild/win32-arm64@0.24.0': + optional: true + '@esbuild/win32-ia32@0.21.5': optional: true + '@esbuild/win32-ia32@0.24.0': + optional: true + '@esbuild/win32-x64@0.21.5': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@9.10.0)': + '@esbuild/win32-x64@0.24.0': + optional: true + + '@eslint-community/eslint-utils@4.4.1(eslint@9.10.0)': dependencies: eslint: 9.10.0 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.11.0': {} + '@eslint-community/regexpp@4.12.1': {} '@eslint/config-array@0.18.0': dependencies: @@ -2595,7 +2867,7 @@ snapshots: dependencies: ajv: 6.12.6 debug: 4.3.7 - espree: 10.1.0 + espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.0 @@ -2700,6 +2972,10 @@ snapshots: '@pkgr/core@0.1.1': {} + '@playwright/test@1.48.2': + dependencies: + playwright: 1.48.2 + '@polka/url@1.0.0-next.25': {} '@rollup/plugin-commonjs@26.0.1(rollup@4.21.2)': @@ -2796,22 +3072,22 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.21.2': optional: true - '@stylistic/eslint-plugin-js@2.8.0(eslint@9.10.0)': + '@stylistic/eslint-plugin-js@2.10.1(eslint@9.10.0)': dependencies: eslint: 9.10.0 - eslint-visitor-keys: 4.0.0 - espree: 10.1.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 - '@sveltejs/eslint-config@8.1.0(@stylistic/eslint-plugin-js@2.8.0(eslint@9.10.0))(eslint-config-prettier@9.1.0(eslint@9.10.0))(eslint-plugin-n@17.10.2(eslint@9.10.0))(eslint-plugin-svelte@2.43.0(eslint@9.10.0)(svelte@5.0.0))(eslint@9.10.0)(typescript-eslint@8.5.0(eslint@9.10.0)(typescript@5.6.2))(typescript@5.6.2)': + '@sveltejs/eslint-config@8.1.0(@stylistic/eslint-plugin-js@2.10.1(eslint@9.10.0))(eslint-config-prettier@9.1.0(eslint@9.10.0))(eslint-plugin-n@17.13.1(eslint@9.10.0))(eslint-plugin-svelte@2.46.0(eslint@9.10.0)(svelte@5.0.0))(eslint@9.10.0)(typescript-eslint@8.5.0(eslint@9.10.0)(typescript@5.6.3))(typescript@5.6.3)': dependencies: - '@stylistic/eslint-plugin-js': 2.8.0(eslint@9.10.0) + '@stylistic/eslint-plugin-js': 2.10.1(eslint@9.10.0) eslint: 9.10.0 eslint-config-prettier: 9.1.0(eslint@9.10.0) - eslint-plugin-n: 17.10.2(eslint@9.10.0) - eslint-plugin-svelte: 2.43.0(eslint@9.10.0)(svelte@5.0.0) - globals: 15.9.0 - typescript: 5.6.2 - typescript-eslint: 8.5.0(eslint@9.10.0)(typescript@5.6.2) + eslint-plugin-n: 17.13.1(eslint@9.10.0) + eslint-plugin-svelte: 2.46.0(eslint@9.10.0)(svelte@5.0.0) + globals: 15.12.0 + typescript: 5.6.3 + typescript-eslint: 8.5.0(eslint@9.10.0)(typescript@5.6.3) '@svitejs/changesets-changelog-github-compact@1.1.0': dependencies: @@ -2826,6 +3102,8 @@ snapshots: path-browserify: 1.0.1 tinyglobby: 0.2.10 + '@types/degit@2.8.6': {} + '@types/estree@1.0.5': {} '@types/gitignore-parser@0.0.3': {} @@ -2836,56 +3114,58 @@ snapshots: dependencies: undici-types: 5.26.5 - '@types/node@22.5.4': + '@types/node@22.9.0': dependencies: undici-types: 6.19.8 '@types/prompts@2.4.9': dependencies: - '@types/node': 18.19.64 + '@types/node': 22.9.0 kleur: 3.0.3 + '@types/ps-tree@1.1.6': {} + '@types/resolve@1.20.2': {} '@types/semver@7.5.8': {} '@types/tar-fs@2.0.4': dependencies: - '@types/node': 22.5.4 + '@types/node': 22.9.0 '@types/tar-stream': 3.1.3 '@types/tar-stream@3.1.3': dependencies: - '@types/node': 22.5.4 + '@types/node': 22.9.0 - '@typescript-eslint/eslint-plugin@8.5.0(@typescript-eslint/parser@8.5.0(eslint@9.10.0)(typescript@5.6.2))(eslint@9.10.0)(typescript@5.6.2)': + '@typescript-eslint/eslint-plugin@8.5.0(@typescript-eslint/parser@8.5.0(eslint@9.10.0)(typescript@5.6.3))(eslint@9.10.0)(typescript@5.6.3)': dependencies: - '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 8.5.0(eslint@9.10.0)(typescript@5.6.2) + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.5.0(eslint@9.10.0)(typescript@5.6.3) '@typescript-eslint/scope-manager': 8.5.0 - '@typescript-eslint/type-utils': 8.5.0(eslint@9.10.0)(typescript@5.6.2) - '@typescript-eslint/utils': 8.5.0(eslint@9.10.0)(typescript@5.6.2) + '@typescript-eslint/type-utils': 8.5.0(eslint@9.10.0)(typescript@5.6.3) + '@typescript-eslint/utils': 8.5.0(eslint@9.10.0)(typescript@5.6.3) '@typescript-eslint/visitor-keys': 8.5.0 eslint: 9.10.0 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.6.2) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.5.0(eslint@9.10.0)(typescript@5.6.2)': + '@typescript-eslint/parser@8.5.0(eslint@9.10.0)(typescript@5.6.3)': dependencies: '@typescript-eslint/scope-manager': 8.5.0 '@typescript-eslint/types': 8.5.0 - '@typescript-eslint/typescript-estree': 8.5.0(typescript@5.6.2) + '@typescript-eslint/typescript-estree': 8.5.0(typescript@5.6.3) '@typescript-eslint/visitor-keys': 8.5.0 debug: 4.3.7 eslint: 9.10.0 optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color @@ -2894,21 +3174,21 @@ snapshots: '@typescript-eslint/types': 8.5.0 '@typescript-eslint/visitor-keys': 8.5.0 - '@typescript-eslint/type-utils@8.5.0(eslint@9.10.0)(typescript@5.6.2)': + '@typescript-eslint/type-utils@8.5.0(eslint@9.10.0)(typescript@5.6.3)': dependencies: - '@typescript-eslint/typescript-estree': 8.5.0(typescript@5.6.2) - '@typescript-eslint/utils': 8.5.0(eslint@9.10.0)(typescript@5.6.2) + '@typescript-eslint/typescript-estree': 8.5.0(typescript@5.6.3) + '@typescript-eslint/utils': 8.5.0(eslint@9.10.0)(typescript@5.6.3) debug: 4.3.7 - ts-api-utils: 1.3.0(typescript@5.6.2) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - eslint - supports-color '@typescript-eslint/types@8.5.0': {} - '@typescript-eslint/typescript-estree@8.5.0(typescript@5.6.2)': + '@typescript-eslint/typescript-estree@8.5.0(typescript@5.6.3)': dependencies: '@typescript-eslint/types': 8.5.0 '@typescript-eslint/visitor-keys': 8.5.0 @@ -2917,18 +3197,18 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.6.2) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.5.0(eslint@9.10.0)(typescript@5.6.2)': + '@typescript-eslint/utils@8.5.0(eslint@9.10.0)(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.10.0) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.10.0) '@typescript-eslint/scope-manager': 8.5.0 '@typescript-eslint/types': 8.5.0 - '@typescript-eslint/typescript-estree': 8.5.0(typescript@5.6.2) + '@typescript-eslint/typescript-estree': 8.5.0(typescript@5.6.3) eslint: 9.10.0 transitivePeerDependencies: - supports-color @@ -2939,59 +3219,66 @@ snapshots: '@typescript-eslint/types': 8.5.0 eslint-visitor-keys: 3.4.3 - '@vitest/expect@2.0.5': + '@vitest/expect@2.1.4': dependencies: - '@vitest/spy': 2.0.5 - '@vitest/utils': 2.0.5 - chai: 5.1.1 + '@vitest/spy': 2.1.4 + '@vitest/utils': 2.1.4 + chai: 5.1.2 tinyrainbow: 1.2.0 - '@vitest/pretty-format@2.0.5': + '@vitest/mocker@2.1.4(vite@5.4.10(@types/node@22.9.0))': + dependencies: + '@vitest/spy': 2.1.4 + estree-walker: 3.0.3 + magic-string: 0.30.12 + optionalDependencies: + vite: 5.4.10(@types/node@22.9.0) + + '@vitest/pretty-format@2.1.4': dependencies: tinyrainbow: 1.2.0 - '@vitest/runner@2.0.5': + '@vitest/runner@2.1.4': dependencies: - '@vitest/utils': 2.0.5 + '@vitest/utils': 2.1.4 pathe: 1.1.2 - '@vitest/snapshot@2.0.5': + '@vitest/snapshot@2.1.4': dependencies: - '@vitest/pretty-format': 2.0.5 + '@vitest/pretty-format': 2.1.4 magic-string: 0.30.12 pathe: 1.1.2 - '@vitest/spy@2.0.5': + '@vitest/spy@2.1.4': dependencies: tinyspy: 3.0.2 - '@vitest/ui@2.0.5(vitest@2.0.5)': + '@vitest/ui@2.1.4(vitest@2.1.4)': dependencies: - '@vitest/utils': 2.0.5 - fast-glob: 3.3.2 + '@vitest/utils': 2.1.4 fflate: 0.8.2 flatted: 3.3.1 pathe: 1.1.2 - sirv: 2.0.4 + sirv: 3.0.0 + tinyglobby: 0.2.10 tinyrainbow: 1.2.0 - vitest: 2.0.5(@types/node@22.5.4)(@vitest/ui@2.0.5) + vitest: 2.1.4(@types/node@22.9.0)(@vitest/ui@2.1.4) - '@vitest/utils@2.0.5': + '@vitest/utils@2.1.4': dependencies: - '@vitest/pretty-format': 2.0.5 - estree-walker: 3.0.3 - loupe: 3.1.1 + '@vitest/pretty-format': 2.1.4 + loupe: 3.1.2 tinyrainbow: 1.2.0 - acorn-jsx@5.3.2(acorn@8.12.1): + acorn-jsx@5.3.2(acorn@8.14.0): dependencies: - acorn: 8.12.1 + acorn: 8.14.0 - acorn-typescript@1.4.13(acorn@8.12.1): + acorn-typescript@1.4.13(acorn@8.14.0): dependencies: - acorn: 8.12.1 + acorn: 8.14.0 - acorn@8.12.1: {} + acorn@8.14.0: {} ajv@6.12.6: dependencies: @@ -3085,12 +3372,12 @@ snapshots: callsites@3.1.0: {} - chai@5.1.1: + chai@5.1.2: dependencies: assertion-error: 2.0.1 check-error: 2.1.1 deep-eql: 5.0.2 - loupe: 3.1.1 + loupe: 3.1.2 pathval: 2.0.0 chalk@4.1.2: @@ -3110,7 +3397,7 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 '@types/estree': 1.0.5 - acorn: 8.12.1 + acorn: 8.14.0 estree-walker: 3.0.3 periscopic: 3.1.0 @@ -3163,6 +3450,8 @@ snapshots: deepmerge@4.3.1: {} + degit@2.8.4: {} + detect-indent@6.1.0: {} detect-indent@7.0.1: {} @@ -3193,6 +3482,8 @@ snapshots: dotenv@16.4.5: {} + duplexer@0.1.2: {} + eastasianwidth@0.2.0: {} emoji-regex@8.0.0: {} @@ -3245,6 +3536,33 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 + esbuild@0.24.0: + optionalDependencies: + '@esbuild/aix-ppc64': 0.24.0 + '@esbuild/android-arm': 0.24.0 + '@esbuild/android-arm64': 0.24.0 + '@esbuild/android-x64': 0.24.0 + '@esbuild/darwin-arm64': 0.24.0 + '@esbuild/darwin-x64': 0.24.0 + '@esbuild/freebsd-arm64': 0.24.0 + '@esbuild/freebsd-x64': 0.24.0 + '@esbuild/linux-arm': 0.24.0 + '@esbuild/linux-arm64': 0.24.0 + '@esbuild/linux-ia32': 0.24.0 + '@esbuild/linux-loong64': 0.24.0 + '@esbuild/linux-mips64el': 0.24.0 + '@esbuild/linux-ppc64': 0.24.0 + '@esbuild/linux-riscv64': 0.24.0 + '@esbuild/linux-s390x': 0.24.0 + '@esbuild/linux-x64': 0.24.0 + '@esbuild/netbsd-x64': 0.24.0 + '@esbuild/openbsd-arm64': 0.24.0 + '@esbuild/openbsd-x64': 0.24.0 + '@esbuild/sunos-x64': 0.24.0 + '@esbuild/win32-arm64': 0.24.0 + '@esbuild/win32-ia32': 0.24.0 + '@esbuild/win32-x64': 0.24.0 + escape-string-regexp@4.0.0: {} eslint-compat-utils@0.5.1(eslint@9.10.0): @@ -3258,37 +3576,37 @@ snapshots: eslint-plugin-es-x@7.8.0(eslint@9.10.0): dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.10.0) - '@eslint-community/regexpp': 4.11.0 + '@eslint-community/eslint-utils': 4.4.1(eslint@9.10.0) + '@eslint-community/regexpp': 4.12.1 eslint: 9.10.0 eslint-compat-utils: 0.5.1(eslint@9.10.0) - eslint-plugin-n@17.10.2(eslint@9.10.0): + eslint-plugin-n@17.13.1(eslint@9.10.0): dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.10.0) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.10.0) enhanced-resolve: 5.17.1 eslint: 9.10.0 eslint-plugin-es-x: 7.8.0(eslint@9.10.0) - get-tsconfig: 4.8.0 - globals: 15.9.0 + get-tsconfig: 4.8.1 + globals: 15.12.0 ignore: 5.3.2 minimatch: 9.0.5 semver: 7.6.3 - eslint-plugin-svelte@2.43.0(eslint@9.10.0)(svelte@5.0.0): + eslint-plugin-svelte@2.46.0(eslint@9.10.0)(svelte@5.0.0): dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.10.0) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.10.0) '@jridgewell/sourcemap-codec': 1.5.0 eslint: 9.10.0 eslint-compat-utils: 0.5.1(eslint@9.10.0) esutils: 2.0.3 - known-css-properties: 0.34.0 - postcss: 8.4.45 - postcss-load-config: 3.1.4(postcss@8.4.45) - postcss-safe-parser: 6.0.0(postcss@8.4.45) + known-css-properties: 0.35.0 + postcss: 8.4.47 + postcss-load-config: 3.1.4(postcss@8.4.47) + postcss-safe-parser: 6.0.0(postcss@8.4.47) postcss-selector-parser: 6.1.2 semver: 7.6.3 - svelte-eslint-parser: 0.41.0(svelte@5.0.0) + svelte-eslint-parser: 0.43.0(svelte@5.0.0) optionalDependencies: svelte: 5.0.0 transitivePeerDependencies: @@ -3306,12 +3624,12 @@ snapshots: eslint-visitor-keys@3.4.3: {} - eslint-visitor-keys@4.0.0: {} + eslint-visitor-keys@4.2.0: {} eslint@9.10.0: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.10.0) - '@eslint-community/regexpp': 4.11.0 + '@eslint-community/eslint-utils': 4.4.1(eslint@9.10.0) + '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.18.0 '@eslint/eslintrc': 3.1.0 '@eslint/js': 9.10.0 @@ -3325,8 +3643,8 @@ snapshots: debug: 4.3.7 escape-string-regexp: 4.0.0 eslint-scope: 8.0.2 - eslint-visitor-keys: 4.0.0 - espree: 10.1.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 @@ -3349,16 +3667,16 @@ snapshots: esm-env@1.0.0: {} - espree@10.1.0: + espree@10.3.0: dependencies: - acorn: 8.12.1 - acorn-jsx: 5.3.2(acorn@8.12.1) - eslint-visitor-keys: 4.0.0 + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 4.2.0 espree@9.6.1: dependencies: - acorn: 8.12.1 - acorn-jsx: 5.3.2(acorn@8.12.1) + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} @@ -3386,17 +3704,17 @@ snapshots: esutils@2.0.3: {} - execa@8.0.1: + event-stream@3.3.4: dependencies: - cross-spawn: 7.0.3 - get-stream: 8.0.1 - human-signals: 5.0.0 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.3.0 - onetime: 6.0.0 - signal-exit: 4.1.0 - strip-final-newline: 3.0.0 + duplexer: 0.1.2 + from: 0.1.7 + map-stream: 0.1.0 + pause-stream: 0.0.11 + split: 0.3.3 + stream-combiner: 0.0.4 + through: 2.3.8 + + expect-type@1.1.0: {} extendable-error@0.1.7: {} @@ -3462,6 +3780,8 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 + from@0.1.7: {} + fs-extra@7.0.1: dependencies: graceful-fs: 4.2.11 @@ -3474,18 +3794,17 @@ snapshots: jsonfile: 4.0.0 universalify: 0.1.2 + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true function-bind@1.1.2: {} - get-func-name@2.0.2: {} - get-stdin@9.0.0: {} - get-stream@8.0.1: {} - - get-tsconfig@4.8.0: + get-tsconfig@4.8.1: dependencies: resolve-pkg-maps: 1.0.0 @@ -3512,7 +3831,7 @@ snapshots: globals@14.0.0: {} - globals@15.9.0: {} + globals@15.12.0: {} globalyzer@0.1.0: {} @@ -3554,8 +3873,6 @@ snapshots: human-id@1.0.2: {} - human-signals@5.0.0: {} - iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -3603,8 +3920,6 @@ snapshots: dependencies: '@types/estree': 1.0.5 - is-stream@3.0.0: {} - is-subdir@1.2.0: dependencies: better-path-resolve: 1.0.0 @@ -3648,7 +3963,7 @@ snapshots: kleur@4.1.5: {} - known-css-properties@0.34.0: {} + known-css-properties@0.35.0: {} levn@0.4.1: dependencies: @@ -3673,9 +3988,7 @@ snapshots: lodash.startcase@4.4.0: {} - loupe@3.1.1: - dependencies: - get-func-name: 2.0.2 + loupe@3.1.2: {} lru-cache@10.4.3: {} @@ -3692,9 +4005,9 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 - mdn-data@2.0.30: {} + map-stream@0.1.0: {} - merge-stream@2.0.0: {} + mdn-data@2.0.30: {} merge2@1.4.1: {} @@ -3703,8 +4016,6 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 - mimic-fn@4.0.0: {} - minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -3735,20 +4046,12 @@ snapshots: dependencies: whatwg-url: 5.0.0 - npm-run-path@5.3.0: - dependencies: - path-key: 4.0.0 - object-assign@4.1.1: {} once@1.4.0: dependencies: wrappy: 1.0.2 - onetime@6.0.0: - dependencies: - mimic-fn: 4.0.0 - optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -3811,8 +4114,6 @@ snapshots: path-key@3.1.1: {} - path-key@4.0.0: {} - path-parse@1.0.7: {} path-scurry@1.11.1: @@ -3826,13 +4127,17 @@ snapshots: pathval@2.0.0: {} + pause-stream@0.0.11: + dependencies: + through: 2.3.8 + periscopic@3.1.0: dependencies: '@types/estree': 1.0.5 estree-walker: 3.0.3 is-reference: 3.0.2 - picocolors@1.1.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -3842,30 +4147,38 @@ snapshots: pirates@4.0.6: {} - postcss-load-config@3.1.4(postcss@8.4.45): + playwright-core@1.48.2: {} + + playwright@1.48.2: + dependencies: + playwright-core: 1.48.2 + optionalDependencies: + fsevents: 2.3.2 + + postcss-load-config@3.1.4(postcss@8.4.47): dependencies: lilconfig: 2.1.0 yaml: 1.10.2 optionalDependencies: - postcss: 8.4.45 + postcss: 8.4.47 - postcss-safe-parser@6.0.0(postcss@8.4.45): + postcss-safe-parser@6.0.0(postcss@8.4.47): dependencies: - postcss: 8.4.45 + postcss: 8.4.47 - postcss-scss@4.0.9(postcss@8.4.45): + postcss-scss@4.0.9(postcss@8.4.47): dependencies: - postcss: 8.4.45 + postcss: 8.4.47 postcss-selector-parser@6.1.2: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss@8.4.45: + postcss@8.4.47: dependencies: nanoid: 3.3.7 - picocolors: 1.1.0 + picocolors: 1.1.1 source-map-js: 1.2.1 prelude-ls@1.2.1: {} @@ -3891,6 +4204,10 @@ snapshots: kleur: 3.0.3 sisteransi: 1.0.5 + ps-tree@1.2.0: + dependencies: + event-stream: 3.3.4 + pseudomap@1.0.2: {} pump@3.0.2: @@ -3935,13 +4252,13 @@ snapshots: reusify@1.0.4: {} - rollup-plugin-esbuild@6.1.1(esbuild@0.21.5)(rollup@4.21.2): + rollup-plugin-esbuild@6.1.1(esbuild@0.24.0)(rollup@4.21.2): dependencies: '@rollup/pluginutils': 5.1.2(rollup@4.21.2) debug: 4.3.7 es-module-lexer: 1.5.4 - esbuild: 0.21.5 - get-tsconfig: 4.8.0 + esbuild: 0.24.0 + get-tsconfig: 4.8.1 rollup: 4.21.2 transitivePeerDependencies: - supports-color @@ -4001,7 +4318,7 @@ snapshots: silver-fleece@1.2.1: {} - sirv@2.0.4: + sirv@3.0.0: dependencies: '@polka/url': 1.0.0-next.25 mrmime: 2.0.0 @@ -4037,12 +4354,20 @@ snapshots: cross-spawn: 5.1.0 signal-exit: 3.0.7 + split@0.3.3: + dependencies: + through: 2.3.8 + sprintf-js@1.0.3: {} stackback@0.0.2: {} std-env@3.7.0: {} + stream-combiner@0.0.4: + dependencies: + duplexer: 0.1.2 + streamx@2.20.1: dependencies: fast-fifo: 1.3.2 @@ -4073,8 +4398,6 @@ snapshots: strip-bom@3.0.0: {} - strip-final-newline@3.0.0: {} - strip-json-comments@3.1.1: {} sucrase@3.35.0: @@ -4093,13 +4416,13 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-eslint-parser@0.41.0(svelte@5.0.0): + svelte-eslint-parser@0.43.0(svelte@5.0.0): dependencies: eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - postcss: 8.4.45 - postcss-scss: 4.0.9(postcss@8.4.45) + postcss: 8.4.47 + postcss-scss: 4.0.9(postcss@8.4.47) optionalDependencies: svelte: 5.0.0 @@ -4109,7 +4432,7 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 '@types/estree': 1.0.5 - acorn: 8.12.1 + acorn: 8.14.0 aria-query: 5.3.2 axobject-query: 4.1.0 code-red: 1.0.4 @@ -4125,8 +4448,8 @@ snapshots: '@ampproject/remapping': 2.3.0 '@jridgewell/sourcemap-codec': 1.5.0 '@types/estree': 1.0.5 - acorn: 8.12.1 - acorn-typescript: 1.4.13(acorn@8.12.1) + acorn: 8.14.0 + acorn-typescript: 1.4.13(acorn@8.14.0) aria-query: 5.3.2 axobject-query: 4.1.0 esm-env: 1.0.0 @@ -4173,6 +4496,8 @@ snapshots: dependencies: any-promise: 1.3.0 + through@2.3.8: {} + tiny-glob@0.2.9: dependencies: globalyzer: 0.1.0 @@ -4182,7 +4507,7 @@ snapshots: tinybench@2.9.0: {} - tinyexec@0.3.0: {} + tinyexec@0.3.1: {} tinyglobby@0.2.10: dependencies: @@ -4209,9 +4534,9 @@ snapshots: tr46@0.0.3: {} - ts-api-utils@1.3.0(typescript@5.6.2): + ts-api-utils@1.3.0(typescript@5.6.3): dependencies: - typescript: 5.6.2 + typescript: 5.6.3 ts-interface-checker@0.1.13: {} @@ -4226,18 +4551,18 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.5.0(eslint@9.10.0)(typescript@5.6.2): + typescript-eslint@8.5.0(eslint@9.10.0)(typescript@5.6.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.5.0(@typescript-eslint/parser@8.5.0(eslint@9.10.0)(typescript@5.6.2))(eslint@9.10.0)(typescript@5.6.2) - '@typescript-eslint/parser': 8.5.0(eslint@9.10.0)(typescript@5.6.2) - '@typescript-eslint/utils': 8.5.0(eslint@9.10.0)(typescript@5.6.2) + '@typescript-eslint/eslint-plugin': 8.5.0(@typescript-eslint/parser@8.5.0(eslint@9.10.0)(typescript@5.6.3))(eslint@9.10.0)(typescript@5.6.3) + '@typescript-eslint/parser': 8.5.0(eslint@9.10.0)(typescript@5.6.3) + '@typescript-eslint/utils': 8.5.0(eslint@9.10.0)(typescript@5.6.3) optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - eslint - supports-color - typescript@5.6.2: {} + typescript@5.6.3: {} undici-types@5.26.5: {} @@ -4245,21 +4570,21 @@ snapshots: universalify@0.1.2: {} - unplugin-isolated-decl@0.6.5(rollup@4.21.2)(typescript@5.6.2)(webpack-sources@3.2.3): + unplugin-isolated-decl@0.6.5(rollup@4.21.2)(typescript@5.6.3)(webpack-sources@3.2.3): dependencies: '@rollup/pluginutils': 5.1.2(rollup@4.21.2) magic-string: 0.30.12 oxc-parser: 0.30.3 unplugin: 1.14.1(webpack-sources@3.2.3) optionalDependencies: - typescript: 5.6.2 + typescript: 5.6.3 transitivePeerDependencies: - rollup - webpack-sources unplugin@1.14.1(webpack-sources@3.2.3): dependencies: - acorn: 8.12.1 + acorn: 8.14.0 webpack-virtual-modules: 0.6.2 optionalDependencies: webpack-sources: 3.2.3 @@ -4270,35 +4595,16 @@ snapshots: util-deprecate@1.0.2: {} - valibot@0.41.0(typescript@5.6.2): + valibot@0.41.0(typescript@5.6.3): optionalDependencies: - typescript: 5.6.2 - - vite-node@2.0.5(@types/node@18.19.64): - dependencies: - cac: 6.7.14 - debug: 4.3.7 - pathe: 1.1.2 - tinyrainbow: 1.2.0 - vite: 5.4.3(@types/node@18.19.64) - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser + typescript: 5.6.3 - vite-node@2.0.5(@types/node@22.5.4): + vite-node@2.1.4(@types/node@22.9.0): dependencies: cac: 6.7.14 debug: 4.3.7 pathe: 1.1.2 - tinyrainbow: 1.2.0 - vite: 5.4.3(@types/node@22.5.4) + vite: 5.4.10(@types/node@22.9.0) transitivePeerDependencies: - '@types/node' - less @@ -4310,85 +4616,44 @@ snapshots: - supports-color - terser - vite@5.4.3(@types/node@18.19.64): + vite@5.4.10(@types/node@22.9.0): dependencies: esbuild: 0.21.5 - postcss: 8.4.45 + postcss: 8.4.47 rollup: 4.21.2 optionalDependencies: - '@types/node': 18.19.64 + '@types/node': 22.9.0 fsevents: 2.3.3 - vite@5.4.3(@types/node@22.5.4): + vitest@2.1.4(@types/node@22.9.0)(@vitest/ui@2.1.4): dependencies: - esbuild: 0.21.5 - postcss: 8.4.45 - rollup: 4.21.2 - optionalDependencies: - '@types/node': 22.5.4 - fsevents: 2.3.3 - - vitest@2.0.5(@types/node@18.19.64)(@vitest/ui@2.0.5): - dependencies: - '@ampproject/remapping': 2.3.0 - '@vitest/expect': 2.0.5 - '@vitest/pretty-format': 2.0.5 - '@vitest/runner': 2.0.5 - '@vitest/snapshot': 2.0.5 - '@vitest/spy': 2.0.5 - '@vitest/utils': 2.0.5 - chai: 5.1.1 - debug: 4.3.7 - execa: 8.0.1 - magic-string: 0.30.12 - pathe: 1.1.2 - std-env: 3.7.0 - tinybench: 2.9.0 - tinypool: 1.0.1 - tinyrainbow: 1.2.0 - vite: 5.4.3(@types/node@18.19.64) - vite-node: 2.0.5(@types/node@18.19.64) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 18.19.64 - '@vitest/ui': 2.0.5(vitest@2.0.5) - transitivePeerDependencies: - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - vitest@2.0.5(@types/node@22.5.4)(@vitest/ui@2.0.5): - dependencies: - '@ampproject/remapping': 2.3.0 - '@vitest/expect': 2.0.5 - '@vitest/pretty-format': 2.0.5 - '@vitest/runner': 2.0.5 - '@vitest/snapshot': 2.0.5 - '@vitest/spy': 2.0.5 - '@vitest/utils': 2.0.5 - chai: 5.1.1 + '@vitest/expect': 2.1.4 + '@vitest/mocker': 2.1.4(vite@5.4.10(@types/node@22.9.0)) + '@vitest/pretty-format': 2.1.4 + '@vitest/runner': 2.1.4 + '@vitest/snapshot': 2.1.4 + '@vitest/spy': 2.1.4 + '@vitest/utils': 2.1.4 + chai: 5.1.2 debug: 4.3.7 - execa: 8.0.1 + expect-type: 1.1.0 magic-string: 0.30.12 pathe: 1.1.2 std-env: 3.7.0 tinybench: 2.9.0 + tinyexec: 0.3.1 tinypool: 1.0.1 tinyrainbow: 1.2.0 - vite: 5.4.3(@types/node@22.5.4) - vite-node: 2.0.5(@types/node@22.5.4) + vite: 5.4.10(@types/node@22.9.0) + vite-node: 2.1.4(@types/node@22.9.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.5.4 - '@vitest/ui': 2.0.5(vitest@2.0.5) + '@types/node': 22.9.0 + '@vitest/ui': 2.1.4(vitest@2.1.4) transitivePeerDependencies: - less - lightningcss + - msw - sass - sass-embedded - stylus diff --git a/prettier.config.js b/prettier.config.js index 1a3d9c70..e44ee21e 100644 --- a/prettier.config.js +++ b/prettier.config.js @@ -44,11 +44,13 @@ const packageSortOrder = [ 'keywords' ]; +/** @type {import("prettier").Config} */ export default { useTabs: true, singleQuote: true, trailingComma: 'none', printWidth: 100, + endOfLine: 'lf', plugins: ['prettier-plugin-packagejson', 'prettier-plugin-svelte'], overrides: [ { @@ -65,10 +67,7 @@ export default { } }, { - files: [ - '**/CHANGELOG.md', - 'packages/migrate/migrations/routes/*/samples.md' - ], + files: ['**/CHANGELOG.md', 'packages/migrate/migrations/routes/*/samples.md'], options: { requirePragma: true } @@ -80,4 +79,4 @@ export default { } } ] -} +}; diff --git a/rollup.config.js b/rollup.config.js index f66a0e6c..6ec4e049 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -35,7 +35,11 @@ function getConfig(project) { parsers: `${projectRoot}/tooling/parsers.ts` }; } else if (project === 'cli') { - inputs = [`${projectRoot}/index.ts`, `${projectRoot}/bin.ts`]; + inputs = [ + `${projectRoot}/lib/index.ts`, + `${projectRoot}/lib/testing.ts`, + `${projectRoot}/bin.ts` + ]; } else { inputs = [`${projectRoot}/index.ts`]; } @@ -68,6 +72,7 @@ function getConfig(project) { console.log('building templates'); const start = performance.now(); await buildTemplates(path.resolve('packages', 'cli', 'dist')); + await buildTemplates(path.resolve('packages', 'create', 'dist')); const end = performance.now(); console.log(`finished building templates: ${Math.round(end - start)}ms`); } @@ -107,7 +112,8 @@ function getConfig(project) { external, plugins: [ preserveShebangs(), - 'exports' in pkg && dts({ include: project === 'cli' ? [inputs[0]] : undefined }), + 'exports' in pkg && + dts({ include: project === 'cli' ? [`${projectRoot}/lib/*`] : undefined }), esbuild(), nodeResolve({ preferBuiltins: true, rootDir: projectRoot }), commonjs(), @@ -115,7 +121,7 @@ function getConfig(project) { dynamicImportVars({ // since we're relying on the usage of standard dynamic imports for community adders, we need to // prevent this plugin from transforming these cases - exclude: ['packages/cli/utils/fetch-packages.ts'] + exclude: ['packages/cli/commands/add/fetch-packages.ts'] }), buildCliTemplatesPlugin, communityAdderIdsPlugin diff --git a/vitest.workspace.ts b/vitest.workspace.ts new file mode 100644 index 00000000..2a7e8f5f --- /dev/null +++ b/vitest.workspace.ts @@ -0,0 +1,3 @@ +import { defineWorkspace } from 'vitest/config'; + +export default defineWorkspace(['packages/*', 'community-adder-template']);