diff --git a/community-addon-template/src/index.js b/community-addon-template/src/index.js index 3c2f5ee50..6cb0802dc 100644 --- a/community-addon-template/src/index.js +++ b/community-addon-template/src/index.js @@ -14,7 +14,7 @@ export default defineAddon({ setup: ({ kit, unsupported }) => { if (!kit) unsupported('Requires SvelteKit'); }, - run: ({ sv, options, typescript }) => { + run: ({ sv, options, ext }) => { sv.file('addon-template-demo.txt', (content) => { if (options.demo) { return 'This is a text file made by the Community Addon Template demo!'; @@ -25,7 +25,7 @@ export default defineAddon({ sv.file('src/DemoComponent.svelte', (content) => { if (!options.demo) return content; const { ast, generateCode } = parseSvelte(content); - const scriptAst = svelte.ensureScript(ast, { langTs: typescript }); + const scriptAst = svelte.ensureScript(ast, { ext }); js.imports.addDefault(scriptAst, { from: '../addon-template-demo.txt?raw', as: 'demo' }); return generateCode(); }); diff --git a/packages/sv/lib/addons/_tests/mdsvex/test.ts b/packages/sv/lib/addons/_tests/mdsvex/test.ts index 5144d5ac9..31b6d0868 100644 --- a/packages/sv/lib/addons/_tests/mdsvex/test.ts +++ b/packages/sv/lib/addons/_tests/mdsvex/test.ts @@ -41,9 +41,8 @@ function addFixture(cwd: string, variant: string) { } const src = fs.readFileSync(page, 'utf8'); - const { ast, generateCode } = parseSvelte(src); - const scriptAst = svelte.ensureScript(ast); - imports.addDefault(scriptAst, { from: './Demo.svx', as: 'Demo' }); + const { script, generateCode } = parseSvelte(src, { ensureScript: { ext: 'ts' } }); + imports.addDefault(script, { from: './Demo.svx', as: 'Demo' }); const div = html.createElement('div', { class: 'mdsvex' }); div.fragment.nodes = svelte.toFragment(''); diff --git a/packages/sv/lib/addons/common.ts b/packages/sv/lib/addons/common.ts index 95108f8c8..d2f46d10f 100644 --- a/packages/sv/lib/addons/common.ts +++ b/packages/sv/lib/addons/common.ts @@ -1,5 +1,5 @@ import { imports, exports, common } from '../core/tooling/js/index.ts'; -import { toFragment, type SvelteAst, ensureScript } from '../core/tooling/svelte/index.ts'; +import { toFragment, type SvelteAst } from '../core/tooling/svelte/index.ts'; import { parseScript, parseSvelte } from '../core/tooling/parsers.ts'; import process from 'node:process'; @@ -64,8 +64,8 @@ export function addEslintConfigPrettier(content: string): string { return generateCode(); } -export function addToDemoPage(existingContent: string, path: string, langTs: boolean): string { - const { ast, generateCode } = parseSvelte(existingContent); +export function addToDemoPage(existingContent: string, path: string, ext: 'ts' | 'js'): string { + const { ast, script, generateCode } = parseSvelte(existingContent, { ensureScript: { ext } }); for (const node of ast.fragment.nodes) { if (node.type === 'RegularElement') { @@ -86,7 +86,7 @@ export function addToDemoPage(existingContent: string, path: string, langTs: boo } } - imports.addNamed(ensureScript(ast, { langTs }), { imports: ['resolve'], from: '$app/paths' }); + imports.addNamed(script, { imports: ['resolve'], from: '$app/paths' }); ast.fragment.nodes.unshift(...toFragment(`${path}`)); ast.fragment.nodes.unshift(); diff --git a/packages/sv/lib/addons/drizzle/index.ts b/packages/sv/lib/addons/drizzle/index.ts index 3ee9784fd..e3cdb20b1 100644 --- a/packages/sv/lib/addons/drizzle/index.ts +++ b/packages/sv/lib/addons/drizzle/index.ts @@ -85,10 +85,10 @@ export default defineAddon({ if (!kit) return unsupported('Requires SvelteKit'); }, - run: ({ sv, typescript, options, kit, dependencyVersion, cwd, cancel, files }) => { + run: ({ sv, ext, options, kit, dependencyVersion, cwd, cancel, files }) => { if (!kit) throw new Error('SvelteKit is required'); - const ext = typescript ? 'ts' : 'js'; + const typescript = ext === 'ts'; const baseDBPath = path.resolve(cwd, kit.libDirectory, 'server', 'db'); const paths = { 'drizzle config': path.resolve(cwd, `drizzle.config.${ext}`), diff --git a/packages/sv/lib/addons/eslint/index.ts b/packages/sv/lib/addons/eslint/index.ts index 49d716107..f8b1cb255 100644 --- a/packages/sv/lib/addons/eslint/index.ts +++ b/packages/sv/lib/addons/eslint/index.ts @@ -17,7 +17,8 @@ export default defineAddon({ shortDescription: 'linter', homepage: 'https://eslint.org', options: {}, - run: ({ sv, typescript, dependencyVersion, files }) => { + run: ({ sv, ext, dependencyVersion, files }) => { + const typescript = ext === 'ts'; const prettierInstalled = Boolean(dependencyVersion('prettier')); sv.devDependency('eslint', '^9.39.1'); diff --git a/packages/sv/lib/addons/lucia/index.ts b/packages/sv/lib/addons/lucia/index.ts index 3964788ce..ef316e328 100644 --- a/packages/sv/lib/addons/lucia/index.ts +++ b/packages/sv/lib/addons/lucia/index.ts @@ -45,8 +45,8 @@ export default defineAddon({ runsAfter('tailwindcss'); }, - run: ({ sv, typescript, options, kit, dependencyVersion }) => { - const ext = typescript ? 'ts' : 'js'; + run: ({ sv, ext, options, kit, dependencyVersion }) => { + const typescript = ext === 'ts'; sv.devDependency('@oslojs/crypto', '^1.0.1'); sv.devDependency('@oslojs/encoding', '^1.1.0'); @@ -387,7 +387,7 @@ export default defineAddon({ const { ast, generateCode } = parseScript(content); js.imports.addNamespace(ast, { from: '$lib/server/auth', as: 'auth' }); js.kit.addHooksHandle(ast, { - typescript, + ext, newHandleName: 'handleAuth', handleContent: getAuthHandleContent() }); @@ -396,7 +396,7 @@ export default defineAddon({ if (options.demo) { sv.file(`${kit?.routesDirectory}/demo/+page.svelte`, (content) => { - return addToDemoPage(content, 'lucia', typescript); + return addToDemoPage(content, 'lucia', ext); }); sv.file(`${kit!.routesDirectory}/demo/lucia/login/+page.server.${ext}`, (content) => { diff --git a/packages/sv/lib/addons/paraglide/index.ts b/packages/sv/lib/addons/paraglide/index.ts index 55b502372..d9ebdf65b 100644 --- a/packages/sv/lib/addons/paraglide/index.ts +++ b/packages/sv/lib/addons/paraglide/index.ts @@ -62,8 +62,7 @@ export default defineAddon({ setup: ({ kit, unsupported }) => { if (!kit) unsupported('Requires SvelteKit'); }, - run: ({ sv, options, files, typescript, kit }) => { - const ext = typescript ? 'ts' : 'js'; + run: ({ sv, options, files, ext, kit }) => { if (!kit) throw new Error('SvelteKit is required'); const paraglideOutDir = 'src/lib/paraglide'; @@ -127,7 +126,7 @@ export default defineAddon({ }); });`; kitJs.addHooksHandle(ast, { - typescript, + ext, newHandleName: 'handleParaglide', handleContent: hookHandleContent }); @@ -181,13 +180,15 @@ export default defineAddon({ }); sv.file(`${kit.routesDirectory}/+layout.svelte`, (content) => { - const { ast, generateCode } = parseSvelte(content); - const scriptAst = svelte.ensureScript(ast); - imports.addNamed(scriptAst, { + const { ast, script, generateCode } = parseSvelte(content, { + ensureScript: { ext } + }); + + imports.addNamed(script, { imports: ['locales', 'localizeHref'], from: '$lib/paraglide/runtime' }); - imports.addNamed(scriptAst, { imports: ['page'], from: '$app/state' }); + imports.addNamed(script, { imports: ['page'], from: '$app/state' }); ast.fragment.nodes.push( ...svelte.toFragment(`
{#each locales as locale} @@ -200,16 +201,17 @@ export default defineAddon({ if (options.demo) { sv.file(`${kit.routesDirectory}/demo/+page.svelte`, (content) => { - return addToDemoPage(content, 'paraglide', typescript); + return addToDemoPage(content, 'paraglide', ext); }); // add usage example sv.file(`${kit.routesDirectory}/demo/paraglide/+page.svelte`, (content) => { - const { ast, generateCode } = parseSvelte(content); - const scriptAst = svelte.ensureScript(ast, { langTs: typescript }); + const { ast, script, generateCode } = parseSvelte(content, { + ensureScript: { ext } + }); - imports.addNamed(scriptAst, { imports: { m: 'm' }, from: '$lib/paraglide/messages.js' }); - imports.addNamed(scriptAst, { + imports.addNamed(script, { imports: { m: 'm' }, from: '$lib/paraglide/messages.js' }); + imports.addNamed(script, { imports: { setLocale: 'setLocale' }, diff --git a/packages/sv/lib/addons/playwright/index.ts b/packages/sv/lib/addons/playwright/index.ts index 6bf862ed5..f0d749937 100644 --- a/packages/sv/lib/addons/playwright/index.ts +++ b/packages/sv/lib/addons/playwright/index.ts @@ -7,9 +7,7 @@ export default defineAddon({ shortDescription: 'browser testing', homepage: 'https://playwright.dev', options: {}, - run: ({ sv, typescript, files }) => { - const ext = typescript ? 'ts' : 'js'; - + run: ({ sv, ext, files }) => { sv.devDependency('@playwright/test', '^1.57.0'); sv.file(files.package, (content) => { diff --git a/packages/sv/lib/addons/sveltekit-adapter/index.ts b/packages/sv/lib/addons/sveltekit-adapter/index.ts index b5630edcc..7b23f034e 100644 --- a/packages/sv/lib/addons/sveltekit-adapter/index.ts +++ b/packages/sv/lib/addons/sveltekit-adapter/index.ts @@ -42,7 +42,7 @@ export default defineAddon({ setup: ({ kit, unsupported }) => { if (!kit) unsupported('Requires SvelteKit'); }, - run: ({ sv, options, files, cwd, packageManager, typescript }) => { + run: ({ sv, options, files, cwd, packageManager, ext }) => { const adapter = adapters.find((a) => a.id === options.adapter)!; // removes previously installed adapters @@ -171,7 +171,7 @@ export default defineAddon({ }); const jsconfig = fileExists(cwd, 'jsconfig.json'); - const typeChecked = typescript || jsconfig; + const typeChecked = ext === 'ts' || jsconfig; if (typeChecked) { // Ignore generated Cloudflare Types diff --git a/packages/sv/lib/addons/tailwindcss/index.ts b/packages/sv/lib/addons/tailwindcss/index.ts index c43fcb129..01db0fc58 100644 --- a/packages/sv/lib/addons/tailwindcss/index.ts +++ b/packages/sv/lib/addons/tailwindcss/index.ts @@ -33,7 +33,7 @@ export default defineAddon({ shortDescription: 'css framework', homepage: 'https://tailwindcss.com', options, - run: ({ sv, options, files, kit, dependencyVersion, typescript }) => { + run: ({ sv, options, files, kit, dependencyVersion, ext }) => { const prettierInstalled = Boolean(dependencyVersion('prettier')); sv.devDependency('tailwindcss', '^4.1.17'); @@ -88,18 +88,19 @@ export default defineAddon({ const appSvelte = 'src/App.svelte'; const stylesheetRelative = files.getRelative({ from: appSvelte, to: files.stylesheet }); sv.file(appSvelte, (content) => { - const { ast, generateCode } = parseSvelte(content); - const scriptAst = svelte.ensureScript(ast, { langTs: typescript }); - imports.addEmpty(scriptAst, { from: stylesheetRelative }); + const { script, generateCode } = parseSvelte(content, { + ensureScript: { ext } + }); + imports.addEmpty(script, { 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 { ast, generateCode } = parseSvelte(content); - const scriptAst = svelte.ensureScript(ast, { langTs: typescript }); - imports.addEmpty(scriptAst, { from: stylesheetRelative }); + const { ast, script, generateCode } = parseSvelte(content, { ensureScript: { ext } }); + + imports.addEmpty(script, { from: stylesheetRelative }); if (content.length === 0) { const svelteVersion = dependencyVersion('svelte'); diff --git a/packages/sv/lib/addons/vitest-addon/index.ts b/packages/sv/lib/addons/vitest-addon/index.ts index f2c048ad6..99fde6a8c 100644 --- a/packages/sv/lib/addons/vitest-addon/index.ts +++ b/packages/sv/lib/addons/vitest-addon/index.ts @@ -24,8 +24,7 @@ export default defineAddon({ homepage: 'https://vitest.dev', options, - run: ({ sv, files, typescript, kit, options, dependencyVersion }) => { - const ext = typescript ? 'ts' : 'js'; + run: ({ sv, files, ext, kit, options, dependencyVersion }) => { const unitTesting = options.usages.includes('unit'); const componentTesting = options.usages.includes('component'); @@ -160,7 +159,7 @@ export default defineAddon({ }); }, - nextSteps: ({ highlighter, typescript, options }) => { + nextSteps: ({ highlighter, ext, options }) => { const toReturn: string[] = []; if (vitestV3Installed) { @@ -175,7 +174,7 @@ export default defineAddon({ `${highlighter.optional('Optional')} Check ${highlighter.path('./vite.config.ts')} and remove duplicate project definitions` ); toReturn.push( - `${highlighter.optional('Optional')} Remove ${highlighter.path('./vitest-setup-client' + (typescript ? '.ts' : '.js'))} file` + `${highlighter.optional('Optional')} Remove ${highlighter.path('./vitest-setup-client.' + ext)} file` ); } diff --git a/packages/sv/lib/cli/add/workspace.ts b/packages/sv/lib/cli/add/workspace.ts index 886ca7468..036b2317c 100644 --- a/packages/sv/lib/cli/add/workspace.ts +++ b/packages/sv/lib/cli/add/workspace.ts @@ -82,7 +82,7 @@ export async function createWorkspace({ return { cwd: resolvedCwd, packageManager: packageManager ?? (await detect({ cwd }))?.name ?? getUserAgent() ?? 'npm', - typescript: usesTypescript, + ext: usesTypescript ? 'ts' : 'js', files: { viteConfig, svelteConfig, diff --git a/packages/sv/lib/cli/create.ts b/packages/sv/lib/cli/create.ts index e02d2eeb6..132b7a681 100644 --- a/packages/sv/lib/cli/create.ts +++ b/packages/sv/lib/cli/create.ts @@ -386,7 +386,7 @@ export async function createVirtualWorkspace({ const virtualWorkspace: Workspace = { ...tentativeWorkspace, - typescript: type === 'typescript', + ext: type === 'typescript' ? 'ts' : 'js', files: { ...tentativeWorkspace.files, viteConfig: type === 'typescript' ? commonFilePaths.viteConfigTS : commonFilePaths.viteConfig, diff --git a/packages/sv/lib/core/addon/workspace.ts b/packages/sv/lib/core/addon/workspace.ts index 4c1fdc4d0..f8e0d6242 100644 --- a/packages/sv/lib/core/addon/workspace.ts +++ b/packages/sv/lib/core/addon/workspace.ts @@ -13,7 +13,8 @@ export type Workspace = { * @returns the dependency version with any leading characters such as ^ or ~ removed */ dependencyVersion: (pkg: string) => string | undefined; - typescript: boolean; + /** to know if the workspace is using typescript or javascript */ + ext: 'ts' | 'js'; files: { viteConfig: 'vite.config.js' | 'vite.config.ts'; svelteConfig: 'svelte.config.js' | 'svelte.config.ts'; diff --git a/packages/sv/lib/core/tests/svelte/common/ensure-script-ts/run.ts b/packages/sv/lib/core/tests/svelte/common/ensure-script-ts/run.ts index 3ac0c7533..ccac1642a 100644 --- a/packages/sv/lib/core/tests/svelte/common/ensure-script-ts/run.ts +++ b/packages/sv/lib/core/tests/svelte/common/ensure-script-ts/run.ts @@ -1,5 +1,5 @@ import { type SvelteAst, ensureScript } from '../../../../tooling/svelte/index.ts'; export function run(ast: SvelteAst.Root): void { - ensureScript(ast, { langTs: true }); + ensureScript(ast, { ext: 'ts' }); } diff --git a/packages/sv/lib/core/tooling/js/kit.ts b/packages/sv/lib/core/tooling/js/kit.ts index fed1cf763..571d24227 100644 --- a/packages/sv/lib/core/tooling/js/kit.ts +++ b/packages/sv/lib/core/tooling/js/kit.ts @@ -61,12 +61,12 @@ export function addGlobalAppInterface( export function addHooksHandle( node: AstTypes.Program, options: { - typescript: boolean; + ext: 'ts' | 'js'; newHandleName: string; handleContent: string; } ): void { - if (options.typescript) { + if (options.ext === 'ts') { imports.addNamed(node, { from: '@sveltejs/kit', imports: { Handle: 'Handle' }, @@ -133,7 +133,7 @@ export function addHooksHandle( value: newHandle }); - if (options.typescript) { + if (options.ext === 'ts') { const declarator = newHandleDecl.declarations[0] as AstTypes.VariableDeclarator; variables.typeAnnotateDeclarator(declarator, { typeName: 'Handle' }); } @@ -145,7 +145,7 @@ export function addHooksHandle( value: variables.createIdentifier(options.newHandleName) }); - if (options.typescript) { + if (options.ext === 'ts') { const declarator = handleDecl.declarations[0] as AstTypes.VariableDeclarator; variables.typeAnnotateDeclarator(declarator, { typeName: 'Handle' }); } @@ -163,7 +163,7 @@ export function addHooksHandle( name: options.newHandleName, value: newHandle }); - if (options.typescript) { + if (options.ext === 'ts') { const declarator = newHandleDecl.declarations[0] as AstTypes.VariableDeclarator; variables.typeAnnotateDeclarator(declarator, { typeName: 'Handle' }); } @@ -269,7 +269,7 @@ export function addHooksHandle( name: handleName, value: sequenceCall }); - if (options.typescript) { + if (options.ext === 'ts') { const declarator = finalHandleDecl.declarations[0] as AstTypes.VariableDeclarator; variables.typeAnnotateDeclarator(declarator, { typeName: 'Handle' }); } diff --git a/packages/sv/lib/core/tooling/parsers.ts b/packages/sv/lib/core/tooling/parsers.ts index 2dc8c5972..d7408b9eb 100644 --- a/packages/sv/lib/core/tooling/parsers.ts +++ b/packages/sv/lib/core/tooling/parsers.ts @@ -1,5 +1,6 @@ import type { TomlTable } from 'smol-toml'; import * as utils from './index.ts'; +import { ensureScript } from './svelte/index.ts'; type ParseBase = { source: string; @@ -48,12 +49,30 @@ export function parseYaml( return { data, source, generateCode }; } -export function parseSvelte(source: string): { ast: utils.SvelteAst.Root } & ParseBase { +export function parseSvelte( + source: string, + options: { ensureScript: Parameters[1] } +): { ast: utils.SvelteAst.Root; script: utils.AstTypes.Program } & ParseBase; +export function parseSvelte( + source: string, + options?: { ensureScript?: Parameters[1] } +): { ast: utils.SvelteAst.Root; script?: utils.AstTypes.Program } & ParseBase; +export function parseSvelte( + source: string, + options?: { ensureScript?: Parameters[1] } +): { ast: utils.SvelteAst.Root; script?: utils.AstTypes.Program } & ParseBase { const ast = utils.parseSvelte(source); + + let script = ast.instance?.content; + if (options?.ensureScript) { + script = ensureScript(ast, options.ensureScript); + } + const generateCode = () => utils.serializeSvelte(ast); return { ast, + script, source, generateCode }; diff --git a/packages/sv/lib/core/tooling/svelte/index.ts b/packages/sv/lib/core/tooling/svelte/index.ts index c73df0908..c56408917 100644 --- a/packages/sv/lib/core/tooling/svelte/index.ts +++ b/packages/sv/lib/core/tooling/svelte/index.ts @@ -6,7 +6,7 @@ export type { SvelteAst }; export function ensureScript( ast: SvelteAst.Root, - options?: { langTs?: boolean } + options?: { ext?: 'ts' | 'js' } ): AstTypes.Program { let scriptAst = ast.instance?.content; if (!scriptAst) { @@ -17,17 +17,18 @@ export function ensureScript( end: 0, context: 'default', // @ts-expect-error - attributes: options?.langTs - ? [ - { - type: 'Attribute', - start: 8, - end: 17, - name: 'lang', - value: [{ start: 14, end: 16, type: 'Text', raw: 'ts', data: 'ts' }] - } - ] - : [], + attributes: + options?.ext === 'ts' + ? [ + { + type: 'Attribute', + start: 8, + end: 17, + name: 'lang', + value: [{ start: 14, end: 16, type: 'Text', raw: 'ts', data: 'ts' }] + } + ] + : [], content: scriptAst }; } @@ -37,7 +38,7 @@ export function ensureScript( export function addSlot( ast: SvelteAst.Root, - options: { svelteVersion: string; langTs?: boolean } + options: { svelteVersion: string; ext?: 'ts' | 'js' } ): void { const slotSyntax = options.svelteVersion && @@ -60,7 +61,7 @@ export function addSlot( return; } - const scriptAst = ensureScript(ast, { langTs: options.langTs }); + const scriptAst = ensureScript(ast, { ext: options.ext }); appendFromString(scriptAst, { code: 'const { children } = $props();' }); diff --git a/packages/sv/lib/create/playground.ts b/packages/sv/lib/create/playground.ts index 6ec216415..08b62a34f 100644 --- a/packages/sv/lib/create/playground.ts +++ b/packages/sv/lib/create/playground.ts @@ -102,8 +102,8 @@ export function detectPlaygroundDependencies(files: PlaygroundData['files']): Ma for (const file of files) { let ast: js.AstTypes.Program | undefined; if (file.name.endsWith('.svelte')) { - const { ast: svelteAst } = parseSvelte(file.content); - ast = svelte.ensureScript(svelteAst); + const { script } = parseSvelte(file.content, { ensureScript: {} }); + ast = script; } else if (file.name.endsWith('.js') || file.name.endsWith('.ts')) { ast = parseScript(file.content).ast; }