sv
sv exposes a programmatic API for creating projects and running add-ons.
defineAddon
Creates an add-on definition. See create your own for a full guide.
import { const transforms: {
script(cb: (file: {
ast: Program;
comments: Comments;
content: string;
js: typeof index_d_exports$3;
}) => void | false, options?: TransformOptions): (content: string) => string;
svelte(cb: (file: {
ast: AST.Root;
content: string;
svelte: typeof index_d_exports$4;
js: typeof index_d_exports$3;
}) => void | false, options?: TransformOptions): (content: string) => string;
... 6 more ...;
text(cb: (file: {
content: string;
text: typeof text_d_exports;
}) => string | false): TransformFn;
}
File transform primitives that know their format.
sv-utils = what to do to content, sv = where and when to do it.
Each transform wraps: parse -> callback({ast/data, utils}) -> generateCode().
The parser choice is baked into the transform type - you can't accidentally
parse a vite config as svelte because you never call a parser yourself.
Transforms are curried: call with the callback to get a (content: string) => string
function that plugs directly into sv.file().
transforms } from '@sveltejs/sv-utils';
import { function defineAddon<const Id extends string, Args extends OptionDefinition>(config: Addon<Args, Id>): Addon<Args, Id>The entry point for your addon, It will hold every thing! (options, setup, run, nextSteps, ...)
defineAddon, function defineAddonOptions(): OptionBuilder<{}>Options for an addon.
Will be prompted to the user if there are not answered by args when calling the cli.
const options = defineAddonOptions()
.add('demo', {
question: `demo? ${color.optional('(a cool one!)')}`
type: string | boolean | number | select | multiselect,
default: true,
})
.build();
To define by args, you can do
npx sv add <addon>=<option1>:<value1>+<option2>:<value2>
defineAddonOptions } from 'sv';
export default defineAddon<"my-addon", {}>(config: Addon<{}, "my-addon">): Addon<{}, "my-addon">The entry point for your addon, It will hold every thing! (options, setup, run, nextSteps, ...)
defineAddon({
id: "my-addon"id: 'my-addon',
options: {}options: function defineAddonOptions(): OptionBuilder<{}>Options for an addon.
Will be prompted to the user if there are not answered by args when calling the cli.
const options = defineAddonOptions()
.add('demo', {
question: `demo? ${color.optional('(a cool one!)')}`
type: string | boolean | number | select | multiselect,
default: true,
})
.build();
To define by args, you can do
npx sv add <addon>=<option1>:<value1>+<option2>:<value2>
defineAddonOptions().function build(): {}build(),
// called before run — declare dependencies and environment requirements
setup?: ((workspace: Workspace & {
dependsOn: (name: keyof OfficialAddons) => void;
unsupported: (reason: string) => void;
runsAfter: (name: keyof OfficialAddons) => void;
}) => MaybePromise<...>) | undefined
setup: ({ dependsOn: (name: keyof OfficialAddons) => voidOn what official addons does this addon depend on?
dependsOn, unsupported: (reason: string) => voidWhy is this addon not supported?
unsupported, isKit: booleanisKit }) => {
if (!isKit: booleanisKit) unsupported: (reason: string) => voidWhy is this addon not supported?
unsupported('Requires SvelteKit');
dependsOn: (name: keyof OfficialAddons) => voidOn what official addons does this addon depend on?
dependsOn('eslint');
},
// the actual work — add files, edit files, declare dependencies
run: (workspace: Workspace & {
options: OptionValues<{}>;
sv: SvApi;
cancel: (reason: string) => void;
}) => MaybePromise<void>
run: ({ sv: SvApisv, options: OptionValues<{}>Add-on options
options, cancel: (reason: string) => voidCancel the addon at any time!
cancel }) => {
// add a dependency
sv: SvApisv.devDependency: (pkg: string, version: string) => voiddevDependency('my-lib', '^1.0.0');
// create or edit files using transforms from @sveltejs/sv-utils
sv: SvApisv.file: (path: string, edit: (content: string) => string | false) => voidEdit a file in the workspace. (will create it if it doesn't exist)
Return false from the callback to abort - the original content is returned unchanged.
file('src/lib/foo.ts', (content: stringcontent) => {
return 'export const foo = true;';
});
sv: SvApisv.file: (path: string, edit: (content: string) => string | false) => voidEdit a file in the workspace. (will create it if it doesn't exist)
Return false from the callback to abort - the original content is returned unchanged.
file(
'src/routes/+page.svelte',
const transforms: {
script(cb: (file: {
ast: Program;
comments: Comments;
content: string;
js: typeof index_d_exports$3;
}) => void | false, options?: TransformOptions): (content: string) => string;
svelte(cb: (file: {
ast: AST.Root;
content: string;
svelte: typeof index_d_exports$4;
js: typeof index_d_exports$3;
}) => void | false, options?: TransformOptions): (content: string) => string;
... 6 more ...;
text(cb: (file: {
content: string;
text: typeof text_d_exports;
}) => string | false): TransformFn;
}
File transform primitives that know their format.
sv-utils = what to do to content, sv = where and when to do it.
Each transform wraps: parse -> callback({ast/data, utils}) -> generateCode().
The parser choice is baked into the transform type - you can't accidentally
parse a vite config as svelte because you never call a parser yourself.
Transforms are curried: call with the callback to get a (content: string) => string
function that plugs directly into sv.file().
transforms.function svelte(cb: (file: {
ast: AST.Root;
content: string;
svelte: typeof index_d_exports$4;
js: typeof index_d_exports$3;
}) => void | false, options?: TransformOptions): (content: string) => string
Transform a Svelte component file.
Return false from the callback to abort - the original content is returned unchanged.
svelte(({ ast: AST.Rootast, svelte: typeof index_d_exports$4svelte }) => {
svelte: typeof index_d_exports$4svelte.index_d_exports$4.addFragment(ast: AST.Root, content: string, options?: {
mode?: "append" | "prepend";
}): void
export index_d_exports$4.addFragment
addFragment(ast: AST.Rootast, '<p>Hello!</p>');
})
);
// cancel at any point if something is wrong
// cancel('reason');
},
// displayed after the add-on runs
nextSteps?: ((workspace: Workspace & {
options: OptionValues<{}>;
}) => string[]) | undefined
nextSteps: ({ options: OptionValues<{}>options }) => ['Run `npm run dev` to get started']
});The sv object in run provides file, dependency, devDependency, execute, and pnpmBuildDependency. For file transforms (AST-based editing of scripts, Svelte components, CSS, JSON, etc.), see @sveltejs/sv-utils.
defineAddonOptions
Builder for add-on options. Chained with .add() and finalized with .build().
import { function defineAddonOptions(): OptionBuilder<{}>Options for an addon.
Will be prompted to the user if there are not answered by args when calling the cli.
const options = defineAddonOptions()
.add('demo', {
question: `demo? ${color.optional('(a cool one!)')}`
type: string | boolean | number | select | multiselect,
default: true,
})
.build();
To define by args, you can do
npx sv add <addon>=<option1>:<value1>+<option2>:<value2>
defineAddonOptions } from 'sv';
const const options: {
database: {
readonly question: "Which database?";
readonly type: "select";
readonly default: "postgresql";
readonly options: [{
readonly value: "postgresql";
}, {
readonly value: "mysql";
}, {
readonly value: "sqlite";
}];
};
docker: {
readonly question: "Add a docker-compose file?";
readonly type: "boolean";
readonly default: false;
readonly condition: (opts: OptionValues<Record<"database", {
readonly question: "Which database?";
readonly type: "select";
readonly default: "postgresql";
readonly options: [{
readonly value: "postgresql";
}, {
readonly value: "mysql";
}, {
readonly value: "sqlite";
}];
}> & Record<...>>) => boolean;
};
}
options = function defineAddonOptions(): OptionBuilder<{}>Options for an addon.
Will be prompted to the user if there are not answered by args when calling the cli.
const options = defineAddonOptions()
.add('demo', {
question: `demo? ${color.optional('(a cool one!)')}`
type: string | boolean | number | select | multiselect,
default: true,
})
.build();
To define by args, you can do
npx sv add <addon>=<option1>:<value1>+<option2>:<value2>
defineAddonOptions()
.add<"database", {
readonly question: "Which database?";
readonly type: "select";
readonly default: "postgresql";
readonly options: [{
readonly value: "postgresql";
}, {
readonly value: "mysql";
}, {
readonly value: "sqlite";
}];
}>(key: "database", question: {
readonly question: "Which database?";
readonly type: "select";
readonly default: "postgresql";
readonly options: [{
readonly value: "postgresql";
}, {
readonly value: "mysql";
}, {
readonly value: "sqlite";
}];
}): OptionBuilder<Record<"database", {
readonly question: "Which database?";
readonly type: "select";
readonly default: "postgresql";
readonly options: [{
readonly value: "postgresql";
}, {
readonly value: "mysql";
}, {
readonly value: "sqlite";
}];
}>>
This type is a bit complex, but in usage, it's quite simple!
The idea is to add() options one by one, with the key and the question.
.add('demo', {
question: 'Do you want to add a demo?',
type: 'boolean', // string, number, select, multiselect
default: true,
// condition: (o) => o.previousOption === 'ok',
})
add('database', {
question: "Which database?"question: 'Which database?',
type: "select"type: 'select',
default: "postgresql"default: 'postgresql',
options: [{
readonly value: "postgresql";
}, {
readonly value: "mysql";
}, {
readonly value: "sqlite";
}]
options: [
{ value: "postgresql"value: 'postgresql' },
{ value: "mysql"value: 'mysql' },
{ value: "sqlite"value: 'sqlite' }
]
})
.add<"docker", {
readonly question: "Add a docker-compose file?";
readonly type: "boolean";
readonly default: false;
readonly condition: (opts: OptionValues<Record<"database", {
readonly question: "Which database?";
readonly type: "select";
readonly default: "postgresql";
readonly options: [{
readonly value: "postgresql";
}, {
readonly value: "mysql";
}, {
readonly value: "sqlite";
}];
}> & Record<"docker", any>>) => boolean;
}>(key: "docker", question: {
readonly question: "Add a docker-compose file?";
readonly type: "boolean";
readonly default: false;
readonly condition: (opts: OptionValues<Record<"database", {
readonly question: "Which database?";
readonly type: "select";
readonly default: "postgresql";
readonly options: [{
readonly value: "postgresql";
}, {
readonly value: "mysql";
}, {
readonly value: "sqlite";
}];
}> & Record<"docker", any>>) => boolean;
}): OptionBuilder<...>
This type is a bit complex, but in usage, it's quite simple!
The idea is to add() options one by one, with the key and the question.
.add('demo', {
question: 'Do you want to add a demo?',
type: 'boolean', // string, number, select, multiselect
default: true,
// condition: (o) => o.previousOption === 'ok',
})
add('docker', {
question: "Add a docker-compose file?"question: 'Add a docker-compose file?',
type: "boolean"type: 'boolean',
default: falsedefault: false,
// only ask when database is not sqlite
condition: (opts: OptionValues<Record<"database", {
readonly question: "Which database?";
readonly type: "select";
readonly default: "postgresql";
readonly options: [{
readonly value: "postgresql";
}, {
readonly value: "mysql";
}, {
readonly value: "sqlite";
}];
}> & Record<"docker", any>>) => boolean
condition: (opts: OptionValues<Record<"database", {
readonly question: "Which database?";
readonly type: "select";
readonly default: "postgresql";
readonly options: [{
readonly value: "postgresql";
}, {
readonly value: "mysql";
}, {
readonly value: "sqlite";
}];
}> & Record<"docker", any>>
opts) => opts: OptionValues<Record<"database", {
readonly question: "Which database?";
readonly type: "select";
readonly default: "postgresql";
readonly options: [{
readonly value: "postgresql";
}, {
readonly value: "mysql";
}, {
readonly value: "sqlite";
}];
}> & Record<"docker", any>>
opts.database: "postgresql" | "mysql" | "sqlite"database !== 'sqlite'
})
.function build(): {
database: {
readonly question: "Which database?";
readonly type: "select";
readonly default: "postgresql";
readonly options: [{
readonly value: "postgresql";
}, {
readonly value: "mysql";
}, {
readonly value: "sqlite";
}];
};
docker: {
readonly question: "Add a docker-compose file?";
readonly type: "boolean";
readonly default: false;
readonly condition: (opts: OptionValues<Record<"database", {
readonly question: "Which database?";
readonly type: "select";
readonly default: "postgresql";
readonly options: [{
readonly value: "postgresql";
}, {
readonly value: "mysql";
}, {
readonly value: "sqlite";
}];
}> & Record<...>>) => boolean;
};
}
build();Options are asked in order. The condition callback receives the answers collected so far — return false to skip the question (its value will be undefined).
create
Programmatically create a new Svelte project.
import { function create(cwd: string, options: Options): voidcreate } from 'sv';
function create(cwd: string, options: Options): voidcreate('./my-app', {
name: stringname: 'my-app',
template: "minimal" | "demo" | "library" | "addon" | "svelte"template: 'minimal',
types: "typescript" | "checkjs" | "none"types: 'typescript'
});add
Programmatically run add-ons against an existing project.
import { function add<Addons extends AddonMap>({ addons, cwd, options, packageManager }: InstallOptions<Addons>): Promise<ReturnType<({ loadedAddons, workspace, setupResults, options }: ApplyAddonOptions) => Promise<{
filesToFormat: string[];
pnpmBuildDependencies: string[];
status: Record<string, string[] | "success">;
}>>>
add, const officialAddons: OfficialAddonsofficialAddons } from 'sv';
await add<{
prettier: Addon<any, string>;
}>({ addons, cwd, options, packageManager }: InstallOptions<{
prettier: Addon<any, string>;
}>): Promise<ReturnType<({ loadedAddons, workspace, setupResults, options }: ApplyAddonOptions) => Promise<{
filesToFormat: string[];
pnpmBuildDependencies: string[];
status: Record<string, string[] | "success">;
}>>>
add({
cwd: stringcwd: './my-app',
addons: {
prettier: Addon<any, string>;
}
addons: { prettier: Addon<any, string>prettier: const officialAddons: OfficialAddonsofficialAddons.prettier: Addon<any, string>prettier },
options: OptionMap<{
prettier: Addon<any, string>;
}>
options: { prettier: {}prettier: {} },
packageManager?: AgentName | undefinedpackageManager: 'npm'
});Edit this page on GitHub llms.txt