sv 1.0.0-next.7 → 1.0.0

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.
@@ -1,5 +1,4 @@
1
1
  import { AgentName } from "@sveltejs/sv-utils";
2
-
3
2
  //#region src/addons/index.d.ts
4
3
  type OfficialAddons = {
5
4
  prettier: Addon<any>;
@@ -7,6 +6,7 @@ type OfficialAddons = {
7
6
  vitest: Addon<any>;
8
7
  playwright: Addon<any>;
9
8
  tailwindcss: Addon<any>;
9
+ enhancedImg: Addon<any>;
10
10
  sveltekitAdapter: Addon<any>;
11
11
  drizzle: Addon<any>;
12
12
  betterAuth: Addon<any>;
@@ -58,54 +58,57 @@ type BaseQuestion<Args extends OptionDefinition> = {
58
58
  question: string;
59
59
  group?: string;
60
60
  /**
61
- * When this condition explicitly returns `false`, the question's value will
62
- * always be `undefined` and will not fallback to the specified `default` value.
63
- */
61
+ * When this condition explicitly returns `false`, the question's value will
62
+ * always be `undefined` and will not fallback to the specified `default` value.
63
+ */
64
64
  condition?: (options: OptionValues<Args>) => boolean;
65
65
  };
66
66
  type Question<Args extends OptionDefinition = OptionDefinition> = BaseQuestion<Args> & (BooleanQuestion | StringQuestion | NumberQuestion | SelectQuestion<any> | MultiSelectQuestion<any>);
67
67
  type OptionDefinition = Record<string, Question<any>>;
68
- type OptionValues<Args extends OptionDefinition> = { [K in keyof Args]: Args[K] extends StringQuestion ? string : Args[K] extends BooleanQuestion ? boolean : Args[K] extends NumberQuestion ? number : Args[K] extends SelectQuestion<infer Value> ? Value : Args[K] extends MultiSelectQuestion<infer Value> ? Value[] : Args[K] extends Question<any> ? unknown : "ERROR: The value for this type is invalid. Ensure that the `default` value exists in `options`." };
68
+ type OptionValues<Args extends OptionDefinition> = { [K in keyof Args]: Args[K] extends StringQuestion ? string : Args[K] extends BooleanQuestion ? boolean : Args[K] extends NumberQuestion ? number : Args[K] extends SelectQuestion<infer Value> ? Value : Args[K] extends MultiSelectQuestion<infer Value> ? Value[] : Args[K] extends Question<any> ? unknown : "ERROR: The value for this type is invalid. Ensure that the `default` value exists in `options`."; };
69
69
  //#endregion
70
70
  //#region src/core/workspace.d.ts
71
71
  type WorkspaceOptions<Args extends OptionDefinition> = OptionValues<Args>;
72
72
  type Workspace = {
73
73
  cwd: string;
74
74
  /**
75
- * Returns the dependency version declared in the package.json.
76
- * This may differ from the installed version.
77
- * Includes both dependencies and devDependencies.
78
- * Also checks parent package.json files if called in a monorepo.
79
- * @param pkg the package to check for
80
- * @returns the dependency version with any leading characters such as ^ or ~ removed
81
- */
82
- dependencyVersion: (pkg: string) => string | undefined; /** to know if the workspace is using typescript or javascript */
75
+ * Returns the dependency version declared in the package.json.
76
+ * This may differ from the installed version.
77
+ * Includes both dependencies and devDependencies.
78
+ * Also checks parent package.json files if called in a monorepo.
79
+ * @param pkg the package to check for
80
+ * @returns the dependency version with any leading characters such as ^ or ~ removed
81
+ */
82
+ dependencyVersion: (pkg: string) => string | undefined;
83
+ /** to know if the workspace is using typescript or javascript */
83
84
  language: "ts" | "js";
84
85
  file: {
85
86
  viteConfig: "vite.config.js" | "vite.config.ts";
86
- typeConfig: "jsconfig.json" | "tsconfig.json" | undefined; /** `${directory.routes}/layout.css` or `src/app.css` */
87
+ typeConfig: "jsconfig.json" | "tsconfig.json" | undefined;
88
+ /** `${directory.routes}/layout.css` or `src/app.css` */
87
89
  stylesheet: `${string}/layout.css` | "src/app.css";
88
90
  package: "package.json";
89
- gitignore: ".gitignore"; /** Get the relative path between two files */
90
- getRelative: ({
91
- from,
92
- to
93
- }: {
91
+ gitignore: ".gitignore";
92
+ /** Get the relative path between two files */
93
+ getRelative: ({ from, to }: {
94
94
  from?: string;
95
95
  to: string;
96
96
  }) => string;
97
97
  /**
98
- * Find a file by walking up the directory tree from cwd.
99
- * Returns the relative path from cwd, or the filename itself if not found.
100
- */
98
+ * Find a file by walking up the directory tree from cwd.
99
+ * Returns the relative path from cwd, or the filename itself if not found.
100
+ */
101
101
  findUp: (filename: string) => string;
102
102
  };
103
103
  isKit: boolean;
104
104
  directory: {
105
- src: string; /** In SvelteKit taking `kit.files.lib` automatically. Falls back to `src/lib` in non-Kit projects */
106
- lib: string; /** In SvelteKit taking `kit.files.routes` automatically. Falls back to `src/routes` in non-Kit projects */
105
+ src: string;
106
+ /** In SvelteKit taking `kit.files.lib` automatically. Falls back to `src/lib` in non-Kit projects */
107
+ lib: string;
108
+ /** In SvelteKit taking `kit.files.routes` automatically. Falls back to `src/routes` in non-Kit projects */
107
109
  kitRoutes: string;
108
- }; /** The package manager used to install dependencies */
110
+ };
111
+ /** The package manager used to install dependencies */
109
112
  packageManager: AgentName;
110
113
  };
111
114
  //#endregion
@@ -114,97 +117,114 @@ type ConditionDefinition = (Workspace: Workspace) => boolean;
114
117
  type FileEdit = (content: string) => string | false;
115
118
  type FileEditMultiple = (content: string, path: string) => string | false;
116
119
  type SvApi = {
117
- /** Add a package to the dependencies. */dependency: (pkg: string, version: string) => void; /** Add a package to the dev dependencies. */
118
- devDependency: (pkg: string, version: string) => void; /** Execute a command in the workspace. */
120
+ /** Add a package to the dependencies. */
121
+ dependency: (pkg: string, version: string) => void;
122
+ /** Add a package to the dev dependencies. */
123
+ devDependency: (pkg: string, version: string) => void;
124
+ /** Execute a command in the workspace. */
119
125
  execute: (args: string[], stdio: "inherit" | "pipe") => Promise<void>;
120
126
  /**
121
- * Edit a file in the workspace. (will create it if it doesn't exist)
122
- *
123
- * Return `false` from the callback to abort - the original content is returned unchanged.
124
- */
125
- file: (path: string, edit: FileEdit) => void; /** Remove a file from the workspace. Respects the migration file filter. */
127
+ * Edit a file in the workspace. (will create it if it doesn't exist)
128
+ *
129
+ * Return `false` from the callback to abort - the original content is returned unchanged.
130
+ */
131
+ file: (path: string, edit: FileEdit) => void;
132
+ /** Remove a file from the workspace. Respects the migration file filter. */
126
133
  removeFile: (path: string) => void;
127
134
  /**
128
- * Edits matching files in the workspace.
129
- * The `include` and `exclude` patterns are glob patterns relative to the workspace root.
130
- * For each matching file, the `edit` callback is called with the file content,
131
- * and should return the new content (or `false` to abort editing that file).
132
- *
133
- * Note: always adds excludes for `node_modules` and dot-prefixed directories
134
- */
135
+ * Edits matching files in the workspace.
136
+ * The `include` and `exclude` patterns are glob patterns relative to the workspace root.
137
+ * For each matching file, the `edit` callback is called with the file content,
138
+ * and should return the new content (or `false` to abort editing that file).
139
+ *
140
+ * Note: always adds excludes for `node_modules` and dot-prefixed directories
141
+ */
135
142
  files: (options: {
136
- /** Glob patterns to include */include: string | string[]; /** Glob patterns to exclude */
143
+ /** Glob patterns to include */
144
+ include: string | string[];
145
+ /** Glob patterns to exclude */
137
146
  exclude?: string[];
138
147
  /**
139
- * Only run `edit` for files whose current content matches this predicate.
140
- * Useful for avoiding expensive transforms on unrelated files.
141
- */
148
+ * Only run `edit` for files whose current content matches this predicate.
149
+ * Useful for avoiding expensive transforms on unrelated files.
150
+ */
142
151
  where?: (content: string) => boolean;
143
152
  }, edit: FileEditMultiple) => void;
144
153
  };
145
154
  type Addon<Args extends OptionDefinition, Id extends string = string, Setup extends Record<string, unknown> = Record<string, unknown>> = {
146
155
  id: Id;
147
- alias?: string; /** one-liner shown in prompts */
148
- shortDescription?: string; /** link to docs/repo */
149
- homepage?: string; /** If true, this addon won't appear in the interactive prompt but can still be used via CLI */
156
+ alias?: string;
157
+ /** one-liner shown in prompts */
158
+ shortDescription?: string;
159
+ /** link to docs/repo */
160
+ homepage?: string;
161
+ /** If true, this addon won't appear in the interactive prompt but can still be used via CLI */
150
162
  hidden?: boolean;
151
- options: Args; /** Setup the addon. Will be called before the addon is run. */
163
+ options: Args;
164
+ /** Setup the addon. Will be called before the addon is run. */
152
165
  setup?: (workspace: Workspace & {
153
- /** On what official addons does this addon depend on? */dependsOn: (name: keyof typeof officialAddons) => void;
166
+ /** On what official addons does this addon depend on? */
167
+ dependsOn: (name: keyof typeof officialAddons) => void;
154
168
  /**
155
- * Why is this addon not supported?
156
- * @example
157
- * if (!isKit) unsupported('Requires SvelteKit');
158
- */
159
- unsupported: (reason: string) => void; /** On what official addons does this addon run after? */
160
- runsAfter: (name: keyof typeof officialAddons) => void; /** Dynamically add an option to be prompted to the user */
169
+ * Why is this addon not supported?
170
+ * @example
171
+ * if (!isKit) unsupported('Requires SvelteKit');
172
+ */
173
+ unsupported: (reason: string) => void;
174
+ /** On what official addons does this addon run after? */
175
+ runsAfter: (name: keyof typeof officialAddons) => void;
176
+ /** Dynamically add an option to be prompted to the user */
161
177
  addOption: <K extends Extract<keyof Setup, string>>(key: K, question: SetupOptions<Setup>[K]) => void;
162
- }) => MaybePromise<void>; /** Run the addon. The actual execution of the addon... Add files, edit files, etc. */
178
+ }) => MaybePromise<void>;
179
+ /** Run the addon. The actual execution of the addon... Add files, edit files, etc. */
163
180
  run: (workspace: Workspace & {
164
- /** Add-on options (includes dynamically added options from setup) */options: WorkspaceOptions<Args> & Record<string, unknown>; /** Api to interact with the workspace. */
181
+ /** Add-on options (includes dynamically added options from setup) */
182
+ options: WorkspaceOptions<Args> & Record<string, unknown>;
183
+ /** Api to interact with the workspace. */
165
184
  sv: SvApi;
166
185
  /** Cancel the addon at any time!
167
- * @example
168
- * return cancel('There is a problem with...');
169
- */
186
+ * @example
187
+ * return cancel('There is a problem with...');
188
+ */
170
189
  cancel: (reason: string) => void;
171
- }) => MaybePromise<void>; /** Next steps to display after the addon is run. */
190
+ }) => MaybePromise<void>;
191
+ /** Next steps to display after the addon is run. */
172
192
  nextSteps?: (workspace: Workspace & {
173
193
  options: WorkspaceOptions<Args> & Record<string, unknown>;
174
194
  }) => string[];
175
195
  };
