Skip to main content

sv-utils

@sveltejs/sv-utils is currently experimental. The API may change. Full documentation is not yet available.

@sveltejs/sv-utils provides utilities for parsing, transforming, and generating code in add-ons.

npm install -D @sveltejs/sv-utils

Architecture

The Svelte CLI is split into two packages with a clear boundary:

  • sv = where and when to do it. It owns paths, workspace detection, dependency tracking, and file I/O. The engine orchestrates add-on execution.
  • @sveltejs/sv-utils = what to do to content. It provides parsers, language tooling, and typed transforms. Everything here is pure — no file system, no workspace awareness.

This separation means transforms are testable without a workspace and composable across add-ons.

Transforms

Transforms are typed, parser-aware functions that turn string -> string. Each transform takes file content as its first argument, a callback to manipulate the parsed AST, and returns the updated content. 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.

import { import transformstransforms, js, svelte, css, json } from '@sveltejs/sv-utils';

transforms.script

Transform a JavaScript/TypeScript file. The callback receives the AST and comments.

import { import transformstransforms, js } from '@sveltejs/sv-utils';

sv.file(files.viteConfig, (content: anycontent) => {
	return import transformstransforms.script(content: anycontent, (ast: anyast, comments: anycomments) => {
		js.
namespace index_d_exports$2.imports
export index_d_exports$2.imports
imports
.
imports_d_exports.addDefault(node: js.AstTypes.Program, options: {
    from: string;
    as: string;
}): void
export imports_d_exports.addDefault
addDefault
(ast: anyast, { as: stringas: 'foo', from: stringfrom: 'foo' });
js.
namespace index_d_exports$2.vite
export index_d_exports$2.vite
vite
.
vite_d_exports.addPlugin(ast: js.AstTypes.Program, options: {
    code: string;
    mode?: "append" | "prepend";
}): void
export vite_d_exports.addPlugin
addPlugin
(ast: anyast, { code: stringcode: 'foo()' });
}); });

transforms.svelte

Transform a Svelte component.

import { import transformstransforms, js, svelte } from '@sveltejs/sv-utils';

sv.file(layoutPath, (content: anycontent) => {
	return import transformstransforms.svelte(content: anycontent, (ast: anyast) => {
		svelte.
index_d_exports$3.ensureScript(ast: AST.Root, options?: {
    language?: "ts" | "js";
}): asserts ast is RootWithInstance
export index_d_exports$3.ensureScript
ensureScript
(ast: anyast, { language?: "ts" | "js" | undefinedlanguage });
js.
namespace index_d_exports$2.imports
export index_d_exports$2.imports
imports
.
imports_d_exports.addDefault(node: js.AstTypes.Program, options: {
    from: string;
    as: string;
}): void
export imports_d_exports.addDefault
addDefault
(ast: RootWithInstanceast.instance: AST.Script

The parsed <script> element, if exists

instance
.AST.Script.content: js.AstTypes.Programcontent, { as: stringas: 'Foo', from: stringfrom: './Foo.svelte' });
svelte.
index_d_exports$3.addFragment(ast: AST.Root, content: string, options?: {
    mode?: "append" | "prepend";
}): void
export index_d_exports$3.addFragment
addFragment
(ast: RootWithInstanceast, '<Foo />');
}); });

transforms.css

Transform a CSS file.

import { import transformstransforms, css } from '@sveltejs/sv-utils';

sv.file(files.stylesheet, (content: anycontent) => {
	return import transformstransforms.css(content: anycontent, (ast: anyast) => {
		css.
index_d_exports.addAtRule(node: _CSS.StyleSheetBase, options: {
    name: string;
    params: string;
    append: boolean;
}): _CSS.Atrule
export index_d_exports.addAtRule
addAtRule
(ast: anyast, { name: stringname: 'import', params: stringparams: "'tailwindcss'" });
}); });

transforms.json

Transform a JSON file. Mutate the data object directly.

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

sv.file(files.tsconfig, (content: anycontent) => {
	return import transformstransforms.json(content: anycontent, (data: anydata) => {
		data: anydata.compilerOptions ??= {};
		data: anydata.compilerOptions.strict = true;
	});
});

transforms.yaml / transforms.toml

Same pattern as transforms.json, for YAML and TOML files respectively.

transforms.text

Transform a plain text file (.env, .gitignore, etc.). No parser — string in, string out.

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

