sv 0.12.8 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/shared.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "addon"
13
13
  ],
14
14
  "exclude": [],
15
- "contents": "# Contributing Guide\n\nCheatsheet: [All official add-ons source code](https://github.com/sveltejs/cli/tree/main/packages/sv/src/addons)\n\n---\n\nSome convenient scripts are provided to help develop the add-on.\n\n```sh\n## create a new minimal project in the `demo` directory\nnpm run demo-create\n\n## add your current add-on to the demo project\nnpm run demo-add\n\n## run the tests\nnpm run test\n```\n\n## Key things to note\n\nYour `add-on` should:\n\n- export a function that returns a `defineAddon` object.\n- have a `package.json` with an `exports` field that points to the main entry point of the add-on.\n\n## Sharing your add-on\n\nWhen you're ready to publish your add-on to npm, run:\n\n```shell\nnpm login\nnpm publish\n```\n\n## Things to be aware of\n\nCommunity add-ons are **not permitted** to have any external dependencies outside of `sv`. If the use of a dependency is absolutely necessary, then they can be bundled using a bundler of your choosing (e.g. Rollup, Rolldown, tsup, etc.).\n"
15
+ "contents": "# Contributing Guide\n\nCheatsheet: [All official add-ons source code](https://github.com/sveltejs/cli/tree/main/packages/sv/src/addons)\n\n---\n\nSome convenient scripts are provided to help develop the add-on.\n\n```sh\n## create a new minimal project in the `demo` directory\nnpm run demo-create\n\n## add your current add-on to the demo project\nnpm run demo-add\n\n## run the tests\nnpm run test\n```\n\n## Key things to note\n\nYour `add-on` should:\n\n- export a function that returns a `defineAddon` object.\n- have a `package.json` with an `exports` field that points to the main entry point of the add-on.\n\n## Building\n\nYour add-on is bundled with [tsdown](https://tsdown.dev/) into a single file in `dist/`. This bundles everything except `sv` (which is a peer dependency provided at runtime).\n\n```sh\nnpm run build\n```\n\n## Publishing\n\nWhen you're ready to publish your add-on to npm:\n\n```sh\nnpm login\nnpm publish\n```\n\n> `prepublishOnly` will automatically run the build before publishing.\n\n## Things to be aware of\n\nCommunity add-ons must have `sv` as a `peerDependency` and should **not** have any `dependencies`. Everything else (including `@sveltejs/sv-utils`) is bundled at build time by tsdown.\n"
16
16
  },
17
17
  {
18
18
  "name": "README.md",
@@ -84,7 +84,7 @@
84
84
  "typescript"
85
85
  ],
86
86
  "exclude": [],
87
- "contents": "import adapter from '@sveltejs/adapter-auto';\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n\tkit: {\n\t\t// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.\n\t\t// If your environment is not supported, or you settled on a specific environment, switch out the adapter.\n\t\t// See https://svelte.dev/docs/kit/adapters for more information about adapters.\n\t\tadapter: adapter()\n\t},\n\tvitePlugin: {\n\t\tdynamicCompileOptions: ({ filename }) =>\n\t\t\tfilename.includes('node_modules') ? undefined : { runes: true }\n\t}\n};\n\nexport default config;\n"
87
+ "contents": "import adapter from '@sveltejs/adapter-auto';\nimport { relative, sep } from 'node:path';\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n\tcompilerOptions: {\n\t\t// defaults to rune mode for the project, except for `node_modules`. Can be removed in svelte 6.\n\t\trunes: ({ filename }) => {\n\t\t\tconst relativePath = relative(import.meta.dirname, filename);\n\t\t\tconst pathSegments = relativePath.toLowerCase().split(sep);\n\t\t\tconst isExternalLibrary = pathSegments.includes('node_modules');\n\n\t\t\treturn isExternalLibrary ? undefined : true;\n\t\t}\n\t},\n\tkit: {\n\t\t// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.\n\t\t// If your environment is not supported, or you settled on a specific environment, switch out the adapter.\n\t\t// See https://svelte.dev/docs/kit/adapters for more information about adapters.\n\t\tadapter: adapter()\n\t}\n};\n\nexport default config;\n"
88
88
  },