176
196
  /** Maps value types to question definitions for dynamic setup options */
177
- type SetupOptions<T extends Record<string, unknown>> = { [K in keyof T]: BaseQuestion<any> & (T[K] extends boolean ? BooleanQuestion : T[K] extends string ? StringQuestion : T[K] extends number ? NumberQuestion : T[K] extends Array<infer V> ? MultiSelectQuestion<V> : Question<any>) };
197
+ type SetupOptions<T extends Record<string, unknown>> = { [K in keyof T]: BaseQuestion<any> & (T[K] extends boolean ? BooleanQuestion : T[K] extends string ? StringQuestion : T[K] extends number ? NumberQuestion : T[K] extends Array<infer V> ? MultiSelectQuestion<V> : Question<any>); };
178
198
  /**
179
- * The entry point for your add-on.
180
- *
181
- * ```ts
182
- * const addon = defineAddon({ id: 'my-addon', options, run });
183
- * ```
184
- *
185
- * If your add-on adds dynamic options via `addOption` during setup, pass their
186
- * types as a type argument:
187
- * ```ts
188
- * const addon = defineAddon<{ extra: boolean }>()({ ... });
189
- * // Take note of the extra call here: 👆 👆
190
- * // This works around Typescript's lack of partial type arguments
191
- * addon.options.extra.default; // boolean
192
- * ```
193
- */
199
+ * The entry point for your add-on.
200
+ *
201
+ * ```ts
202
+ * const addon = defineAddon({ id: 'my-addon', options, run });
203
+ * ```
204
+ *
205
+ * If your add-on adds dynamic options via `addOption` during setup, pass their
206
+ * types as a type argument:
207
+ * ```ts
208
+ * const addon = defineAddon<{ extra: boolean }>()({ ... });
209
+ * // Take note of the extra call here: 👆 👆
210
+ * // This works around Typescript's lack of partial type arguments
211
+ * addon.options.extra.default; // boolean
212
+ * ```
213
+ */
194
214
  declare function defineAddon<const Id extends string, Args extends OptionDefinition>(config: Addon<Args, Id>): Addon<Args, Id>;
