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. 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, import jsjs, import sveltesvelte, import csscss, import jsonjson } from '@sveltejs/sv-utils';

transforms.script

Transform a JavaScript/TypeScript file. The callback receives the AST, comments, and a context with language.

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

const const addVitePlugin: anyaddVitePlugin = import transformstransforms.script((ast: anyast, comments: anycomments, { language: anylanguage }) => {
	import jsjs.imports.addDefault(ast: anyast, { as: stringas: 'foo', from: stringfrom: 'foo' });
	import jsjs.vite.addPlugin(ast: anyast, { code: stringcode: 'foo()' });
});

transforms.svelte

Transform a Svelte component. The engine injects language automatically via the context.

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

const const addFooComponent: anyaddFooComponent = import transformstransforms.svelte((ast: anyast, { language: anylanguage }) => {
	import sveltesvelte.ensureScript(ast: anyast, { language: anylanguage });
	import jsjs.imports.addDefault(ast: anyast.instance.content, { as: stringas: 'Foo', from: stringfrom: './Foo.svelte' });
	import sveltesvelte.addFragment(ast: anyast, '<Foo />');
});

transforms.css

Transform a CSS file. The callback receives the AST and a context with language.

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

const const addTailwind: anyaddTailwind = import transformstransforms.css((ast: anyast, { language: anylanguage }) => {
	import csscss.addAtRule(ast: anyast, { name: stringname: 'import', params: stringparams: "'tailwindcss'" });
});

transforms.json

Transform a JSON file. Mutate the data object directly. The callback also receives a context with language.

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

const const enableStrict: anyenableStrict = import transformstransforms.json((data: anydata, { language: anylanguage }) => {
	data: anydata.compilerOptions ??= {};
	data: anydata.compilerOptions.strict = true;
});

transforms.yaml / transforms.toml

Same pattern as transforms.json, for YAML and TOML files respectively. All callbacks receive a context with language.

transforms.text

Transform a plain text file (.env, .gitignore, etc.). No parser — string in, string out. The callback also receives a context with language.

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

const const addDbUrl: anyaddDbUrl = import transformstransforms.text((content: anycontent, { language: anylanguage }) => {
	return content: anycontent + '\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, import jsjs } from '@sveltejs/sv-utils';

const const myConfig: "{}"myConfig = '{}';
const const setupEslint: anysetupEslint = import transformstransforms.script((ast: anyast) => {
	const { value: const existing: anyexisting } = import jsjs.exports.createDefault(ast: anyast, { fallback: stringfallback: const myConfig: "{}"myConfig });
	if (const existing: anyexisting !== const myConfig: "{}"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, with an optional context:

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

const const addPlugin: anyaddPlugin = import transformstransforms.script((ast: anyast) => {
	import jsjs.imports.addDefault(ast: anyast, { as: stringas: 'foo', from: stringfrom: 'foo' });
});

// use standalone — pass content and context directly
const const result: anyresult = const addPlugin: anyaddPlugin('export default {}', { language: stringlanguage: 'ts' });

Composability

Add-ons can export reusable transforms that other add-ons consume:

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

// reusable transform — export from your package
export const const addFooImport: anyaddFooImport = import transformstransforms.svelte((ast: anyast, { language: anylanguage }) => {
	import sveltesvelte.ensureScript(ast: anyast, { language: anylanguage });
	import jsjs.imports.addDefault(ast: anyast.instance.content, { 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 { import parseparse } from '@sveltejs/sv-utils';

const { const ast: anyast, const generateCode: anygenerateCode } = import parseparse.script(content);
const { const ast: anyast, const generateCode: anygenerateCode } = import parseparse.svelte(content);
const { const ast: anyast, const generateCode: anygenerateCode } = import parseparse.css(content);
const { const data: anydata, const generateCode: anygenerateCode } = import parseparse.json(content);
const { const data: anydata, const generateCode: anygenerateCode } = import parseparse.yaml(content);
const { const data: anydata, const generateCode: anygenerateCode } = import parseparse.toml(content);
const { const ast: anyast, const generateCode: anygenerateCode } = import parseparse.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