89
89
  {
90
90
  "name": "tsconfig.json",
@@ -100,7 +100,7 @@
100
100
  "exclude": [
101
101
  "typescript"
102
102
  ],
103
- "contents": "import adapter from '@sveltejs/adapter-auto';\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n\tkit: {\n\t\t// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.\n\t\t// If your environment is not supported, or you settled on a specific environment, switch out the adapter.\n\t\t// See https://svelte.dev/docs/kit/adapters for more information about adapters.\n\t\tadapter: adapter()\n\t},\n\tvitePlugin: {\n\t\tdynamicCompileOptions: ({ filename }) =>\n\t\t\tfilename.includes('node_modules') ? undefined : { runes: true }\n\t}\n};\n\nexport default config;\n"
103
+ "contents": "import adapter from '@sveltejs/adapter-auto';\nimport { relative, sep } from 'node:path';\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n\tcompilerOptions: {\n\t\t// defaults to rune mode for the project, except for `node_modules`. Can be removed in svelte 6.\n\t\trunes: ({ filename }) => {\n\t\t\tconst relativePath = relative(import.meta.dirname, filename);\n\t\t\tconst pathSegments = relativePath.toLowerCase().split(sep);\n\t\t\tconst isExternalLibrary = pathSegments.includes('node_modules');\n\n\t\t\treturn isExternalLibrary ? undefined : true;\n\t\t}\n\t},\n\tkit: {\n\t\t// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.\n\t\t// If your environment is not supported, or you settled on a specific environment, switch out the adapter.\n\t\t// See https://svelte.dev/docs/kit/adapters for more information about adapters.\n\t\tadapter: adapter()\n\t}\n};\n\nexport default config;\n"
104
104
  },