195
215
  declare function defineAddon<SetupValues extends Record<string, unknown>>(): <const Id extends string, Args extends OptionDefinition>(config: Omit<Addon<Args & SetupOptions<SetupValues>, Id, SetupValues>, "options"> & {
196
216
  options: Args;
197
217
  }) => Addon<Args & SetupOptions<SetupValues>, Id, SetupValues>;
198
218
  /**
199
- * Stage 1: Raw CLI input - what the user typed
200
- */
219
+ * Stage 1: Raw CLI input - what the user typed
220
+ */
201
221
  type AddonInput = {
202
222
  readonly specifier: string;
203
223
  readonly options: string[];
204
224
  };
205
225
  /**
206
- * Stage 2: Classified source - knows where addon comes from
207
- */
226
+ * Stage 2: Classified source - knows where addon comes from
227
+ */
208
228
  type AddonSource = {
209
229
  readonly kind: "official";
210
230
  readonly id: string;
@@ -224,27 +244,27 @@ type AddonReference = {
224
244
  readonly source: AddonSource;
225
245
  };
226
246
  /**
227
- * Stage 3: Code loaded - addon definition is always present
228
- */
247
+ * Stage 3: Code loaded - addon definition is always present
248
+ */
229
249
  type LoadedAddon = {
230
250
  readonly reference: AddonReference;
231
251
  readonly addon: AddonDefinition;
232
252
  };
233
253
  /**
234
- * Stage 4: Setup done - has dependency info
235
- */
254
+ * Stage 4: Setup done - has dependency info
255
+ */
236
256
  type PreparedAddon = LoadedAddon & {
237
257
  readonly setupResult: SetupResult;
238
258
  };
239
259
  /**
240
- * Stage 5: User configured - has answers to questions
241
- */
260
+ * Stage 5: User configured - has answers to questions
261
+ */
242
262
  type ConfiguredAddon = PreparedAddon & {
243
263
  readonly answers: OptionValues<any>;
244
264
  };
245
265
  /**
246
- * Stage 6: Execution result
247
- */
266
+ * Stage 6: Execution result
267
+ */
248
268
  type AddonResult = {
249
269
  readonly id: string;
250
270
  readonly status: "success" | {
@@ -260,45 +280,46 @@ type SetupResult = {
260
280
  };
261
281
  type AddonDefinition<Id extends string = string> = Addon<Record<string, Question<any>>, Id>;
262
282
  type MaybePromise<T> = Promise<T> | T;
263
- type Prettify<T> = { [K in keyof T]: T[K] } & unknown;
283
+ type Prettify<T> = { [K in keyof T]: T[K]; } & unknown;
264
284
  type OptionBuilder<T extends OptionDefinition> = {
265
285
  /**
266
- * This type is a bit complex, but in usage, it's quite simple!
267
- *
268
- * The idea is to `add()` options one by one, with the key and the question.
269
- *
270
- * ```ts
271
- * .add('demo', {
272
- * question: 'Do you want to add a demo?',
273
- * type: 'boolean', // string, number, select, multiselect
274
- * default: true,
275
- * // condition: (o) => o.previousOption === 'ok',
276
- * })
277
- * ```
278
- */
279
- add<K extends string, const Q extends Question<T & Record<K, Q>>>(key: K, question: Q): OptionBuilder<T & Record<K, Q>>; /** Finalize all options of your `add-on`. */
286
+ * This type is a bit complex, but in usage, it's quite simple!
287
+ *
288
+ * The idea is to `add()` options one by one, with the key and the question.
289
+ *
290
+ * ```ts
291
+ * .add('demo', {
292
+ * question: 'Do you want to add a demo?',
293
+ * type: 'boolean', // string, number, select, multiselect
294
+ * default: true,
295
+ * // condition: (o) => o.previousOption === 'ok',
296
+ * })
297
+ * ```
298
+ */
299
+ add<K extends string, const Q extends Question<T & Record<K, Q>>>(key: K, question: Q): OptionBuilder<T & Record<K, Q>>;
300
+ /** Finalize all options of your `add-on`. */
280
301
  build(): Prettify<T>;
281
302
  };
282
303
  /**
283
- * Options for an addon.
284
- *
285
- * Will be prompted to the user if there are not answered by args when calling the cli.
286
- *
287
- * ```ts
288
- * const options = defineAddonOptions()
289
- * .add('demo', {
290
- * question: `demo? ${color.optional('(a cool one!)')}`
291
- * type: string | boolean | number | select | multiselect,
292
- * default: true,
293
- * })
294
- * .build();
295
- * ```
296
- *
297
- * To define by args, you can do
298
- * ```sh
299
- * npx sv add <addon>=<option1>:<value1>+<option2>:<value2>
300
- * ```
301
- */
304
+ * Options for an addon.
305
+ *
306
+ * Will be prompted to the user if there are not answered by args when calling the cli.
307
+ *
308
+ * ```ts
309
+ * const options = defineAddonOptions()
310
+ * .add('demo', {
311
+ * question: `demo? ${color.optional('(a cool one!)')}`
312
+ * type: string | boolean | number | select | multiselect,
313
+ * default: true,
314
+ * })
315
+ * .build();
316
+ * ```
317
+ *
318
+ * To define by args, you can do
319
+ * ```sh
320
+ * npx sv add <addon>=<option1>:<value1>+<option2>:<value2>
321
+ * ```
322
+ */
302
323
  declare function defineAddonOptions(): OptionBuilder<{}>;
303
324
  //#endregion
304
325
  //#region src/core/engine.d.ts
@@ -312,25 +333,15 @@ type AddonMap = Record<string, Addon<any, any>>;
312
333
  type AddonById<Addons extends AddonMap, Id extends string> = Extract<Addons[keyof Addons], {
313
334
  id: Id;
314
335
  }>;
315
- type OptionMap<Addons extends AddonMap> = { [Id in Addons[keyof Addons]["id"]]: Partial<OptionValues<AddonById<Addons, Id>["options"]>> };
316
- declare function add<Addons extends AddonMap>({
317
- addons,
318
- cwd,
319
- options,
320
- packageManager
321
- }: InstallOptions<Addons>): Promise<ReturnType<typeof applyAddons>>;
336
+ type OptionMap<Addons extends AddonMap> = { [Id in Addons[keyof Addons]["id"]]: Partial<OptionValues<AddonById<Addons, Id>["options"]>>; };
337
+ declare function add<Addons extends AddonMap>({ addons, cwd, options, packageManager }: InstallOptions<Addons>): Promise<ReturnType<typeof applyAddons>>;
322
338
  type ApplyAddonOptions = {
323
339
  loadedAddons: LoadedAddon[];
324
340
  options: OptionMap<AddonMap>;
325
341
  workspace: Workspace;
326
342
  setupResults: Record<string, SetupResult>;
327
343
  };
328
- declare function applyAddons({
329
- loadedAddons,
330
- workspace,
331
- setupResults,
332
- options
333
- }: ApplyAddonOptions): Promise<{
344
+ declare function applyAddons({ loadedAddons, workspace, setupResults, options }: ApplyAddonOptions): Promise<{
334
345
  filesToFormat: string[];
335
346
  status: Record<string, string[] | "success">;
336
347
  installNeeded: boolean;