Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
25d0bbf
chore: update `esrap`
manuel3108 Jun 28, 2025
c5aa975
Merge remote-tracking branch 'origin/main' into chore/esrap-2
manuel3108 Sep 7, 2025
9394c80
use esrap pkg.pr.new
manuel3108 Oct 26, 2025
79f262e
fix `svelte-kit` adapter addon
manuel3108 Oct 26, 2025
7c0c0d2
remove useless comment
manuel3108 Oct 26, 2025
f41da14
fix eslint
manuel3108 Oct 26, 2025
7307cc4
fix eslint
manuel3108 Oct 26, 2025
6df65fc
add changed tests
manuel3108 Oct 26, 2025
ae78455
thats ok too
manuel3108 Oct 26, 2025
23d569d
Merge branch 'main' into chore/esrap-2
manuel3108 Oct 26, 2025
1982ac4
those are ok as well
manuel3108 Oct 26, 2025
62444cc
fix last failing test
manuel3108 Oct 26, 2025
e4af8c7
implement proper svelte file processing
manuel3108 Oct 26, 2025
ccf1ab3
fix paraglide
manuel3108 Oct 26, 2025
9ce405c
Merge branch 'main' into chore/svelte-compiler-2
manuel3108 Nov 22, 2025
f243210
fix lockfile
manuel3108 Nov 22, 2025
7f0bf71
update deps
manuel3108 Nov 22, 2025
68b1c83
Merge branch 'main' into chore/svelte-compiler-2
manuel3108 Nov 24, 2025
d871736
Merge branch 'main' into chore/esrap-2
manuel3108 Nov 26, 2025
0b55155
update esrap
manuel3108 Nov 26, 2025
54685d8
adapt to new api
manuel3108 Nov 30, 2025
0e56b56
improvements
manuel3108 Nov 30, 2025
a89a0e9
cleanup
manuel3108 Nov 30, 2025
4efbc25
remove useless comment
manuel3108 Nov 30, 2025
15d3400
Update packages/core/tooling/index.ts
manuel3108 Nov 30, 2025
c3ca656
Merge branch 'chore/esrap-2' of https://github.com/sveltejs/cli into …
manuel3108 Nov 30, 2025
eb00469
Merge branch 'chore/esrap-2' into chore/svelte-compiler-2
manuel3108 Nov 30, 2025
18debe7
fix all type errors
manuel3108 Nov 30, 2025
8e08462
fix deb
manuel3108 Nov 30, 2025
07a56fa
fix svelte version
manuel3108 Nov 30, 2025
a474b28
update test
manuel3108 Nov 30, 2025
cd408ad
fix more places
manuel3108 Nov 30, 2025
b7a0d99
fix todos
manuel3108 Nov 30, 2025
ad3ab8e
remove now useless workarounds
manuel3108 Nov 30, 2025
dd18d5b
fix
manuel3108 Nov 30, 2025
6a4ceb1
fix mdsvex
manuel3108 Nov 30, 2025
52b2c88
fix failing test?
manuel3108 Nov 30, 2025
eff4819
add tests for new svelte utils
manuel3108 Nov 30, 2025
18a7266
fix formatting
manuel3108 Nov 30, 2025
741c01c
make lint happy
manuel3108 Nov 30, 2025
9631d53
Merge branch 'main' into chore/svelte-compiler-2
manuel3108 Dec 5, 2025
887ab4c
re-add guessQuoteStyle
manuel3108 Dec 5, 2025
bc06007
fix wrong snapshot
manuel3108 Dec 5, 2025
e668c3e
fix last test
manuel3108 Dec 5, 2025
d86ec97
keep replaceAll for script ending
jycouet Dec 5, 2025
1de46a1
new format
jycouet Dec 5, 2025
42e8989
with resolve
jycouet Dec 5, 2025
9235e8b
update snap
jycouet Dec 5, 2025
b0de335
add the ts thingy on no file
jycouet Dec 5, 2025
bdea815
the implem & tests
jycouet Dec 5, 2025
214cbed
update some add-on
jycouet Dec 5, 2025
7ecdfc9
nicer?
jycouet Dec 5, 2025
b540ab5
like before
jycouet Dec 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions community-addon-template/src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { defineAddon, defineAddonOptions } from '@sveltejs/cli-core';
import { imports } from '@sveltejs/cli-core/js';
import * as svelte from '@sveltejs/cli-core/svelte';
import { parseSvelte } from '@sveltejs/cli-core/parsers';

