Skip to main content

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): TransformFn;
    svelte(cb: (file: {
        ast: AST.Root;
        content: string;
        svelte: typeof index_d_exports$4;
        js: typeof index_d_exports$3;
    }) => void | false, options?: TransformOptions): TransformFn;
    ... 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 | false function that plugs directly into sv.file().

@example
import { transforms } from '@sveltejs/sv-utils';

// use with sv.file() - curried form plugs in directly
sv.file(files.viteConfig, transforms.script(({ ast, js }) => {
  js.vite.addPlugin(ast, { code: 'kitRoutes()' });
}));

// standalone usage / testing
const result = transforms.script(({ ast, js }) => {
  js.imports.addDefault(ast, { as: 'foo', from: 'foo' });
})(fileContent);
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) => void

On what official addons does this addon depend on?

dependsOn
, unsupported: (reason: string) => void

Why is this addon not supported?

unsupported
, isKit: booleanisKit }) => {
if (!isKit: booleanisKit) unsupported: (reason: string) => void

Why is this addon not supported?

unsupported
('Requires SvelteKit');
dependsOn: (name: keyof OfficialAddons) => void

On 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) => void

Cancel 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: FileEdit) => void

Edit 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;'; }); // edit multiple existing files sv: SvApisv.
files: (options: {
    include: string | string[];
    exclude?: string[];
    where?: (content: string) => boolean;
}, edit: FileEditMultiple) => void

Edits matching files in the workspace. The include and exclude patterns are glob patterns relative to the workspace root. For each matching file, the edit callback is called with the file content, and should return the new content (or false to abort editing that file).

Note: always adds excludes for node_modules and dot-prefixed directories

files
(
{ include: string | string[]

Glob patterns to include

include
: 'src/**/*.{js,ts,svelte}',
where?: ((content: string) => boolean) | undefined

Only run edit for files whose current content matches this predicate. Useful for avoiding expensive transforms on unrelated files.

where
: (content: stringcontent) => content: stringcontent.String.includes(searchString: string, position?: number): boolean

Returns true if searchString appears as a substring of the result of converting this object to a String, at one or more positions that are greater than or equal to position; otherwise, returns false.

@param
searchString search string
@param
position If position is undefined, 0 is assumed, so as to search all of the String.
includes
('old-value')
}, (content: stringcontent, path: stringpath) => content: stringcontent.String.replaceAll(searchValue: string | RegExp, replaceValue: string): string (+1 overload)

Replace all instances of a substring in a string, using a regular expression or search string.

@param
searchValue A string to search for.
@param
replaceValue A string containing the text to replace for every successful match of searchValue in this string.
replaceAll
('old-value', 'new-value')
); sv: SvApisv.file: (path: string, edit: FileEdit) => void

Edit 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): TransformFn;
    svelte(cb: (file: {
        ast: AST.Root;
        content: string;
        svelte: typeof index_d_exports$4;
        js: typeof index_d_exports$3;
    }) => void | false, options?: TransformOptions): TransformFn;
    ... 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 | false function that plugs directly into sv.file().

@example
import { transforms } from '@sveltejs/sv-utils';

// use with sv.file() - curried form plugs in directly
sv.file(files.viteConfig, transforms.script(({ ast, js }) => {
  js.vite.addPlugin(ast, { code: 'kitRoutes()' });
}));

// standalone usage / testing
const result = transforms.script(({ ast, js }) => {
  js.imports.addDefault(ast, { as: 'foo', from: 'foo' });
})(fileContent);
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): TransformFn

Transform a Svelte component file.

Return false from the callback to abort.

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";
    language?: "ts" | "js";
}): 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, files, dependency, devDependency, and execute. For file transforms (AST-based editing of scripts, Svelte components, CSS, JSON, etc.) and package manager helpers, 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(options: Options): void (+1 overload)create } from 'sv';

function create(options: Options): void (+1 overload)
@deprecated
use create({ cwd, ...options }) instead.
create
({
cwd: stringcwd: './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[];
    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[];
    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