105
105
  {
106
106
  "name": "vite.config.ts",
@@ -1,4 +1,4 @@
1
- import { A as BooleanQuestion, C as defineAddon, D as WorkspaceOptions, E as Workspace, F as Question, I as SelectQuestion, L as StringQuestion, M as NumberQuestion, N as OptionDefinition, O as createWorkspace, P as OptionValues, R as officialAddons, S as Verification, T as getErrorHint, _ as Scripts, a as Addon, b as TestDefinition, c as AddonReference, d as ConditionDefinition, f as ConfiguredAddon, g as PreparedAddon, h as PackageDefinition, i as add, j as MultiSelectQuestion, k as BaseQuestion, l as AddonResult, m as OptionBuilder, n as InstallOptions, o as AddonDefinition, p as LoadedAddon, r as OptionMap, s as AddonInput, t as AddonMap, u as AddonSource, v as SetupResult, w as defineAddonOptions, x as Tests, y as SvApi } from "../engine-BZ0rj9tz.mjs";
1
+ import { A as BooleanQuestion, C as defineAddon, D as WorkspaceOptions, E as Workspace, F as Question, I as SelectQuestion, L as StringQuestion, M as NumberQuestion, N as OptionDefinition, O as createWorkspace, P as OptionValues, R as officialAddons, S as Verification, T as getErrorHint, _ as Scripts, a as Addon, b as TestDefinition, c as AddonReference, d as ConditionDefinition, f as ConfiguredAddon, g as PreparedAddon, h as PackageDefinition, i as add, j as MultiSelectQuestion, k as BaseQuestion, l as AddonResult, m as OptionBuilder, n as InstallOptions, o as AddonDefinition, p as LoadedAddon, r as OptionMap, s as AddonInput, t as AddonMap, u as AddonSource, v as SetupResult, w as defineAddonOptions, x as Tests, y as SvApi } from "../engine-fG9K-byo.mjs";
2
2
 
3
3
  //#region src/create/index.d.ts
4
4
  type TemplateType = (typeof templateTypes)[number];
@@ -1,4 +1,2 @@
1
- import { p as create } from "../package-manager-BYzDyeam.mjs";
2
- import { c as officialAddons, l as defineAddon, t as add, u as defineAddonOptions } from "../engine-DUNH7ELq.mjs";
3
-
4
- export { add, create, defineAddon, defineAddonOptions, officialAddons };
1
+ import { d as defineAddon, f as defineAddonOptions, t as add, u as officialAddons, v as create } from "../engine-lCnxwqd0.mjs";
2
+ export { add, create, defineAddon, defineAddonOptions, officialAddons };
@@ -1,10 +1,10 @@
1
- import { r as OptionMap, t as AddonMap } from "../engine-BZ0rj9tz.mjs";
1
+ import { r as OptionMap, t as AddonMap } from "../engine-fG9K-byo.mjs";
2
2
  import { AgentName } from "@sveltejs/sv-utils";
3
3
  import { Page } from "@playwright/test";
4
+ import * as vitest from "vitest";
4
5
  import { TestProject } from "vitest/node";
5
6
 
6
7
  //#region src/core/package-manager.d.ts
7
-
8
8
  declare function addPnpmBuildDependencies(cwd: string, packageManager: AgentName | null | undefined, allowedPackages: string[]): Promise<void>;
9
9
  //#endregion
10
10
  //#region src/testing.d.ts
@@ -12,14 +12,12 @@ type ProjectVariant = "kit-js" | "kit-ts" | "vite-js" | "vite-ts";
12
12
  declare const variants: ProjectVariant[];
13
13
  type CreateProject = (options: {
14
14
  testId: string;
15
- variant: ProjectVariant;
16
- /** @default true */
15
+ variant: ProjectVariant; /** @default true */
17
16
  clean?: boolean;
18
17
  }) => string;
19
18
  type SetupOptions = {
20
19
  cwd: string;
21
- variants: readonly ProjectVariant[];
22
- /** @default false */
20
+ variants: readonly ProjectVariant[]; /** @default false */
23
21
  clean?: boolean;
24
22
  };
25
23
  declare function setup({
@@ -104,5 +102,11 @@ declare function prepareServer({
104
102
  buildCommand,
105
103
  previewCommand
106
104
  }: PrepareServerOptions): Promise<PrepareServerReturn>;
105
+ type VitestContext = Pick<typeof vitest, "inject" | "test" | "beforeAll" | "beforeEach">;
106
+ declare function createSetupTest(vitest: VitestContext): <Addons extends AddonMap>(addons: Addons, options?: SetupTestOptions<Addons>) => {
107
+ test: vitest.TestAPI<Fixtures>;
108
+ testCases: Array<AddonTestCase<AddonMap>>;
109
+ prepareServer: typeof prepareServer;
110
+ };
107
111
  //#endregion
108
- export { AddonTestCase, CreateProject, Fixtures, PrepareServerOptions, PrepareServerReturn, ProjectVariant, SetupTestOptions, addPnpmBuildDependencies, createProject, prepareServer, setup, setupGlobal, startPreview, variants };
112
+ export { AddonTestCase, CreateProject, Fixtures, PrepareServerOptions, PrepareServerReturn, ProjectVariant, SetupTestOptions, VitestContext, addPnpmBuildDependencies, createProject, createSetupTest, prepareServer, setup, setupGlobal, startPreview, variants };
@@ -1,9 +1,8 @@
1
- import { B as __toESM, R as __commonJSMin, T as q, n as addPnpmBuildDependencies, p as create, w as K, z as __require } from "../package-manager-BYzDyeam.mjs";
1
+ import { _ as z, b as __require, g as R, i as addPnpmBuildDependencies, t as add, v as create, x as __toESM, y as __commonJSMin } from "../engine-lCnxwqd0.mjs";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import process$1 from "node:process";
5
5
  import { execSync } from "node:child_process";
6
-
7
6
  //#region ../../node_modules/.pnpm/through@2.3.8/node_modules/through/index.js
8
7
  var require_through = /* @__PURE__ */ __commonJSMin(((exports, module) => {
9
8
  var Stream$4 = __require("stream");
@@ -83,15 +82,14 @@ var require_through = /* @__PURE__ */ __commonJSMin(((exports, module) => {
83
82
  return stream;
84
83
  }
85
84
  }));
86
-
87
85
  //#endregion
88
86
  //#region ../../node_modules/.pnpm/from@0.1.7/node_modules/from/index.js
89
87
  var require_from = /* @__PURE__ */ __commonJSMin(((exports, module) => {
90
88
  var Stream$3 = __require("stream");
91
- module.exports = function from$1(source) {
89
+ module.exports = function from(source) {
92
90
  if (Array.isArray(source)) {
93
91
  var source_index = 0, source_len = source.length;
94
- return from$1(function(i$1) {
92
+ return from(function(i) {
95
93
  if (source_index < source_len) this.emit("data", source[source_index++]);
96
94
  else this.emit("end");
97
95
  return true;
@@ -135,7 +133,6 @@ var require_from = /* @__PURE__ */ __commonJSMin(((exports, module) => {
135
133
  return s;
136
134
  };
137
135
  }));
138
-
139
136
  //#endregion
140
137
  //#region ../../node_modules/.pnpm/duplexer@0.1.2/node_modules/duplexer/index.js
141
138
  var require_duplexer = /* @__PURE__ */ __commonJSMin(((exports, module) => {
@@ -184,8 +181,8 @@ var require_duplexer = /* @__PURE__ */ __commonJSMin(((exports, module) => {
184
181
  }
185
182
  }
186
183
  function proxyStream(methodName) {
187
- reader.on(methodName, reemit$1);
188
- function reemit$1() {
184
+ reader.on(methodName, reemit);
185
+ function reemit() {
189
186
  var args = slice.call(arguments);
190
187
  args.unshift(methodName);
191
188
  stream.emit.apply(stream, args);
@@ -203,7 +200,6 @@ var require_duplexer = /* @__PURE__ */ __commonJSMin(((exports, module) => {
203
200
  }
204
201
  }
205
202
  }));
206
-
207
203
  //#endregion
208
204
  //#region ../../node_modules/.pnpm/map-stream@0.1.0/node_modules/map-stream/index.js
209
205
  var require_map_stream = /* @__PURE__ */ __commonJSMin(((exports, module) => {
@@ -284,13 +280,11 @@ var require_map_stream = /* @__PURE__ */ __commonJSMin(((exports, module) => {
284
280
  return stream;
285
281
  };
286
282
  }));
287
-
288
283
  //#endregion
289
284
  //#region ../../node_modules/.pnpm/pause-stream@0.0.11/node_modules/pause-stream/index.js
290
285
  var require_pause_stream = /* @__PURE__ */ __commonJSMin(((exports, module) => {
291
286
  module.exports = require_through();
292
287
  }));
293
-
294
288
  //#endregion
295
289
  //#region ../../node_modules/.pnpm/split@0.3.3/node_modules/split/index.js
296
290
  var require_split = /* @__PURE__ */ __commonJSMin(((exports, module) => {
@@ -331,7 +325,6 @@ var require_split = /* @__PURE__ */ __commonJSMin(((exports, module) => {
331
325
  });
332
326
  }
333
327
  }));
334
-
335
328
  //#endregion
336
329
  //#region ../../node_modules/.pnpm/stream-combiner@0.0.4/node_modules/stream-combiner/index.js
337
330
  var require_stream_combiner = /* @__PURE__ */ __commonJSMin(((exports, module) => {
@@ -340,10 +333,10 @@ var require_stream_combiner = /* @__PURE__ */ __commonJSMin(((exports, module) =
340
333
  var streams = [].slice.call(arguments), first = streams[0], last = streams[streams.length - 1], thepipe = duplexer(first, last);
341
334
  if (streams.length == 1) return streams[0];
342
335
  else if (!streams.length) throw new Error("connect called with empty args");
343
- function recurse(streams$1) {
344
- if (streams$1.length < 2) return;
345
- streams$1[0].pipe(streams$1[1]);
346
- recurse(streams$1.slice(1));
336
+ function recurse(streams) {
337
+ if (streams.length < 2) return;
338
+ streams[0].pipe(streams[1]);
339
+ recurse(streams.slice(1));
347
340
  }
348
341
  recurse(streams);
349
342
  function onerror() {
@@ -355,7 +348,6 @@ var require_stream_combiner = /* @__PURE__ */ __commonJSMin(((exports, module) =
355
348
  return thepipe;
356
349
  };
357
350
  }));
358
-
359
351
  //#endregion
360
352
  //#region ../../node_modules/.pnpm/event-stream@3.3.4/node_modules/event-stream/index.js
361
353
  var require_event_stream = /* @__PURE__ */ __commonJSMin(((exports) => {
@@ -460,8 +452,8 @@ var require_event_stream = /* @__PURE__ */ __commonJSMin(((exports) => {
460
452
  reading = false;
461
453
  get.apply(null, arguments);
462
454
  });
463
- } catch (err$1) {
464
- stream.emit("error", err$1);
455
+ } catch (err) {
456
+ stream.emit("error", err);
465
457
  }
466
458
  });
467
459
  }
@@ -516,13 +508,13 @@ var require_event_stream = /* @__PURE__ */ __commonJSMin(((exports) => {
516
508
  });
517
509
  };
518
510
  es$1.stringify = function() {
519
- var Buffer$1 = __require("buffer").Buffer;
511
+ var Buffer = __require("buffer").Buffer;
520
512
  return es$1.mapSync(function(e) {
521
- return JSON.stringify(Buffer$1.isBuffer(e) ? e.toString() : e) + "\n";
513
+ return JSON.stringify(Buffer.isBuffer(e) ? e.toString() : e) + "\n";
522
514
  });
523
515
  };
524
- es$1.replace = function(from$1, to) {
525
- return es$1.pipeline(es$1.split(from$1), es$1.join(to));
516
+ es$1.replace = function(from, to) {
517
+ return es$1.pipeline(es$1.split(from), es$1.join(to));
526
518
  };
527
519
  es$1.join = function(str) {
528
520
  if ("function" === typeof str) return es$1.wait(str);
@@ -549,10 +541,9 @@ var require_event_stream = /* @__PURE__ */ __commonJSMin(((exports) => {
549
541
  throw new Error("[EVENT-STREAM] es.pipeable is deprecated");
550
542
  };
551
543
  }));
552
-
553
544
  //#endregion
554
- //#region ../../node_modules/.pnpm/ps-tree@1.2.0/node_modules/ps-tree/index.js
555
- var require_ps_tree = /* @__PURE__ */ __commonJSMin(((exports, module) => {
545
+ //#region src/testing.ts
546
+ var import_ps_tree = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
556
547
  var spawn$1 = __require("child_process").spawn, es = require_event_stream();
557
548
  module.exports = function childrenOfPid(pid, callback) {
558
549
  var headers = null;
@@ -608,11 +599,7 @@ var require_ps_tree = /* @__PURE__ */ __commonJSMin(((exports, module) => {
608
599
  default: throw new Error("Unknown process listing header: " + str);
609
600
  }
610
601
  }
611
- }));
612
-
613
- //#endregion
614
- //#region src/testing.ts
615
- var import_ps_tree = /* @__PURE__ */ __toESM(require_ps_tree(), 1);
602
+ })))(), 1);
616
603
  const variants = [
617
604
  "kit-js",
618
605
  "kit-ts",
@@ -620,15 +607,15 @@ const variants = [
620
607
  "vite-ts"
621
608
  ];
622
609
  const TEMPLATES_DIR = ".templates";
623
- function setup({ cwd: cwd$1, clean = false, variants: variants$1 }) {
624
- const workingDir = path.resolve(cwd$1);
610
+ function setup({ cwd, clean = false, variants }) {
611
+ const workingDir = path.resolve(cwd);
625
612
  if (clean && fs.existsSync(workingDir)) fs.rmSync(workingDir, {
626
613
  force: true,
627
614
  recursive: true
628
615
  });
629
616
  const templatesDir = path.resolve(workingDir, TEMPLATES_DIR);
630
617
  fs.mkdirSync(templatesDir, { recursive: true });
631
- for (const variant of variants$1) {
618
+ for (const variant of variants) {
632
619
  const templatePath = path.resolve(templatesDir, variant);
633
620
  if (fs.existsSync(templatePath)) continue;
634
621
  if (variant === "kit-js") create(templatePath, {
@@ -655,8 +642,8 @@ function setup({ cwd: cwd$1, clean = false, variants: variants$1 }) {
655
642
  }
656
643
  return { templatesDir };
657
644
  }
658
- function createProject({ cwd: cwd$1, testName, templatesDir }) {
659
- const testDir = path.resolve(cwd$1, testName);
645
+ function createProject({ cwd, testName, templatesDir }) {
646
+ const testDir = path.resolve(cwd, testName);
660
647
  fs.mkdirSync(testDir, { recursive: true });
661
648
  return ({ testId, variant, clean = true }) => {
662
649
  const targetDir = path.resolve(testDir, testId);
@@ -672,11 +659,11 @@ function createProject({ cwd: cwd$1, testName, templatesDir }) {
672
659
  return targetDir;
673
660
  };
674
661
  }
675
- async function startPreview({ cwd: cwd$1, command = "npm run preview" }) {
662
+ async function startPreview({ cwd, command = "npm run preview" }) {
676
663
  const [cmd, ...args] = command.split(" ");
677
- const proc = q(cmd, args, {
664
+ const proc = z(cmd, args, {
678
665
  nodeOptions: {
679
- cwd: cwd$1,
666
+ cwd,
680
667
  stdio: "pipe"
681
668
  },
682
669
  throwOnError: true,
@@ -686,13 +673,13 @@ async function startPreview({ cwd: cwd$1, command = "npm run preview" }) {
686
673
  if (!proc.pid) return;
687
674
  await terminate(proc.pid);
688
675
  };
689
- return await new Promise((resolve$1, reject) => {
676
+ return await new Promise((resolve, reject) => {
690
677
  if (!proc.process?.stdout) return reject("impossible state");
691
678
  proc.process.stdout.on("data", (data) => {
692
679
  const urls = data.toString().replace(/[^\x20-\xaf]+/g, "").replace(/\[[0-9]{1,2}m/g, "").match(/http:\/\/[^:\s]+:[0-9]+\//g);
693
680
  if (urls && urls.length > 0) {
694
681
  const url = urls[0];
695
- resolve$1({
682
+ resolve({
696
683
  url,
697
684
  close
698
685
  });
@@ -710,7 +697,7 @@ async function getProcessTree(pid) {
710
697
  }
711
698
  async function terminate(pid) {
712
699
  if (process$1.platform === "win32") {
713
- await K("taskkill", [
700
+ await R("taskkill", [
714
701
  "/PID",
715
702
  `${pid}`,
716
703
  "/T",
@@ -745,13 +732,13 @@ function setupGlobal({ TEST_DIR, pre, post }) {
745
732
  };
746
733
  };
747
734
  }
748
- async function prepareServer({ cwd: cwd$1, page, buildCommand = "pnpm build", previewCommand = "pnpm preview" }) {
735
+ async function prepareServer({ cwd, page, buildCommand = "pnpm build", previewCommand = "pnpm preview" }) {
749
736
  if (buildCommand) execSync(buildCommand, {
750
- cwd: cwd$1,
737
+ cwd,
751
738
  stdio: "pipe"
752
739
  });
753
740
  const { url, close } = await startPreview({
754
- cwd: cwd$1,
741
+ cwd,
755
742
  command: previewCommand
756
743
  });
757
744
  page.setDefaultNavigationTimeout(62e3);
@@ -766,6 +753,96 @@ async function prepareServer({ cwd: cwd$1, page, buildCommand = "pnpm build", pr
766
753
  close
767
754
  };
768
755
  }
769
-
756
+ function createSetupTest(vitest) {
757
+ return function setupTest(addons, options) {
758
+ const { inject, test: vitestTest, beforeAll, beforeEach } = vitest;
759
+ const test = vitestTest.extend({});
760
+ const cwd = inject("testDir");
761
+ const templatesDir = inject("templatesDir");
762
+ const variants = inject("variants");
763
+ const withBrowser = options?.browser ?? true;
764
+ let create;
765
+ let browser;
766
+ if (withBrowser) beforeAll(async () => {
767
+ let chromium;
768
+ try {
769
+ ({chromium} = await import("@playwright/test"));
770
+ } catch {
771
+ throw new Error("Browser testing requires @playwright/test. Install it with: pnpm add -D @playwright/test");
772
+ }
773
+ browser = await chromium.launch();
774
+ return async () => {
775
+ await browser.close();
776
+ };
777
+ });
778
+ const testCases = [];
779
+ for (const kind of options?.kinds ?? []) for (const variant of variants) {
780
+ const addonTestCase = {
781
+ variant,
782
+ kind
783
+ };
784
+ if (options?.filter === void 0 || options.filter(addonTestCase)) testCases.push(addonTestCase);
785
+ }
786
+ let testName;
787
+ test.beforeAll(async (_ctx, suite) => {
788
+ testName = path.dirname(suite.file.filepath).split("/").at(-1);
789
+ create = createProject({
790
+ cwd,
791
+ templatesDir,
792
+ testName
793
+ });
794
+ fs.writeFileSync(path.resolve(cwd, testName, "pnpm-workspace.yaml"), "packages:\n - '**/*'", "utf8");
795
+ fs.writeFileSync(path.resolve(cwd, testName, "package.json"), JSON.stringify({
796
+ name: `${testName}-workspace-root`,
797
+ private: true
798
+ }));
799
+ for (const addonTestCase of testCases) {
800
+ const { variant, kind } = addonTestCase;
801
+ const cwd = create({
802
+ testId: `${kind.type}-${variant}`,
803
+ variant
804
+ });
805
+ const metaPath = path.resolve(cwd, "meta.json");
806
+ fs.writeFileSync(metaPath, JSON.stringify({
807
+ variant,
808
+ kind
809
+ }, null, " "), "utf8");
810
+ if (options?.preAdd) await options.preAdd({
811
+ addonTestCase,
812
+ cwd
813
+ });
814
+ const { pnpmBuildDependencies } = await add({
815
+ cwd,
816
+ addons,
817
+ options: kind.options,
818
+ packageManager: "pnpm"
819
+ });
820
+ await addPnpmBuildDependencies(cwd, "pnpm", ["esbuild", ...pnpmBuildDependencies]);
821
+ }
822
+ execSync("pnpm install", {
823
+ cwd: path.resolve(cwd, testName),
824
+ stdio: "pipe"
825
+ });
826
+ });
827
+ beforeEach(async (ctx) => {
828
+ let browserCtx;
829
+ if (withBrowser) {
830
+ browserCtx = await browser.newContext();
831
+ ctx.page = await browserCtx.newPage();
832
+ }
833
+ ctx.cwd = (addonTestCase) => {
834
+ return path.join(cwd, testName, `${addonTestCase.kind.type}-${addonTestCase.variant}`);
835
+ };
836
+ return async () => {
837
+ if (withBrowser) await browserCtx.close();
838
+ };
839
+ });
840
+ return {
841
+ test,
842
+ testCases,
843
+ prepareServer
844
+ };
845
+ };
846
+ }
770
847
  //#endregion
771
- export { addPnpmBuildDependencies, createProject, prepareServer, setup, setupGlobal, startPreview, variants };
848
+ export { addPnpmBuildDependencies, createProject, createSetupTest, prepareServer, setup, setupGlobal, startPreview, variants };
@@ -1,4 +1,4 @@
1
- import { js, parse, svelte } from '@sveltejs/sv-utils';
1
+ import { transforms } from '@sveltejs/sv-utils';
2
2
  import { defineAddon, defineAddonOptions } from 'sv';
3
3
 
4
4
  const options = defineAddonOptions()
@@ -13,41 +13,41 @@ export default defineAddon({
13
13
  id: '~SV-NAME-TODO~',
14
14
  options,
15
15
 
16
- setup: ({ kit, unsupported }) => {
17
- if (!kit) unsupported('Requires SvelteKit');
16
+ setup: ({ isKit, unsupported }) => {
17
+ if (!isKit) unsupported('Requires SvelteKit');
18
18
  },
19
19
 
20
- run: ({ kit, sv, options, language, cancel }) => {
21
- if (!kit) return cancel('SvelteKit is required');
22
-
23
- sv.file(`src/lib/~SV-NAME-TODO~/content.txt`, () => {
24
- return `This is a text file made by the Community Addon Template demo for the add-on: '~SV-NAME-TODO~'!`;
25
- });
26
-
27
- sv.file(`src/lib/~SV-NAME-TODO~/HelloComponent.svelte`, (content) => {
28
- const { ast, generateCode } = parse.svelte(content);
29
- svelte.ensureScript(ast, { language });
30
-
31
- js.imports.addDefault(ast.instance.content, { as: 'content', from: './content.txt?raw' });
32
-
33
- svelte.addFragment(ast, '<p>{content}</p>');
34
- svelte.addFragment(ast, `<h2>Hello ${options.who}!</h2>`);
35
-
36
- return generateCode();
37
- });
38
-
39
- sv.file(kit.routesDirectory + '/+page.svelte', (content) => {
40
- const { ast, generateCode } = parse.svelte(content);
41
- svelte.ensureScript(ast, { language });
42
-
43
- js.imports.addDefault(ast.instance.content, {
44
- as: 'HelloComponent',
45
- from: `$lib/~SV-NAME-TODO~/HelloComponent.svelte`
46
- });
47
-
48
- svelte.addFragment(ast, '<HelloComponent />');
49
-
50
- return generateCode();
51
- });
20
+ run: ({ directory, sv, options, language }) => {
21
+ sv.file(
22
+ `${directory.lib}/~SV-NAME-TODO~/content.txt`,
23
+ transforms.text(() => {
24
+ return `This is a text file made by the Community Addon Template demo for the add-on: '~SV-NAME-TODO~'!`;
25
+ })
26
+ );
27
+
28
+ sv.file(
29
+ `${directory.lib}/~SV-NAME-TODO~/HelloComponent.svelte`,
30
+ transforms.svelteScript({ language }, ({ ast, svelte, js }) => {
31
+ js.imports.addDefault(ast.instance.content, {
32
+ as: 'content',
33
+ from: './content.txt?raw'
34
+ });
35
+
36
+ svelte.addFragment(ast, '<p>{content}</p>');
37
+ svelte.addFragment(ast, `<h2>Hello ${options.who}!</h2>`);
38
+ })
39
+ );
40
+
41
+ sv.file(
42
+ directory.kitRoutes + '/+page.svelte',
43
+ transforms.svelteScript({ language }, ({ ast, svelte, js }) => {
44
+ js.imports.addDefault(ast.instance.content, {
45
+ as: 'HelloComponent',
46
+ from: `$lib/~SV-NAME-TODO~/HelloComponent.svelte`
47
+ });
48
+
49
+ svelte.addFragment(ast, '<HelloComponent />');
50
+ })
51
+ );
52
52
  }
53
53
  });
@@ -1,129 +1,4 @@
1
- import { chromium } from '@playwright/test';
2
- import { execSync } from 'node:child_process';
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { add } from 'sv';
6
- import { createProject, addPnpmBuildDependencies, prepareServer } from 'sv/testing';
7
- import { inject, test as vitestTest, beforeAll, beforeEach } from 'vitest';
1
+ import { createSetupTest } from 'sv/testing';
2
+ import * as vitest from 'vitest';
8
3
 
9
- const cwd = inject('testDir');
10
- const templatesDir = inject('templatesDir');
11
- const variants = inject('variants');
12
-
13
- /**
14
- * @template {import('sv').AddonMap} AddonMap
15
- * @param {AddonMap} addons
16
- * @param {import('sv/testing').SetupTestOptions<AddonMap>} [options]
17
- * @returns {{ test: ReturnType<typeof vitestTest.extend<import('sv/testing').Fixtures>>, testCases: Array<import('sv/testing').AddonTestCase<AddonMap>>, prepareServer: typeof prepareServer }}
18
- */
19
- export function setupTest(addons, options) {
20
- /** @type {ReturnType<typeof vitestTest.extend<import('sv/testing').Fixtures>>} */
21
- // @ts-ignore - vitest.extend expects fixtures object but we provide it in beforeEach
22
- const test = vitestTest.extend({});
23
-
24
- const withBrowser = options?.browser ?? true;
25
-
26
- /** @type {ReturnType<typeof createProject>} */
27
- let create;
28
- /** @type {Awaited<ReturnType<typeof chromium.launch>>} */
29
- let browser;
30
-
31
- if (withBrowser) {
32
- beforeAll(async () => {
33
- browser = await chromium.launch();
34
- return async () => {
35
- await browser.close();
36
- };
37
- });
38
- }
39
-
40
- /** @type {Array<import('sv/testing').AddonTestCase<AddonMap>>} */
41
- const testCases = [];
42
- for (const kind of options?.kinds ?? []) {
43
- for (const variant of variants) {
44
- const addonTestCase = { variant, kind };
45
- if (options?.filter === undefined || options.filter(addonTestCase)) {
46
- testCases.push(addonTestCase);
47
- }
48
- }
49
- }
50
- /** @type {string} */
51
- let testName;
52
- test.beforeAll(async (_ctx, suite) => {
53
- testName = path.dirname(suite.name).split('/').at(-1) ?? '';
54
-
55
- // constructs a builder to create test projects
56
- create = createProject({ cwd, templatesDir, testName });
57
-
58
- // creates a pnpm workspace in each addon dir
59
- fs.writeFileSync(
60
- path.resolve(cwd, testName, 'pnpm-workspace.yaml'),
61
- "packages:\n - '**/*'",
62
- 'utf8'
63
- );
64
-
65
- // creates a barebones package.json in each addon dir
66
- fs.writeFileSync(
67
- path.resolve(cwd, testName, 'package.json'),
68
- JSON.stringify({
69
- name: `${testName}-workspace-root`,
70
- private: true
71
- })
72
- );
73
-
74
- for (const addonTestCase of testCases) {
75
- const { variant, kind } = addonTestCase;
76
- const cwd = create({ testId: `${kind.type}-${variant}`, variant });
77
-
78
- // test metadata
79
- const metaPath = path.resolve(cwd, 'meta.json');
80
- fs.writeFileSync(metaPath, JSON.stringify({ variant, kind }, null, '\t'), 'utf8');
81
-
82
- if (options?.preAdd) {
83
- await options.preAdd({ addonTestCase, cwd });
84
- }
85
- const { pnpmBuildDependencies } = await add({
86
- cwd,
87
- addons,
88
- options: kind.options,
89
- packageManager: 'pnpm'
90
- });
91
- await addPnpmBuildDependencies(cwd, 'pnpm', ['esbuild', ...pnpmBuildDependencies]);
92
- }
93
-
94
- execSync('pnpm install', { cwd: path.resolve(cwd, testName), stdio: 'pipe' });
95
- });
96
-
97
- // runs before each test case
98
- /**
99
- * @param {import('sv/testing').Fixtures & import('vitest').TestContext} ctx
100
- */
101
- beforeEach(async (ctx) => {
102
- /** @type {Awaited<ReturnType<typeof browser.newContext>>} */
103
- let browserCtx;
104
- if (withBrowser) {
105
- browserCtx = await browser.newContext();
106
- /** @type {import('sv/testing').Fixtures} */ (/** @type {unknown} */ (ctx)).page =
107
- await browserCtx.newPage();
108
- }
109
-
110
- /**
111
- * @param {import('sv/testing').AddonTestCase<Addons>} addonTestCase
112
- * @returns {string}
113
- */
114
- /** @type {import('sv/testing').Fixtures} */ (/** @type {unknown} */ (ctx)).cwd = (
115
- addonTestCase
116
- ) => {
117
- return path.join(cwd, testName, `${addonTestCase.kind.type}-${addonTestCase.variant}`);
118
- };
119
-
120
- return async () => {
121
- if (withBrowser) {
122
- await browserCtx.close();
123
- }
124
- // ...other tear downs
125
- };
126
- });
127
-
128
- return { test, testCases, prepareServer };
129
- }
4
+ export const setupTest = createSetupTest(vitest);
@@ -0,0 +1,6 @@
1
+ import { defineConfig } from 'tsdown';
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.js'],
5
+ format: 'esm'
6
+ });