From 97a2beb260566547d92bc4f62299aa50efc28155 Mon Sep 17 00:00:00 2001 From: jycouet Date: Tue, 7 Jul 2026 22:10:32 +0200 Subject: [PATCH 1/3] re-add diffLines size cap, handle trailing commas before ), trim comments --- packages/sv-utils/src/sanitize.ts | 34 ++++++++----------------- packages/sv-utils/src/tests/sanitize.ts | 31 ++++++++++++++++++++++ 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/packages/sv-utils/src/sanitize.ts b/packages/sv-utils/src/sanitize.ts index abbfbe002..8557f8e68 100644 --- a/packages/sv-utils/src/sanitize.ts +++ b/packages/sv-utils/src/sanitize.ts @@ -28,25 +28,20 @@ export function sanitizeName(name: string, style: 'package' | 'wrangler'): strin return sanitized || 'undefined-sv-name'; } +// `diffLines` is O(N·D); past this size we keep the printer output rather than hanging. +const MAX_DIFF_INPUT_BYTES = 512 * 1024; + /** - * Minimizes formatting churn in generated output. - * - * Formatting-only hunks are restored verbatim from the original. Real changes keep the updated - * content while reusing the original blank-line layout when the old and updated lines can be paired - * safely. This avoids unrelated punctuation and blank-line churn around useful edits without - * rewriting authored content. - * - * Brand-new or whitespace-only files are kept verbatim: their blank lines are authored layout, not - * printer churn, so stripping them would mangle generated markdown, env files, etc. + * Minimizes formatting churn in reprinted output: formatting-only hunks are restored verbatim from + * the original, real changes keep the updated content but reuse the original blank-line layout. */ export function minimizeDiff(old: string, updated: string): string { if (isBlank(old)) return updated; + if (old.length > MAX_DIFF_INPUT_BYTES || updated.length > MAX_DIFF_INPUT_BYTES) return updated; const original = normalizeLineEndings(old); const replacement = normalizeLineEndings(updated); - // These passes need different line alignment. First restore formatting-only replacements using - // exact lines, then ignore indentation while restoring the original blank-line layout. const formattingMinimized = restoreFormattingOnlyChanges(original, replacement); return restoreBlankLineLayout(original, formattingMinimized); } @@ -54,8 +49,7 @@ export function minimizeDiff(old: string, updated: string): string { type LineChange = ReturnType[number]; function restoreFormattingOnlyChanges(original: string, replacement: string): string { - // Exact matching keeps closing braces and other repeated punctuation attached to the replacement - // that reformatted them instead of letting diffLines use them as misleading anchors. + // exact matching keeps reformatted punctuation inside the hunk instead of becoming a false anchor const changes = diffLines(original, replacement); let result = ''; @@ -78,8 +72,7 @@ function restoreFormattingOnlyChanges(original: string, replacement: string): st } function restoreBlankLineLayout(original: string, replacement: string): string { - // The formatting pass has already handled rewrapped hunks. Ignoring whitespace here gives - // diffLines stable anchors across reindentation so isolated blank-line moves remain visible. + // ignoring whitespace keeps reindented lines as anchors so only blank-line moves show up const changes = diffLines(original, replacement, { ignoreWhitespace: true }); let result = ''; @@ -94,8 +87,7 @@ function restoreBlankLineLayout(original: string, replacement: string): string { continue; } - // diffLines can use a blank line as an anchor between the removed and added sides of a - // replacement. Consider that anchor as part of the hunk so the decision is still made here. + // a blank line can anchor between the removed and added sides; treat it as part of the hunk if ( isChange(change) && next && @@ -112,7 +104,6 @@ function restoreBlankLineLayout(original: string, replacement: string): string { if (!isChange(change)) { result += change.value; } else if (isBlank(change.value)) { - // Keep removed blank lines and discard added ones. if (change.removed) result += change.value; } else if (change.added) { result += change.value; @@ -141,9 +132,6 @@ function isBlank(value: string): boolean { } function resolveReplacement(changes: LineChange[]): string { - // Reconstruct both sides because a replacement may include an unchanged blank-line anchor. - // Formatting-equivalent replacements use the original verbatim; real edits keep their updated - // content while borrowing the original blank-line positions when the lines pair safely. let original = ''; let replacement = ''; @@ -161,7 +149,7 @@ function normalizeForComparison(value: string): string { return value .replace(/\s/g, '') .replace(/;/g, '') - .replace(/,([}\]])/g, '$1') + .replace(/,([}\])])/g, '$1') .replace(/,$/, ''); } @@ -170,7 +158,7 @@ function preserveBlankLineLayout(original: string, replacement: string): string const replacementLines = replacement.split('\n'); const replacementContent = replacementLines.filter((line) => line.trim() !== ''); - // Positional pairing is only safe when every original content line has an updated counterpart. + // positional pairing is only safe when content line counts match if (originalLines.filter((line) => line.trim() !== '').length !== replacementContent.length) { return replacement; } diff --git a/packages/sv-utils/src/tests/sanitize.ts b/packages/sv-utils/src/tests/sanitize.ts index af6118223..948931a03 100644 --- a/packages/sv-utils/src/tests/sanitize.ts +++ b/packages/sv-utils/src/tests/sanitize.ts @@ -580,6 +580,37 @@ describe('minimizeDiff', () => { expect(minimizeDiff(old, updated)).toBe(old.replace("'old'", "'new'")); }); + it('restores original formatting when a call with trailing commas is collapsed onto one line', () => { + const old = dedent` + const version = 'old'; + + const sha = await canonicalize( + opts.owner, + opts.repo, + opts.commit, + ); + `; + + const updated = dedent` + const version = 'new'; + + const sha = await canonicalize(opts.owner, opts.repo, opts.commit); + `; + + expect(minimizeDiff(old, updated)).toBe(old.replace("'old'", "'new'")); + }); + + it('keeps oversized inputs verbatim instead of diffing them', () => { + // worst case for diffLines is O(N·D); past the size cap the updated content is returned as-is + const line = (i: number) => `const value_${i} = compute(${i});`; + const old = Array.from({ length: 20_000 }, (_, i) => line(i)).join('\n'); + const updated = Array.from({ length: 20_000 }, (_, i) => `\t${line(i)}\n`).join(''); + + const start = performance.now(); + expect(minimizeDiff(old, updated)).toBe(updated); + expect(performance.now() - start).toBeLessThan(1000); + }); + it('keeps updated hunks when non-trailing commas change the meaning', () => { const old = dedent` const values = ['a' + 'b']; From 9b2c49f6ab6e8d2cbf8f419304b72310a6653f7c Mon Sep 17 00:00:00 2001 From: jycouet Date: Tue, 7 Jul 2026 22:11:30 +0200 Subject: [PATCH 2/3] update migrate snapshots for new minimizeDiff blank-line behavior --- .../app-state/tests/app-state/strings-comments.snapshot.svelte | 1 + .../tests/environment/dynamic-import-namespace.snapshot.ts | 1 + .../sveltekit-3/tests/svelte-config/eslint.config.snapshot.js | 1 + .../sveltekit-3/tests/svelte-config/vite.config.snapshot.ts | 2 ++ 4 files changed, 5 insertions(+) diff --git a/packages/sv/src/migrate/migrations/app-state/tests/app-state/strings-comments.snapshot.svelte b/packages/sv/src/migrate/migrations/app-state/tests/app-state/strings-comments.snapshot.svelte index 54db38e97..80829ce6d 100644 --- a/packages/sv/src/migrate/migrations/app-state/tests/app-state/strings-comments.snapshot.svelte +++ b/packages/sv/src/migrate/migrations/app-state/tests/app-state/strings-comments.snapshot.svelte @@ -6,4 +6,5 @@ * This is a page */ + Nice page!
{page.url}
diff --git a/packages/sv/src/migrate/migrations/sveltekit-3/tests/environment/dynamic-import-namespace.snapshot.ts b/packages/sv/src/migrate/migrations/sveltekit-3/tests/environment/dynamic-import-namespace.snapshot.ts index 8278edc28..50546bc05 100644 --- a/packages/sv/src/migrate/migrations/sveltekit-3/tests/environment/dynamic-import-namespace.snapshot.ts +++ b/packages/sv/src/migrate/migrations/sveltekit-3/tests/environment/dynamic-import-namespace.snapshot.ts @@ -1,6 +1,7 @@ export async function requireDynamicImportEnv(name: string): Promise { // @migration-task Declare the imported env variables in src/env.ts manually. const privateEnv = await import('$app/env/private'); + const value = privateEnv[name]; if (!value) throw new Error(`${name} must be set`); return value; diff --git a/packages/sv/src/migrate/migrations/sveltekit-3/tests/svelte-config/eslint.config.snapshot.js b/packages/sv/src/migrate/migrations/sveltekit-3/tests/svelte-config/eslint.config.snapshot.js index 5bb4f4c31..1dc6c34a4 100644 --- a/packages/sv/src/migrate/migrations/sveltekit-3/tests/svelte-config/eslint.config.snapshot.js +++ b/packages/sv/src/migrate/migrations/sveltekit-3/tests/svelte-config/eslint.config.snapshot.js @@ -1,6 +1,7 @@ import js from '@eslint/js'; import svelte from 'eslint-plugin-svelte'; import { defineConfig } from 'eslint/config'; + // @migration-task svelteConfig should not be needed anymore, see https://github.com/sveltejs/eslint-plugin-svelte/issues/1550 import svelteConfig from './svelte.config.js'; diff --git a/packages/sv/src/migrate/migrations/sveltekit-3/tests/svelte-config/vite.config.snapshot.ts b/packages/sv/src/migrate/migrations/sveltekit-3/tests/svelte-config/vite.config.snapshot.ts index 757db8736..1cb998f7b 100644 --- a/packages/sv/src/migrate/migrations/sveltekit-3/tests/svelte-config/vite.config.snapshot.ts +++ b/packages/sv/src/migrate/migrations/sveltekit-3/tests/svelte-config/vite.config.snapshot.ts @@ -9,7 +9,9 @@ import devtoolsJson from 'vite-plugin-devtools-json'; // derive paths and adapter config from the environment const { paths, adapterConfig } = helper(process.env['SOME_ENV_VAR']); + const base = process.env['VITEST'] ? '' : '/some-base'; // empty base while testing + export default defineConfig({ plugins: [ tailwindcss(), From d94684c580e4cc77325444f2a773ea07153c13b6 Mon Sep 17 00:00:00 2001 From: jycouet Date: Tue, 7 Jul 2026 22:24:17 +0200 Subject: [PATCH 3/3] update cli create snapshots for new minimizeDiff blank-line behavior --- .../src/cli/tests/snapshots/create-experimental/.env.example | 2 ++ .../src/cli/tests/snapshots/create-experimental/src/app.d.ts | 3 +++ .../snapshots/create-experimental/src/lib/server/db/schema.ts | 1 + .../src/cli/tests/snapshots/create-experimental/vite.config.ts | 1 - .../cli/tests/snapshots/create-with-all-addons/.env.example | 2 ++ .../cli/tests/snapshots/create-with-all-addons/src/app.d.ts | 2 ++ .../tests/snapshots/create-with-all-addons/src/hooks.server.ts | 3 +++ .../create-with-all-addons/src/lib/server/db/schema.ts | 1 + .../snapshots/create-with-all-addons/src/routes/+layout.svelte | 1 + .../cli/tests/snapshots/create-with-all-addons/vite.config.ts | 2 +- 10 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/sv/src/cli/tests/snapshots/create-experimental/.env.example b/packages/sv/src/cli/tests/snapshots/create-experimental/.env.example index 6bb40ccbe..34a24e9fe 100644 --- a/packages/sv/src/cli/tests/snapshots/create-experimental/.env.example +++ b/packages/sv/src/cli/tests/snapshots/create-experimental/.env.example @@ -1,6 +1,8 @@ # Drizzle DATABASE_URL=file:local.db + ORIGIN="" + # Better Auth # For production use 32 characters and generated with high entropy # https://www.better-auth.com/docs/installation diff --git a/packages/sv/src/cli/tests/snapshots/create-experimental/src/app.d.ts b/packages/sv/src/cli/tests/snapshots/create-experimental/src/app.d.ts index 6ccfd4dd2..16910ac28 100644 --- a/packages/sv/src/cli/tests/snapshots/create-experimental/src/app.d.ts +++ b/packages/sv/src/cli/tests/snapshots/create-experimental/src/app.d.ts @@ -1,4 +1,5 @@ import type { User, Session } from 'better-auth'; + // See https://svelte.dev/docs/kit/types#app.d.ts // for information about these interfaces declare global { @@ -9,7 +10,9 @@ declare global { caches: CacheStorage; cf?: IncomingRequestCfProperties } + interface Locals { user?: User; session?: Session } + // interface Error {} // interface PageData {} // interface PageState {} diff --git a/packages/sv/src/cli/tests/snapshots/create-experimental/src/lib/server/db/schema.ts b/packages/sv/src/cli/tests/snapshots/create-experimental/src/lib/server/db/schema.ts index 74eb9ddbf..35de29be6 100644 --- a/packages/sv/src/cli/tests/snapshots/create-experimental/src/lib/server/db/schema.ts +++ b/packages/sv/src/cli/tests/snapshots/create-experimental/src/lib/server/db/schema.ts @@ -5,4 +5,5 @@ export const task = sqliteTable('task', { title: text('title').notNull(), priority: integer('priority').notNull().default(1) }); + export * from './auth.schema'; diff --git a/packages/sv/src/cli/tests/snapshots/create-experimental/vite.config.ts b/packages/sv/src/cli/tests/snapshots/create-experimental/vite.config.ts index 60c7bfb22..ed92d13b0 100644 --- a/packages/sv/src/cli/tests/snapshots/create-experimental/vite.config.ts +++ b/packages/sv/src/cli/tests/snapshots/create-experimental/vite.config.ts @@ -10,7 +10,6 @@ export default defineConfig({ runes: ({ filename }) => filename.split(/[/\\]/).includes('node_modules') ? undefined : true }, - adapter: adapter(), experimental: { explicitEnvironmentVariables: true }, typescript: { diff --git a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/.env.example b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/.env.example index 6bb40ccbe..34a24e9fe 100644 --- a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/.env.example +++ b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/.env.example @@ -1,6 +1,8 @@ # Drizzle DATABASE_URL=file:local.db + ORIGIN="" + # Better Auth # For production use 32 characters and generated with high entropy # https://www.better-auth.com/docs/installation diff --git a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/app.d.ts b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/app.d.ts index f4734f616..7a2a5d2e4 100644 --- a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/app.d.ts +++ b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/app.d.ts @@ -1,9 +1,11 @@ import type { User, Session } from 'better-auth'; + // See https://svelte.dev/docs/kit/types#app.d.ts // for information about these interfaces declare global { namespace App { interface Locals { user?: User; session?: Session } + // interface Error {} // interface PageData {} // interface PageState {} diff --git a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/hooks.server.ts b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/hooks.server.ts index 167ed2bdb..f0872bb70 100644 --- a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/hooks.server.ts +++ b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/hooks.server.ts @@ -16,10 +16,13 @@ const handleParaglide: Handle = ({ event, resolve }) => paraglideMiddleware(even const handleBetterAuth: Handle = async ({ event, resolve }) => { const session = await auth.api.getSession({ headers: event.request.headers }); + if (session) { event.locals.session = session.session; event.locals.user = session.user; } + return svelteKitHandler({ event, resolve, auth, building }); }; + export const handle: Handle = sequence(handleParaglide, handleBetterAuth); diff --git a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/lib/server/db/schema.ts b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/lib/server/db/schema.ts index 74eb9ddbf..35de29be6 100644 --- a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/lib/server/db/schema.ts +++ b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/lib/server/db/schema.ts @@ -5,4 +5,5 @@ export const task = sqliteTable('task', { title: text('title').notNull(), priority: integer('priority').notNull().default(1) }); + export * from './auth.schema'; diff --git a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/routes/+layout.svelte b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/routes/+layout.svelte index d3dabe29a..0f0a134b4 100644 --- a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/routes/+layout.svelte +++ b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/routes/+layout.svelte @@ -14,6 +14,7 @@ {@render children()} +