export const options = defineAddonOptions()
Expand All @@ -26,9 +27,10 @@ export default defineAddon({

sv.file('src/DemoComponent.svelte', (content) => {
if (!options.demo) return content;
const { script, generateCode } = parseSvelte(content, { typescript });
imports.addDefault(script.ast, { from: '../addon-template-demo.txt?raw', as: 'demo' });
return generateCode({ script: script.generateCode(), template: '{demo}' });
const { ast, generateCode } = parseSvelte(content);
const scriptAst = svelte.ensureScript(ast, { langTs: typescript });
imports.addDefault(scriptAst, { from: '../addon-template-demo.txt?raw', as: 'demo' });
return generateCode();
});
}
});
35 changes: 24 additions & 11 deletions packages/addons/_tests/mdsvex/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import path from 'node:path';
import { expect } from '@playwright/test';
import { parseSvelte } from '@sveltejs/cli-core/parsers';
import { imports } from '@sveltejs/cli-core/js';
import * as html from '@sveltejs/cli-core/html';
import * as svelte from '@sveltejs/cli-core/svelte';
import { setupTest } from '../_setup/suite.ts';
import { svxFile } from './fixtures.ts';
import mdsvex from '../../mdsvex/index.ts';
Expand Down Expand Up @@ -40,19 +40,32 @@ function addFixture(cwd: string, variant: string) {
}

const src = fs.readFileSync(page, 'utf8');
const { script, template, generateCode } = parseSvelte(src);
imports.addDefault(script.ast, { from: './Demo.svx', as: 'Demo' });
const { ast, generateCode } = parseSvelte(src);
const scriptAst = svelte.ensureScript(ast);
imports.addDefault(scriptAst, { from: './Demo.svx', as: 'Demo' });

const div = html.createDiv({ class: 'mdsvex' });
html.appendElement(template.ast.childNodes, div);
const mdsvexNode = html.createElement('Demo');
html.appendElement(div.childNodes, mdsvexNode);