sv.file('.env', (content: anycontent) => {
	return import transformstransforms.text(content: anycontent, (data: anydata) => {
		return data: anydata + '\nDATABASE_URL="file:local.db"';
	});
});

Aborting a transform

Return false from any transform callback to abort — the original content is returned unchanged.

import { import transformstransforms, js } from '@sveltejs/sv-utils';

sv.file(files.eslintConfig, (content: anycontent) => {
	return import transformstransforms.script(content: anycontent, (ast: anyast) => {
		const { value: anyvalue: const existing: anyexisting } = js.
namespace index_d_exports$2.exports
export index_d_exports$2.exports
exports
.
exports_d_exports.createDefault<any>(node: js.AstTypes.Program, options: {
    fallback: any;
}): js.exports.ExportDefaultResult<any>
export exports_d_exports.createDefault
createDefault
(ast: anyast, { fallback: anyfallback: myConfig });
if (const existing: anyexisting !== myConfig) { // config already exists, don't touch it return false; } // ... continue modifying ast }); });

Standalone usage & testing

Transforms are just functions — they work without the sv engine. Pass content directly:

import { import transformstransforms, js } from '@sveltejs/sv-utils';

const const result: anyresult = import transformstransforms.script('export default {}', (ast: anyast) => {
	js.
namespace index_d_exports$2.imports
export index_d_exports$2.imports
imports
.
imports_d_exports.addDefault(node: js.AstTypes.Program, options: {
    from: string;
    as: string;
}): void
export imports_d_exports.addDefault
addDefault
(ast: anyast, { as: stringas: 'foo', from: stringfrom: 'foo' });
});

Composability

Since content flows through explicitly, you can mix transforms and raw edits in a single sv.file callback:

sv.file(path, (content) => {


	content: anycontent = transforms.script(content: anycontent, (ast) => {

		js.imports.addDefault(ast: anyast, { as: stringas: 'foo', from: stringfrom: 'foo' });
	});
	content: anycontent = content: anycontent.replace('foo', 'bar');
	return content: anycontent;
});

Add-ons can also export reusable transform functions:

import { import transformstransforms, js, svelte } from '@sveltejs/sv-utils';

// reusable — export from your package
export function function addFooImport(content: any, language: any): anyaddFooImport(content: anycontent, language: anylanguage) {
	return import transformstransforms.svelte(content: anycontent, (ast: anyast) => {
		svelte.
index_d_exports$3.ensureScript(ast: AST.Root, options?: {
    language?: "ts" | "js";
}): asserts ast is RootWithInstance
export index_d_exports$3.ensureScript
ensureScript
(ast: anyast, { language?: "ts" | "js" | undefinedlanguage });
js.
namespace index_d_exports$2.imports
export index_d_exports$2.imports
imports
.
imports_d_exports.addDefault(node: js.AstTypes.Program, options: {
    from: string;
    as: string;
}): void
export imports_d_exports.addDefault
addDefault
(ast: RootWithInstanceast.instance: AST.Script

The parsed <script> element, if exists

instance
.AST.Script.content: js.AstTypes.Programcontent, { as: stringas: 'Foo', from: stringfrom: './Foo.svelte' });
}); }

Parsers (low-level)

For cases where transforms don't fit (e.g., conditional parsing, error handling around the parser), the parse namespace is still available:

import { 
const parse: {
    css: (source: string) => {
        ast: Omit<_CSS.StyleSheetBase, "attributes" | "content">;
    } & ParseBase;
    html: (source: string) => {
        ast: AST.Fragment;
    } & ParseBase;
    json: (source: string) => {
        data: any;
    } & ParseBase;
    script: (source: string) => {
        ast: Program;
        comments: Comments;
    } & ParseBase;
    svelte: (source: string) => {
        ast: AST.Root;
    } & ParseBase;
    toml: (source: string) => {
        data: TomlTable;
    } & ParseBase;
    yaml: (source: string) => {
        data: ReturnType<(content: string) => ReturnType<any>>;
    } & ParseBase;
}

Will help you parse code into an ast from all supported languages. Then manipulate the ast as you want, and finally generateCode() to write it back to the file.

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

const { ast, generateCode } = parse.css('body { color: red; }');
const { ast, generateCode } = parse.html('<div>Hello, world!</div>');
const { ast, generateCode } = parse.json('{ "name": "John", "age": 30 }');
const { ast, generateCode } = parse.script('function add(a, b) { return a + b; }');
const { ast, generateCode } = parse.svelte('<div>Hello, world!</div>');
const { ast, generateCode } = parse.toml('name = "John"');
const { ast, generateCode } = parse.yaml('name: John');
parse
} from '@sveltejs/sv-utils';
const { const ast: Programast, const generateCode: () => string

Generate the code after manipulating the ast.

import { svelte } from 'sv/core';
const { ast, generateCode } = parse.svelte(content);

svelte.addFragment(ast, '<p>Hello World</p>');

const code = generateCode();
generateCode
} =
const parse: {
    css: (source: string) => {
        ast: Omit<_CSS.StyleSheetBase, "attributes" | "content">;
    } & ParseBase;
    html: (source: string) => {
        ast: AST.Fragment;
    } & ParseBase;
    json: (source: string) => {
        data: any;
    } & ParseBase;
    script: (source: string) => {
        ast: Program;
        comments: Comments;
    } & ParseBase;
    svelte: (source: string) => {
        ast: AST.Root;
    } & ParseBase;
    toml: (source: string) => {
        data: TomlTable;
    } & ParseBase;
    yaml: (source: string) => {
        data: ReturnType<(content: string) => ReturnType<any>>;
    } & ParseBase;
}

Will help you parse code into an ast from all supported languages. Then manipulate the ast as you want, and finally generateCode() to write it back to the file.

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

const { ast, generateCode } = parse.css('body { color: red; }');
const { ast, generateCode } = parse.html('<div>Hello, world!</div>');
const { ast, generateCode } = parse.json('{ "name": "John", "age": 30 }');
const { ast, generateCode } = parse.script('function add(a, b) { return a + b; }');
const { ast, generateCode } = parse.svelte('<div>Hello, world!</div>');
const { ast, generateCode } = parse.toml('name = "John"');
const { ast, generateCode } = parse.yaml('name: John');
parse
.
script: (source: string) => {
    ast: Program;
    comments: Comments;
} & ParseBase
script
(content);
const { const ast: AST.Rootast, const generateCode: () => string

Generate the code after manipulating the ast.

import { svelte } from 'sv/core';
const { ast, generateCode } = parse.svelte(content);

svelte.addFragment(ast, '<p>Hello World</p>');

const code = generateCode();
generateCode
} =
const parse: {
    css: (source: string) => {
        ast: Omit<_CSS.StyleSheetBase, "attributes" | "content">;
    } & ParseBase;
    html: (source: string) => {
        ast: AST.Fragment;
    } & ParseBase;
    json: (source: string) => {
        data: any;
    } & ParseBase;
    script: (source: string) => {
        ast: Program;
        comments: Comments;
    } & ParseBase;
    svelte: (source: string) => {
        ast: AST.Root;
    } & ParseBase;
    toml: (source: string) => {
        data: TomlTable;
    } & ParseBase;
    yaml: (source: string) => {
        data: ReturnType<(content: string) => ReturnType<any>>;
    } & ParseBase;
}

Will help you parse code into an ast from all supported languages. Then manipulate the ast as you want, and finally generateCode() to write it back to the file.

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

const { ast, generateCode } = parse.css('body { color: red; }');
const { ast, generateCode } = parse.html('<div>Hello, world!</div>');
const { ast, generateCode } = parse.json('{ "name": "John", "age": 30 }');
const { ast, generateCode } = parse.script('function add(a, b) { return a + b; }');
const { ast, generateCode } = parse.svelte('<div>Hello, world!</div>');
const { ast, generateCode } = parse.toml('name = "John"');
const { ast, generateCode } = parse.yaml('name: John');
parse
.
svelte: (source: string) => {
    ast: AST.Root;
} & ParseBase
svelte
(content);
const { const ast: Omit<_CSS.StyleSheetBase, "attributes" | "content">ast, const generateCode: () => string

Generate the code after manipulating the ast.

import { svelte } from 'sv/core';
const { ast, generateCode } = parse.svelte(content);

svelte.addFragment(ast, '<p>Hello World</p>');

const code = generateCode();
generateCode
} =
const parse: {
    css: (source: string) => {
        ast: Omit<_CSS.StyleSheetBase, "attributes" | "content">;
    } & ParseBase;
    html: (source: string) => {
        ast: AST.Fragment;
    } & ParseBase;
    json: (source: string) => {
        data: any;
    } & ParseBase;
    script: (source: string) => {
        ast: Program;
        comments: Comments;
    } & ParseBase;
    svelte: (source: string) => {
        ast: AST.Root;
    } & ParseBase;
    toml: (source: string) => {
        data: TomlTable;
    } & ParseBase;
    yaml: (source: string) => {
        data: ReturnType<(content: string) => ReturnType<any>>;
    } & ParseBase;
}

Will help you parse code into an ast from all supported languages. Then manipulate the ast as you want, and finally generateCode() to write it back to the file.

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

const { ast, generateCode } = parse.css('body { color: red; }');
const { ast, generateCode } = parse.html('<div>Hello, world!</div>');
const { ast, generateCode } = parse.json('{ "name": "John", "age": 30 }');
const { ast, generateCode } = parse.script('function add(a, b) { return a + b; }');
const { ast, generateCode } = parse.svelte('<div>Hello, world!</div>');
const { ast, generateCode } = parse.toml('name = "John"');
const { ast, generateCode } = parse.yaml('name: John');
parse
.
css: (source: string) => {
    ast: Omit<_CSS.StyleSheetBase, "attributes" | "content">;
} & ParseBase
css
(content);
const { const data: anydata, const generateCode: () => string

Generate the code after manipulating the ast.

import { svelte } from 'sv/core';
const { ast, generateCode } = parse.svelte(content);

svelte.addFragment(ast, '<p>Hello World</p>');

const code = generateCode();
generateCode
} =
const parse: {
    css: (source: string) => {
        ast: Omit<_CSS.StyleSheetBase, "attributes" | "content">;
    } & ParseBase;
    html: (source: string) => {
        ast: AST.Fragment;
    } & ParseBase;
    json: (source: string) => {
        data: any;
    } & ParseBase;
    script: (source: string) => {
        ast: Program;
        comments: Comments;
    } & ParseBase;
    svelte: (source: string) => {
        ast: AST.Root;
    } & ParseBase;
    toml: (source: string) => {
        data: TomlTable;
    } & ParseBase;
    yaml: (source: string) => {
        data: ReturnType<(content: string) => ReturnType<any>>;
    } & ParseBase;
}

Will help you parse code into an ast from all supported languages. Then manipulate the ast as you want, and finally generateCode() to write it back to the file.

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

const { ast, generateCode } = parse.css('body { color: red; }');
const { ast, generateCode } = parse.html('<div>Hello, world!</div>');
const { ast, generateCode } = parse.json('{ "name": "John", "age": 30 }');
const { ast, generateCode } = parse.script('function add(a, b) { return a + b; }');
const { ast, generateCode } = parse.svelte('<div>Hello, world!</div>');
const { ast, generateCode } = parse.toml('name = "John"');
const { ast, generateCode } = parse.yaml('name: John');
parse
.
json: (source: string) => {
    data: any;
} & ParseBase
json
(content);
const { const data: anydata, const generateCode: () => string

Generate the code after manipulating the ast.

import { svelte } from 'sv/core';
const { ast, generateCode } = parse.svelte(content);

svelte.addFragment(ast, '<p>Hello World</p>');

const code = generateCode();
generateCode
} =
const parse: {
    css: (source: string) => {
        ast: Omit<_CSS.StyleSheetBase, "attributes" | "content">;
    } & ParseBase;
    html: (source: string) => {
        ast: AST.Fragment;
    } & ParseBase;
    json: (source: string) => {
        data: any;
    } & ParseBase;
    script: (source: string) => {
        ast: Program;
        comments: Comments;
    } & ParseBase;
    svelte: (source: string) => {
        ast: AST.Root;
    } & ParseBase;
    toml: (source: string) => {
        data: TomlTable;
    } & ParseBase;
    yaml: (source: string) => {
        data: ReturnType<(content: string) => ReturnType<any>>;
    } & ParseBase;
}

Will help you parse code into an ast from all supported languages. Then manipulate the ast as you want, and finally generateCode() to write it back to the file.

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

const { ast, generateCode } = parse.css('body { color: red; }');
const { ast, generateCode } = parse.html('<div>Hello, world!</div>');
const { ast, generateCode } = parse.json('{ "name": "John", "age": 30 }');
const { ast, generateCode } = parse.script('function add(a, b) { return a + b; }');
const { ast, generateCode } = parse.svelte('<div>Hello, world!</div>');
const { ast, generateCode } = parse.toml('name = "John"');
const { ast, generateCode } = parse.yaml('name: John');
parse
.
yaml: (source: string) => {
    data: ReturnType<(content: string) => ReturnType<any>>;
} & ParseBase
yaml
(content);
const { const data: TomlTabledata, const generateCode: () => string

Generate the code after manipulating the ast.

import { svelte } from 'sv/core';
const { ast, generateCode } = parse.svelte(content);

svelte.addFragment(ast, '<p>Hello World</p>');

const code = generateCode();
generateCode
} =
const parse: {
    css: (source: string) => {
        ast: Omit<_CSS.StyleSheetBase, "attributes" | "content">;
    } & ParseBase;
    html: (source: string) => {
        ast: AST.Fragment;
    } & ParseBase;
    json: (source: string) => {
        data: any;
    } & ParseBase;
    script: (source: string) => {
        ast: Program;
        comments: Comments;
    } & ParseBase;
    svelte: (source: string) => {
        ast: AST.Root;
    } & ParseBase;
    toml: (source: string) => {
        data: TomlTable;
    } & ParseBase;
    yaml: (source: string) => {
        data: ReturnType<(content: string) => ReturnType<any>>;
    } & ParseBase;
}

Will help you parse code into an ast from all supported languages. Then manipulate the ast as you want, and finally generateCode() to write it back to the file.

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

const { ast, generateCode } = parse.css('body { color: red; }');
const { ast, generateCode } = parse.html('<div>Hello, world!</div>');
const { ast, generateCode } = parse.json('{ "name": "John", "age": 30 }');
const { ast, generateCode } = parse.script('function add(a, b) { return a + b; }');
const { ast, generateCode } = parse.svelte('<div>Hello, world!</div>');
const { ast, generateCode } = parse.toml('name = "John"');
const { ast, generateCode } = parse.yaml('name: John');
parse
.
toml: (source: string) => {
    data: TomlTable;
} & ParseBase
toml
(content);
const { const ast: AST.Fragmentast, const generateCode: () => string

Generate the code after manipulating the ast.

import { svelte } from 'sv/core';
const { ast, generateCode } = parse.svelte(content);

svelte.addFragment(ast, '<p>Hello World</p>');

const code = generateCode();
generateCode
} =
const parse: {
    css: (source: string) => {
        ast: Omit<_CSS.StyleSheetBase, "attributes" | "content">;
    } & ParseBase;
    html: (source: string) => {
        ast: AST.Fragment;
    } & ParseBase;
    json: (source: string) => {
        data: any;
    } & ParseBase;
    script: (source: string) => {
        ast: Program;
        comments: Comments;
    } & ParseBase;
    svelte: (source: string) => {
        ast: AST.Root;
    } & ParseBase;
    toml: (source: string) => {
        data: TomlTable;
    } & ParseBase;
    yaml: (source: string) => {
        data: ReturnType<(content: string) => ReturnType<any>>;
    } & ParseBase;
}

Will help you parse code into an ast from all supported languages. Then manipulate the ast as you want, and finally generateCode() to write it back to the file.

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

const { ast, generateCode } = parse.css('body { color: red; }');
const { ast, generateCode } = parse.html('<div>Hello, world!</div>');
const { ast, generateCode } = parse.json('{ "name": "John", "age": 30 }');
const { ast, generateCode } = parse.script('function add(a, b) { return a + b; }');
const { ast, generateCode } = parse.svelte('<div>Hello, world!</div>');
const { ast, generateCode } = parse.toml('name = "John"');
const { ast, generateCode } = parse.yaml('name: John');
parse
.
html: (source: string) => {
    ast: AST.Fragment;
} & ParseBase
html
(content);

Language tooling

Namespaced helpers for AST manipulation:

  • js.* — imports, exports, objects, arrays, variables, functions, vite config helpers, SvelteKit helpers
  • css.* — rules, declarations, at-rules, imports
  • svelte.* — ensureScript, addSlot, addFragment
  • json.* — arrayUpsert, packageScriptsUpsert
  • html.* — attribute manipulation
  • text.* — upsert lines in flat files (.env, .gitignore)

Edit this page on GitHub llms.txt

previous next