const content = generateCode({
script: script.generateCode(),
template: template.generateCode()
ast.fragment.nodes.push({
type: 'RegularElement',
name: 'div',
attributes: [
{
type: 'Attribute',
name: 'class',
value: [{ type: 'Text', data: 'mdsvex', raw: 'mdsvex', start: 0, end: 0 }],
start: 0,
end: 0
}
],
fragment: {
type: 'Fragment',
nodes: svelte.toFragment('<Demo />')
},
start: 0,
end: 0
});

const content = generateCode();

fs.writeFileSync(page, content, 'utf8');
fs.writeFileSync(svx, svxFile, 'utf8');
}
37 changes: 25 additions & 12 deletions packages/addons/common.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { imports, exports, common } from '@sveltejs/cli-core/js';
import { toFragment, type SvelteAst, ensureScript } from '@sveltejs/cli-core/svelte';
import { parseScript, parseSvelte } from '@sveltejs/cli-core/parsers';
import process from 'node:process';

Expand Down Expand Up @@ -63,22 +64,34 @@ export function addEslintConfigPrettier(content: string): string {
return generateCode();
}

export function addToDemoPage(existingContent: string, path: string, typescript: boolean): string {
const { script, template, generateCode } = parseSvelte(existingContent, { typescript });

for (const node of template.ast.childNodes) {
// we use includes as it could be "/demo/${path}" or "resolve("demo/${path}")" or "resolve('demo/${path}')"
if (node.type === 'tag' && node.attribs['href'].includes(`/demo/${path}`)) {
return existingContent;
export function addToDemoPage(existingContent: string, path: string, langTs: boolean): string {
const { ast, generateCode } = parseSvelte(existingContent);

for (const node of ast.fragment.nodes) {
if (node.type === 'RegularElement') {
const hrefAttribute = node.attributes.find(
(x) => x.type === 'Attribute' && x.name === 'href'
) as SvelteAst.Attribute;
if (!hrefAttribute || !hrefAttribute.value) continue;

if (!Array.isArray(hrefAttribute.value)) continue;

const hasDemo = hrefAttribute.value.some(
// we use includes as it could be "/demo/${path}" or "resolve("demo/${path}")" or "resolve('demo/${path}')"
(x) => x.type === 'Text' && x.data.includes(`/demo/${path}`)
);
if (hasDemo) {
return existingContent;
}
}
}

imports.addNamed(script.ast, { imports: ['resolve'], from: '$app/paths' });
imports.addNamed(ensureScript(ast, { langTs }), { imports: ['resolve'], from: '$app/paths' });

ast.fragment.nodes.unshift(...toFragment(`<a href={resolve('/demo/${path}')}>${path}</a>`));
ast.fragment.nodes.unshift();

return generateCode({
script: script.generateCode(),
template: `<a href={resolve('/demo/${path}')}>${path}</a>\n${template.source}`
});
return generateCode();
}

/**
Expand Down
41 changes: 20 additions & 21 deletions packages/addons/paraglide/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import MagicString from 'magic-string';
import { colors, defineAddon, defineAddonOptions, log } from '@sveltejs/cli-core';
import { common, imports, variables, exports, kit as kitJs, vite } from '@sveltejs/cli-core/js';
import * as html from '@sveltejs/cli-core/html';
import * as svelte from '@sveltejs/cli-core/svelte';
import { parseHtml, parseJson, parseScript, parseSvelte } from '@sveltejs/cli-core/parsers';
import { addToDemoPage } from '../common.ts';

Expand Down Expand Up @@ -183,35 +183,34 @@ export default defineAddon({

// add usage example
sv.file(`${kit.routesDirectory}/demo/paraglide/+page.svelte`, (content) => {
const { script, template, generateCode } = parseSvelte(content, { typescript });
imports.addNamed(script.ast, { from: '$lib/paraglide/messages.js', imports: ['m'] });
imports.addNamed(script.ast, { from: '$app/navigation', imports: ['goto'] });
imports.addNamed(script.ast, { from: '$app/state', imports: ['page'] });
imports.addNamed(script.ast, { from: '$lib/paraglide/runtime', imports: ['setLocale'] });
const { ast, generateCode } = parseSvelte(content);
const scriptAst = svelte.ensureScript(ast, { langTs: typescript });

const scriptCode = new MagicString(script.generateCode());

const templateCode = new MagicString(template.source);
imports.addNamed(scriptAst, { imports: { m: 'm' }, from: '$lib/paraglide/messages.js' });
imports.addNamed(scriptAst, {
imports: {
setLocale: 'setLocale'
},
from: '$lib/paraglide/runtime'
});

// add localized message
templateCode.append("\n\n<h1>{m.hello_world({ name: 'SvelteKit User' })}</h1>\n");
let templateCode = "<h1>{m.hello_world({ name: 'SvelteKit User' })}</h1>";

// add links to other localized pages, the first one is the default
// language, thus it does not require any localized route
const { validLanguageTags } = parseLanguageTagInput(options.languageTags);
const links = validLanguageTags
.map(
(x) =>
`${templateCode.getIndentString()}<button onclick={() => setLocale('${x}')}>${x}</button>`
)
.join('\n');
templateCode.append(`<div>\n${links}\n</div>`);

templateCode.append(
'<p>\nIf you use VSCode, install the <a href="https://marketplace.visualstudio.com/items?itemName=inlang.vs-code-extension" target="_blank">Sherlock i18n extension</a> for a better i18n experience.\n</p>'
);
.map((x) => `<button onclick={() => setLocale('${x}')}>${x}</button>`)
.join('');
templateCode += `<div>${links}</div>`;

templateCode +=
'<p>If you use VSCode, install the <a href="https://marketplace.visualstudio.com/items?itemName=inlang.vs-code-extension" target="_blank">Sherlock i18n extension</a> for a better i18n experience.</p>';

return generateCode({ script: scriptCode.toString(), template: templateCode.toString() });
ast.fragment.nodes.push(...svelte.toFragment(templateCode));

return generateCode();
});
}

Expand Down
24 changes: 11 additions & 13 deletions packages/addons/tailwindcss/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defineAddon, defineAddonOptions } from '@sveltejs/cli-core';
import { imports, vite } from '@sveltejs/cli-core/js';
import * as svelte from '@sveltejs/cli-core/svelte';
import { parseCss, parseJson, parseScript, parseSvelte } from '@sveltejs/cli-core/parsers';
import { addSlot } from '@sveltejs/cli-core/html';

const plugins = [
{
Expand Down Expand Up @@ -32,7 +32,7 @@ export default defineAddon({
shortDescription: 'css framework',
homepage: 'https://tailwindcss.com',
options,
run: ({ sv, options, files, typescript, kit, dependencyVersion }) => {
run: ({ sv, options, files, kit, dependencyVersion, typescript }) => {
const prettierInstalled = Boolean(dependencyVersion('prettier'));

sv.devDependency('tailwindcss', '^4.1.17');
Expand Down Expand Up @@ -97,30 +97,28 @@ export default defineAddon({
const appSvelte = 'src/App.svelte';
const stylesheetRelative = files.getRelative({ from: appSvelte, to: files.stylesheet });
sv.file(appSvelte, (content) => {
const { script, generateCode } = parseSvelte(content, { typescript });
imports.addEmpty(script.ast, { from: stylesheetRelative });
return generateCode({ script: script.generateCode() });
const { ast, generateCode } = parseSvelte(content);
const scriptAst = svelte.ensureScript(ast, { langTs: typescript });
imports.addEmpty(scriptAst, { from: stylesheetRelative });
return generateCode();
});
} else {
const layoutSvelte = `${kit?.routesDirectory}/+layout.svelte`;
const stylesheetRelative = files.getRelative({ from: layoutSvelte, to: files.stylesheet });
sv.file(layoutSvelte, (content) => {
const { script, template, generateCode } = parseSvelte(content, { typescript });
imports.addEmpty(script.ast, { from: stylesheetRelative });
const { ast, generateCode } = parseSvelte(content);
const scriptAst = svelte.ensureScript(ast, { langTs: typescript });
imports.addEmpty(scriptAst, { from: stylesheetRelative });

if (content.length === 0) {
const svelteVersion = dependencyVersion('svelte');
if (!svelteVersion) throw new Error('Failed to determine svelte version');
addSlot(script.ast, {
htmlAst: template.ast,
svelte.addSlot(ast, {
svelteVersion
});
}

return generateCode({
script: script.generateCode(),
template: content.length === 0 ? template.generateCode() : undefined
});
return generateCode();
});
}

Expand Down
14 changes: 3 additions & 11 deletions packages/cli/commands/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,7 @@ async function createProject(cwd: ProjectPath, options: Options) {
});

if (options.fromPlayground) {
await createProjectFromPlayground(
options.fromPlayground,
projectPath,
language === 'typescript'
);
await createProjectFromPlayground(options.fromPlayground, projectPath);
}

p.log.success('Project created');
Expand Down Expand Up @@ -322,19 +318,15 @@ async function createProject(cwd: ProjectPath, options: Options) {
return { directory: projectPath, addOnNextSteps, packageManager };
}

async function createProjectFromPlayground(
url: string,
cwd: string,
typescript: boolean
): Promise<void> {
async function createProjectFromPlayground(url: string, cwd: string): Promise<void> {
const urlData = parsePlaygroundUrl(url);
const playground = await downloadPlaygroundData(urlData);

// Detect external dependencies and ask for confirmation
const dependencies = detectPlaygroundDependencies(playground.files);
const installDependencies = await confirmExternalDependencies(Array.from(dependencies.keys()));

setupPlaygroundProject(url, playground, cwd, installDependencies, typescript);
setupPlaygroundProject(url, playground, cwd, installDependencies);
}

async function confirmExternalDependencies(dependencies: string[]): Promise<boolean> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
<script lang="ts">
import './layout.css';
import favicon from '$lib/assets/favicon.svg';

let { children } = $props();
</script>

<svelte:head>
<link rel="icon" href={favicon} />
</svelte:head>

<svelte:head><link rel="icon" href={favicon} /></svelte:head>
{@render children()}
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
<script lang="ts">
import { setLocale } from '$lib/paraglide/runtime';
import { page } from '$app/state';
import { goto } from '$app/navigation';
import { m } from '$lib/paraglide/messages.js';
</script>



<h1>{m.hello_world({ name: 'SvelteKit User' })}</h1>
<div>
<button onclick={() => setLocale('en')}>en</button>
<button onclick={() => setLocale('es')}>es</button>
</div><p>
If you use VSCode, install the <a href="https://marketplace.visualstudio.com/items?itemName=inlang.vs-code-extension" target="_blank">Sherlock i18n extension</a> for a better i18n experience.
</div>
<p>
If you use VSCode, install the
<a
href="https://marketplace.visualstudio.com/items?itemName=inlang.vs-code-extension"
target="_blank"
>
Sherlock i18n extension
</a>
for a better i18n experience.
</p>
2 changes: 2 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"./css": "./tooling/css/index.ts",
"./html": "./tooling/html/index.ts",
"./js": "./tooling/js/index.ts",
"./svelte": "./tooling/svelte/index.ts",
"./parsers": "./tooling/parsers.ts"
},
"devDependencies": {
Expand All @@ -40,6 +41,7 @@
"picocolors": "^1.1.1",
"postcss": "^8.5.6",
"silver-fleece": "^1.2.1",
"svelte": "^5.45.0",
"yaml": "^2.8.1",
"zimmerframe": "^1.1.4"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/core/tests/js/object/property-node/input.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const test = {
/** a comment */
// prettier-ignore
foo: 1
};
4 changes: 2 additions & 2 deletions packages/core/tests/js/object/property-node/output.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const test = {
/** a comment */
/*a comment updated*/ // prettier-ignore
foo: 1,

james: '007'
/*aka: bond, james bond*/ james: '007'
};
8 changes: 4 additions & 4 deletions packages/core/tests/js/object/property-node/run.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { object, common, type AstTypes } from '@sveltejs/cli-core/js';
import { object, common, type AstTypes, type Comments } from '@sveltejs/cli-core/js';
import { getTestObjectExpression } from '../objectTestHelper.ts';

export function run(ast: AstTypes.Program): void {
export function run(ast: AstTypes.Program, comments: Comments): void {
const obj = getTestObjectExpression(ast);

const p1 = object.propertyNode(obj, {
name: 'foo',
fallback: object.create({})
});
p1.leadingComments = [{ type: 'Block', value: 'a comment updated' }];
comments.add(p1, { type: 'Block', value: 'a comment updated' });

const p2 = object.propertyNode(obj, {
name: 'james',
fallback: common.createLiteral('007')
});
p2.leadingComments = [{ type: 'Block', value: 'aka: bond, james bond' }];
comments.add(p2, { type: 'Block', value: 'aka: bond, james bond' });
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Nothing to see here
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script lang="ts"></script>

Nothing to see here
5 changes: 5 additions & 0 deletions packages/core/tests/svelte/common/ensure-script-ts/run.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { type SvelteAst, ensureScript } from '@sveltejs/cli-core/svelte';

export function run(ast: SvelteAst.Root): void {
ensureScript(ast, { langTs: true });
}
3 changes: 3 additions & 0 deletions packages/core/tests/svelte/common/ensure-script/input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
<p>This is a Svelte component without script block</p>
</div>
Loading
Loading