diff --git a/README.md b/README.md index 815eb90..9270487 100644 --- a/README.md +++ b/README.md @@ -29,23 +29,6 @@ A powerful, customizable diff-match-patch component for Svelte with TypeScript s - πŸ” Real-time diff updates - 🎯 Expected patterns β€” mark dynamic regions (dates, names) as "expected" instead of diffs -## Recent Updates - -### New Features - -- Expected patterns β€” use named regex capture groups to mark dynamic regions as "expected" instead of diffs -- Added detailed timing information for diff operations -- Enhanced cleanup algorithms for better diff results -- Improved performance for large text comparisons -- Added TypeScript types for all component props and events -- Implemented proper state management with Svelte 5 runes - -### Testing Improvements - -- Enhanced Playwright E2E test coverage -- Added comprehensive tests for cleanup algorithms -- Improved test reliability with proper component mounting checks - ## Installation ```bash @@ -75,9 +58,9 @@ My animation's comical, unusual, and whimsical, I'm quite adept at funny gags, comedic theory I have read, From wicked puns and stupid jokes to anvils that drop on your head.`) - const onProcessing = (timing, diff) => { + const onProcessing = (timing, diffs) => { console.log('Diff timing:', timing) - console.log('Diff result:', diff) + console.log('Diff result:', diffs) } @@ -116,17 +99,22 @@ import type { SvelteDiffTiming, SvelteDiffTuple, SvelteDiffProps } from '@humans ## Props -| Prop | Type | Default | Description | -| ----------------- | ---------- | ------- | ---------------------------------------------- | -| originalText | `string` | - | The original text to compare against | -| modifiedText | `string` | - | The modified text to compare with original | -| timeout | `number` | 1 | Timeout in seconds for diff computation | -| cleanupSemantic | `boolean` | false | Enable semantic cleanup for better readability | -| cleanupEfficiency | `number` | 4 | Efficiency cleanup level (0-4) | -| compact | `boolean` | true | Render unstyled equal text without spans | -| onProcessing | `function` | - | Callback for timing and diff information | -| rendererClasses | `object` | - | CSS classes for diff highlighting | -| renderers | `object` | - | Custom Svelte snippets for rendering | +| Prop | Type | Default | Description | +| ------------------- | --------------------------- | ---------- | ------------------------------------------------------------------------------------- | +| `originalText` | `string` | _required_ | The original (before/source) text to compare | +| `modifiedText` | `string` | _required_ | The modified (after/target) text to compare | +| `timeout` | `number` | `1` | Max diff computation time in seconds; `0` is unlimited | +| `cleanupSemantic` | `boolean` | `false` | Optimize edit boundaries for human readability | +| `cleanupEfficiency` | `number` | `4` | Edit cost used by efficiency cleanup; `0` disables it | +| `compact` | `boolean` | `true` | Render unstyled equal text without wrapper spans; `false` restores legacy equal spans | +| `onProcessing` | `function` | β€” | Receives `(timing, diffs, captures?)` after each computation | +| `rendererClasses` | `RendererClasses` | `{}` | CSS classes for the built-in `remove`/`insert`/`equal`/`expected` spans | +| `renderers` | `Partial` | `{}` | Snippet map for individual segment types | +| `remove` | `Snippet<[string]>` | β€” | Child snippet for removed text (wins over `renderers.remove`) | +| `insert` | `Snippet<[string]>` | β€” | Child snippet for inserted text (wins over `renderers.insert`) | +| `equal` | `Snippet<[string]>` | β€” | Child snippet for unchanged text (wins over `renderers.equal`) | +| `expected` | `Snippet<[string, string]>` | β€” | Child snippet for expected values, receiving `(text, groupName)` | +| `lineBreak` | `Snippet<[]>` | β€” | Child snippet rendered between lines | ## Custom Rendering with Snippets @@ -273,6 +261,28 @@ The `onProcessing` callback receives captured values as its third argument: If no capture groups are present in `originalText`, the component behaves exactly as before β€” no changes needed to existing code. +## Programmatic API + +The expected-pattern engine is also exported as framework-agnostic functions, so you can compute matches and tag diffs without mounting the component: + +```typescript +import { + parseExpectedPatterns, + extractCaptures, + tagExpectedRegions, + cleanTemplate +} from '@humanspeak/svelte-diff' +``` + +| Function | Signature | Description | +| ----------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `parseExpectedPatterns` | `(text) => ParseResult \| null` | Parse and compile `(?pattern)` named groups from a template. Returns `null` when the text contains no named groups. | +| `extractCaptures` | `(originalText, modifiedText, parseResult) => ExtractResult \| null` | Extract captured values and their positions from the modified text. Returns `null` when the template does not match. | +| `tagExpectedRegions` | `(diffs, captureRanges) => DisplayDiff[]` | Split raw diff tuples so regions overlapping a capture range are tagged as `expected`. | +| `cleanTemplate` | `(text) => string` | Replace `(?pattern)` syntax with readable `` placeholders. | + +These are the same functions the component uses internally; see [`src/lib/expectedPatterns.ts`](src/lib/expectedPatterns.ts) for full JSDoc. + ## Events The component emits a `processing` event with timing and diff information: @@ -281,10 +291,10 @@ The component emits a `processing` event with timing and diff information: diff --git a/docs/.gitignore b/docs/.gitignore index 12d7df3..8270c3d 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -27,3 +27,13 @@ vite.config.ts.timestamp-* # Sentry Config File .env.sentry-build-plugin + +# Generated by @humanspeak/docs-kit vite plugins at build time +src/lib/sitemap-manifest.json +src/lib/demo-manifest.json +src/lib/demo-loaders.ts +src/lib/demo-virtual.d.ts +/static/docs/ +/static/examples/ +/static/examples.md +/static/social-cards/ diff --git a/docs/src/lib/demo-loaders.ts b/docs/src/lib/demo-loaders.ts deleted file mode 100644 index a40dc43..0000000 --- a/docs/src/lib/demo-loaders.ts +++ /dev/null @@ -1,100 +0,0 @@ -/* This file is generated by docs-kit demoManifestPlugin({ split: true }). */ - -import type { DemoManifestEntry } from '@humanspeak/docs-kit' - -export type DemoCodeLoader = () => Promise<{ default: DemoManifestEntry }> - -export const demoCodeLoaders = { - 'basic-diff/demos/BasicDiff.svelte': () => import('virtual:docs-kit/demo/basic-diff/demos/BasicDiff.svelte'), - 'cleanup-modes/demos/CleanupModes.svelte': () => import('virtual:docs-kit/demo/cleanup-modes/demos/CleanupModes.svelte'), - 'custom-snippets/demos/CustomSnippets.svelte': () => import('virtual:docs-kit/demo/custom-snippets/demos/CustomSnippets.svelte'), - 'expected-patterns/demos/ExpectedPatterns.svelte': () => import('virtual:docs-kit/demo/expected-patterns/demos/ExpectedPatterns.svelte'), - 'live-editor/demos/LiveEditor.svelte': () => import('virtual:docs-kit/demo/live-editor/demos/LiveEditor.svelte'), - 'timing/demos/Timing.svelte': () => import('virtual:docs-kit/demo/timing/demos/Timing.svelte'), -} satisfies Record - -export type DemoCodeLoaderKey = keyof typeof demoCodeLoaders - -export const demoCodeDependencies: Partial> = { -} - -export interface DemoCodeSample { - /** Stable identifier rendered in the code reference header. */ - id: string - /** Human-readable sample label rendered next to the identifier. */ - label: string - /** Lazy loader for the pre-highlighted demo source module. */ - load: () => Promise<{ default: DemoManifestEntry }> - /** Optional override for docs-kit's idle preload behavior. */ - preload?: 'idle' | false -} - -/** - * Builds a lazy `CodeReferenceV2` sample from docs-kit's generated demo source key. - * - * @param key - Demo path emitted by `demoManifestPlugin({ split: true })`. - * @param id - Stable sample identifier rendered in the code panel. - * @param label - Human-readable file label rendered in the code panel. - * @param preload - Optional override for docs-kit's idle preload behavior. - * @returns A lazy code sample compatible with docs-kit's `CodeReferenceV2`. - */ -export function demoCodeSample( - key: DemoCodeLoaderKey, - id: string, - label: string, - preload?: 'idle' | false -): DemoCodeSample { - const sample: DemoCodeSample = { - id, - label, - load: demoCodeLoaders[key] - } - - if (preload !== undefined) { - sample.preload = preload - } - - return sample -} - -function demoCodeLabelForKey(key: DemoCodeLoaderKey): string { - return key.split('/').pop() ?? key -} - -function demoCodeIdForKey(baseId: string, key: DemoCodeLoaderKey, index: number): string { - if (index === 0) return baseId - const fileName = demoCodeLabelForKey(key).replace(/\.svelte$/, '') - const slug = fileName - .replace(/([a-z0-9])([A-Z])/g, '$1-$2') - .replace(/[^a-zA-Z0-9]+/g, '-') - .replace(/^-|-$/g, '') - .toLowerCase() - return `${baseId}-${slug || index}` -} - -/** - * Builds lazy `CodeReferenceV2` samples for a demo entrypoint and every - * co-located `.svelte` component imported by that demo. - * - * @param key - Demo path emitted by `demoManifestPlugin({ split: true })`. - * @param id - Stable sample identifier for the demo entrypoint. - * @param label - Human-readable file label for the demo entrypoint. - * @param preload - Optional override for docs-kit's idle preload behavior. - * @returns Lazy code samples for the demo followed by local component dependencies. - */ -export function demoCodeSamples( - key: DemoCodeLoaderKey, - id: string, - label: string, - preload?: 'idle' | false -): DemoCodeSample[] { - const keys = [key, ...(demoCodeDependencies[key] ?? [])] - return keys.map((sampleKey, index) => - demoCodeSample( - sampleKey, - demoCodeIdForKey(id, sampleKey, index), - index === 0 ? label : demoCodeLabelForKey(sampleKey), - preload - ) - ) -} diff --git a/docs/src/lib/demo-manifest.json b/docs/src/lib/demo-manifest.json deleted file mode 100644 index 0e4583f..0000000 --- a/docs/src/lib/demo-manifest.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "basic-diff/demos/BasicDiff.svelte": { - "importPath": "virtual:docs-kit/demo/basic-diff/demos/BasicDiff.svelte", - "codeBytes": 1629, - "htmlBytes": 23535 - }, - "cleanup-modes/demos/CleanupModes.svelte": { - "importPath": "virtual:docs-kit/demo/cleanup-modes/demos/CleanupModes.svelte", - "codeBytes": 2259, - "htmlBytes": 29429 - }, - "custom-snippets/demos/CustomSnippets.svelte": { - "importPath": "virtual:docs-kit/demo/custom-snippets/demos/CustomSnippets.svelte", - "codeBytes": 1409, - "htmlBytes": 22266 - }, - "expected-patterns/demos/ExpectedPatterns.svelte": { - "importPath": "virtual:docs-kit/demo/expected-patterns/demos/ExpectedPatterns.svelte", - "codeBytes": 2569, - "htmlBytes": 38916 - }, - "live-editor/demos/LiveEditor.svelte": { - "importPath": "virtual:docs-kit/demo/live-editor/demos/LiveEditor.svelte", - "codeBytes": 2632, - "htmlBytes": 37957 - }, - "timing/demos/Timing.svelte": { - "importPath": "virtual:docs-kit/demo/timing/demos/Timing.svelte", - "codeBytes": 2608, - "htmlBytes": 44021 - } -} diff --git a/docs/src/lib/demo-virtual.d.ts b/docs/src/lib/demo-virtual.d.ts deleted file mode 100644 index 548bb90..0000000 --- a/docs/src/lib/demo-virtual.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* This file is generated by docs-kit demoManifestPlugin({ split: true }). */ - -declare module 'virtual:docs-kit/demo/*' { - interface DemoManifestEntry { - code: string - lang: string - html?: { light: string; dark: string } - } - - const entry: DemoManifestEntry - export default entry -} diff --git a/docs/src/lib/sitemap-manifest.json b/docs/src/lib/sitemap-manifest.json deleted file mode 100644 index 4a5e1c0..0000000 --- a/docs/src/lib/sitemap-manifest.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "/": "2026-07-17", - "/compare": "2026-07-17", - "/docs/api/svelte-diff": "2026-07-17", - "/docs/api/types": "2026-07-17", - "/docs/getting-started": "2026-07-17", - "/docs/guides/cleanup": "2026-07-17", - "/docs/guides/custom-rendering": "2026-07-17", - "/docs/guides/expected-patterns": "2026-07-17", - "/docs/guides/performance": "2026-07-17", - "/docs/migration": "2026-07-17", - "/examples": "2026-07-17", - "/examples/basic-diff": "2026-07-17", - "/examples/cleanup-modes": "2026-07-17", - "/examples/custom-snippets": "2026-07-17", - "/examples/expected-patterns": "2026-07-17", - "/examples/live-editor": "2026-07-17", - "/examples/timing": "2026-07-17", - "/compare/vs-jsdiff": "2026-07-17", - "/compare/vs-diff-match-patch": "2026-07-17", - "/compare/vs-diff2html": "2026-07-17" -} diff --git a/docs/static/docs/api-svelte-diff.md b/docs/static/docs/api-svelte-diff.md deleted file mode 100644 index d2c52ad..0000000 --- a/docs/static/docs/api-svelte-diff.md +++ /dev/null @@ -1,110 +0,0 @@ - - -# SvelteDiff API - -> Complete SvelteDiff component API including props, renderer precedence, callbacks, and defaults. - -**Source:** [https://diff.svelte.page/docs/api/svelte-diff](https://diff.svelte.page/docs/api/svelte-diff) - ---- - -The package exports the component as both the default export and a named export. - -```svelte - -``` - -## Props - -| Prop | Type | Default | Purpose | -|---|---|---:|---| -| `originalText` | `string` | required | The before/source text | -| `modifiedText` | `string` | required | The after/target text | -| `timeout` | `number` | `1` | Maximum diff computation time in seconds; `0` is unlimited | -| `cleanupSemantic` | `boolean` | `false` | Optimize edit boundaries for human readability | -| `cleanupEfficiency` | `number` | `4` | Edit cost used by efficiency cleanup; `0` disables it | -| `compact` | `boolean` | `true` | Render unstyled equal text without wrapper spans; `false` restores legacy equal spans | -| `onProcessing` | `function` | β€” | Receive timing, raw tuples, and optional captures | -| `rendererClasses` | `RendererClasses` | `{}` | Classes for built-in segment spans | -| `renderers` | `Partial` | `{}` | Snippet map for individual segment types | -| `remove` | `Snippet<[string]>` | β€” | Direct child snippet for removed text | -| `insert` | `Snippet<[string]>` | β€” | Direct child snippet for inserted text | -| `equal` | `Snippet<[string]>` | β€” | Direct child snippet for unchanged text | -| `expected` | `Snippet<[string, string]>` | β€” | Direct child snippet for expected values | -| `lineBreak` | `Snippet<[]>` | β€” | Direct child snippet between lines | - -## Cleanup precedence - -The component computes a raw diff, then runs at most one cleanup pass: - -1. If `cleanupSemantic` is `true`, semantic cleanup runs. -2. Otherwise, if `cleanupEfficiency > 0`, efficiency cleanup runs with that value as the edit cost. -3. Otherwise, the raw diff is rendered. - -## Renderer precedence - -Resolution happens independently for every segment type: - -1. A direct child snippet such as `{#snippet insert(text)}` -2. The matching property in `renderers` -3. The built-in fallback - -For unchanged text, the default compact fallback emits text directly when no equal class or -renderer is configured. Set `compact={false}` to restore the legacy equal ``. Removed, -inserted, expected, and customized equal segments retain their normal elements. - -That means you can override one type and leave all others on their defaults. - -```svelte - - {#snippet insert(text: string)} - + {text} - {/snippet} - -``` - -## `onProcessing` - -The callback runs after computation and cleanup. - -```svelte - - - -``` - -Timing values are milliseconds measured with `performance.now()`. - -## Expected patterns - -If `originalText` contains named capture groups, the component tries to match those regions in `modifiedText` and renders successful matches as `expected` instead of additions/removals. - -```svelte -v\\d+\\.\\d+\\.\\d+)'} - modifiedText="Release v2.4.1" -/> -``` - -The group name is passed to the expected snippet and its matched value appears in the callback's `captures` object. - -## Deprecated aliases - -`SvelteDiffMatchPatch` and the `SvelteDiffMatchPatch*` type names remain available for compatibility. New code should use `SvelteDiff` and the shorter `SvelteDiff*` types. diff --git a/docs/static/docs/api-types.md b/docs/static/docs/api-types.md deleted file mode 100644 index a88865d..0000000 --- a/docs/static/docs/api-types.md +++ /dev/null @@ -1,100 +0,0 @@ - - -# Types and Exports - -> Public components, callbacks, renderer maps, tuples, and expected-pattern types exported by @humanspeak/svelte-diff. - -**Source:** [https://diff.svelte.page/docs/api/types](https://diff.svelte.page/docs/api/types) - ---- - -# Types & Exports - -Everything public is exported from the package root. - -```typescript -import SvelteDiff, { - SvelteDiff as NamedSvelteDiff, - type SvelteDiffProps, - type SvelteDiffTiming, - type SvelteDiffTuple, - type Renderers, - type RendererClasses, - type CaptureRange, - type DisplayDiff, - type PatternMatchResult -} from '@humanspeak/svelte-diff' -``` - -## Components - -| Export | Notes | -|---|---| -| `default` | The `SvelteDiff` component | -| `SvelteDiff` | Named export of the same component | -| `SvelteDiffMatchPatch` | Deprecated compatibility alias | - -## `SvelteDiffTiming` - -```typescript -type SvelteDiffTiming = { - main: number - cleanup: number - total: number -} -``` - -All values are milliseconds. `main` measures the core algorithm, `cleanup` measures the selected cleanup pass, and `total` covers both. - -## `SvelteDiffTuple` - -An alias for `Diff` from `diff-match-patch-ts`. Each tuple is an operation and its text: - -```typescript -type SvelteDiffTuple = [operation: -1 | 0 | 1, text: string] -``` - -- `-1` β€” removed -- `0` β€” equal -- `1` β€” inserted - -## `Renderers` - -```typescript -type Renderers = { - remove?: Snippet<[string]> - equal?: Snippet<[string]> - insert?: Snippet<[string]> - expected?: Snippet<[string, string]> - lineBreak?: Snippet<[]> -} -``` - -The expected renderer receives both the matched text and its named capture-group name. - -## `RendererClasses` - -```typescript -type RendererClasses = { - remove?: string - equal?: string - insert?: string - expected?: string -} -``` - -Classes only affect built-in fallbacks. When you replace a segment with a snippet, that snippet owns its own classes. - -## Expected-pattern types - -`CaptureRange` describes a named match inside the modified string. `DisplayDiff` is an internal-rendering-shaped segment that may carry an `expected` group name. `PatternMatchResult` combines resolved template text, captured values, and capture ranges. - -```typescript -interface PatternMatchResult { - resolvedText: string - captures: Record - captureRanges: CaptureRange[] -} -``` - -These are exported for integrations that want to share the component's expected-region concepts without duplicating type definitions. diff --git a/docs/static/docs/getting-started.md b/docs/static/docs/getting-started.md deleted file mode 100644 index 3d95d52..0000000 --- a/docs/static/docs/getting-started.md +++ /dev/null @@ -1,101 +0,0 @@ - - -# Getting Started - -> Install @humanspeak/svelte-diff and render a readable, reactive text diff in Svelte 5. - -**Source:** [https://diff.svelte.page/docs/getting-started](https://diff.svelte.page/docs/getting-started) - ---- - -`@humanspeak/svelte-diff` is a focused Svelte 5 component for comparing two strings. It runs the diff-match-patch algorithm, optionally cleans the result for readability, and renders each change as real Svelte markup. - -## Installation - -```bash -npm install @humanspeak/svelte-diff -``` - -```bash -pnpm add @humanspeak/svelte-diff -``` - -## Your first diff - -```svelte - - -

- -

-``` - -By default, removed text is red with a strike-through, inserted text is green, and unchanged text -is unstyled. Unstyled unchanged text uses compact DOM without wrapper spans; pass -`compact={false}` when migrating selectors or styles that require the legacy equal spans. Text is -escaped by Svelte; the component does not inject an HTML string. - -## Reactive inputs - -Both required props are reactive. If either string changes, the component recomputes the diff. - -```svelte - - - - - - -``` - -## Recommended readable defaults - -For prose and user-facing copy, semantic cleanup is usually the best starting point: - -```svelte - -``` - -For machine-like strings where every small edit matters, keep semantic cleanup off and use the default efficiency cleanup. - -## Styling with classes - -Use `rendererClasses` when you want to keep the default `` markup: - -```svelte - -``` - -Use child snippets when you need different elements, attributes, icons, or animation. See [Custom Rendering](/docs/guides/custom-rendering). - -## Next steps - -- [SvelteDiff API](/docs/api/svelte-diff) β€” every prop and precedence rule -- [Expected Patterns](/docs/guides/expected-patterns) β€” separate intentional variation from real changes -- [Cleanup Modes](/docs/guides/cleanup) β€” choose semantic, efficiency, or raw output -- [Interactive Examples](/examples) β€” edit values and inspect real output -- [Comparisons](/compare) β€” decide between this component and lower-level diff tools diff --git a/docs/static/docs/guides-cleanup.md b/docs/static/docs/guides-cleanup.md deleted file mode 100644 index e93b784..0000000 --- a/docs/static/docs/guides-cleanup.md +++ /dev/null @@ -1,66 +0,0 @@ - - -# Cleanup Modes - -> Choose semantic cleanup, efficiency cleanup, or raw diff output for the right balance of readability and fidelity. - -**Source:** [https://diff.svelte.page/docs/guides/cleanup](https://diff.svelte.page/docs/guides/cleanup) - ---- - -The core algorithm finds a valid sequence of edits. Cleanup passes reorganize that sequence without changing the final text. - -## Semantic cleanup - -```svelte - -``` - -Semantic cleanup shifts edit boundaries toward natural-looking word and phrase boundaries. Use it for prose, review screens, changelogs, and other output read by people. - -It may produce a slightly larger edit than the mathematically smallest diff if that edit is easier to understand. - -## Efficiency cleanup - -```svelte - -``` - -Efficiency cleanup removes operationally trivial equalities. The number becomes the algorithm's edit-cost setting. `4` is the component default. - -Higher values make small equal regions more likely to be absorbed into surrounding edits. Lower values preserve more fine-grained equalities. - -## Raw output - -Disable both cleanup paths when exact algorithm output matters: - -```svelte - -``` - -## Precedence - -Semantic cleanup wins when enabled. The component does not run semantic and efficiency cleanup in sequence. - -| Configuration | Cleanup pass | -|---|---| -| `cleanupSemantic={true}` | semantic | -| `cleanupSemantic={false}`, `cleanupEfficiency={4}` | efficiency | -| `cleanupSemantic={false}`, `cleanupEfficiency={0}` | none | - -## Choosing a mode - -- Use **semantic** for prose and human review. -- Use **efficiency** for compact technical diffs and a balanced default. -- Use **raw** when consuming the rendered segmentation as a debugging aid or comparing it with another diff implementation. - -Open the [cleanup modes example](/examples/cleanup-modes) to see all three render the same input side by side. diff --git a/docs/static/docs/guides-custom-rendering.md b/docs/static/docs/guides-custom-rendering.md deleted file mode 100644 index 96dee5b..0000000 --- a/docs/static/docs/guides-custom-rendering.md +++ /dev/null @@ -1,105 +0,0 @@ - - -# Custom Rendering - -> Style SvelteDiff with semantic classes or replace individual diff segments with Svelte 5 snippets. - -**Source:** [https://diff.svelte.page/docs/guides/custom-rendering](https://diff.svelte.page/docs/guides/custom-rendering) - ---- - -SvelteDiff offers two customization levels. `rendererClasses` preserves the built-in markup and changes its classes. Snippets replace the markup itself. - -## Class-based styling - -```svelte - -``` - -```css -:global(.change--removed) { - background: #fee2e2; - color: #991b1b; - text-decoration: line-through; -} - -:global(.change--inserted) { - background: #dcfce7; - color: #166534; -} - -:global(.change--expected) { - background: #dbeafe; - border-bottom: 1px dashed #2563eb; -} -``` - -The classes are applied only to the built-in `` for that segment. A missing class falls back to the component's inline default for removed, inserted, or expected text. - -## Direct child snippets - -Use snippets when semantic HTML or richer UI matters: - -```svelte - - {#snippet remove(text: string)} - {text} - {/snippet} - - {#snippet insert(text: string)} - {text} - {/snippet} - - {#snippet expected(text: string, groupName: string)} - {text} - {/snippet} - - {#snippet lineBreak()} -
- {/snippet} -
-``` - -## Renderer maps - -Snippets can also be assembled into a `renderers` object. This is useful when a design system owns reusable diff renderers. - -```svelte -{#snippet removed(text: string)}{text}{/snippet} -{#snippet inserted(text: string)}{text}{/snippet} - - -``` - -## Mixing strategies - -Resolution is per type. A direct `insert` snippet can coexist with `renderers.remove`; equal text can still use the built-in fallback. - -```svelte - - {#snippet insert(text: string)} - {text} - {/snippet} - -``` - -The direct child snippet wins for `insert`. The renderer map is used for `remove`. Everything else falls back to built-in rendering. - -## Line breaks - -The component splits multiline segments and calls `lineBreak` between lines. Override it when your output needs block separation, line numbers, or accessible separators. - -Keep `white-space: pre-wrap` on the surrounding output if preserving other whitespace matters. diff --git a/docs/static/docs/guides-expected-patterns.md b/docs/static/docs/guides-expected-patterns.md deleted file mode 100644 index 6d7de4d..0000000 --- a/docs/static/docs/guides-expected-patterns.md +++ /dev/null @@ -1,87 +0,0 @@ - - -# Expected Patterns - -> Mark intentional dynamic text such as dates, names, IDs, and versions as expected instead of noisy changes. - -**Source:** [https://diff.svelte.page/docs/guides/expected-patterns](https://diff.svelte.page/docs/guides/expected-patterns) - ---- - -Snapshots, generated files, invoices, and release notes often contain values that are supposed to change. Expected patterns let you label those regions separately instead of showing them as ordinary red/green edits. - -## Named capture syntax - -Put JavaScript-style named capture groups directly in `originalText`: - -```svelte -v\\d+\\.\\d+\\.\\d+) on (?\\d{4}-\\d{2}-\\d{2})'} - modifiedText="Release v2.4.1 on 2026-07-17" -/> -``` - -The version and date render as `expected`. Their names and values are also available to rendering and callback code. - -## Access captured values - -```svelte - - - { - captures = nextCaptures ?? {} - }} -/> - -
{JSON.stringify(captures, null, 2)}
-``` - -## Custom expected markup - -```svelte - - {#snippet expected(text: string, groupName: string)} - - {text} - - {/snippet} - -``` - -## Flexible context matching - -Patterns are matched using literal text around each named group as context. Extra content between the context and capture is tolerated. This is useful when the actual text adds punctuation or labels that the template does not include. - -```text -Template: Copyright (?\d{4}) (?.+) -Actual: Copyright (c) 2026 Humanspeak, Inc. -``` - -`2026` and `Humanspeak, Inc.` can still be identified as the expected values while `(c)` remains a real insertion. - -## Failure behavior - -If the capture groups do not match, SvelteDiff cleans the template before computing the normal diff. Instead of exposing regex syntax to readers, it replaces each named group with a readable placeholder such as ``. - -If `originalText` contains no named groups, the component follows the ordinary diff path with no extra matching work. - -## Pattern safety - -Named groups are discovered with an iterative parenthesis-counting parser rather than a backtracking regex. Escaped parentheses and nested non-named groups are supported. Nested named groups are rejected to keep group ownership unambiguous. - -The pattern body is still compiled as JavaScript regular expression syntax. Treat patterns as trusted configuration, not untrusted user input. - -## Good uses - -- Timestamps in snapshots -- Generated IDs and build numbers -- Copyright years and holders -- Package versions in release output -- User names or environment-specific paths - -Expected patterns are not a general ignore system: successful values stay visible, receive their own styling, and remain available through `captures`. diff --git a/docs/static/docs/guides-performance.md b/docs/static/docs/guides-performance.md deleted file mode 100644 index 730cc37..0000000 --- a/docs/static/docs/guides-performance.md +++ /dev/null @@ -1,93 +0,0 @@ - - -# Timing and Performance - -> Measure SvelteDiff computation and cleanup time, set timeouts, and avoid unnecessary work with large inputs. - -**Source:** [https://diff.svelte.page/docs/guides/performance](https://diff.svelte.page/docs/guides/performance) - ---- - -# Timing & Performance - -SvelteDiff computes whenever `originalText`, `modifiedText`, or a cleanup option changes. The `onProcessing` callback exposes the cost of that work. - -## Compact equal-text DOM - -`compact` defaults to `true`. Unstyled built-in equal segments render as text instead of -wrapper spans, reducing DOM weight without changing text content or intrinsic line breaks when no -selectors or styles depend on the legacy wrapper. Custom equal snippets, `renderers.equal`, and -`rendererClasses.equal` retain their requested markup. - -Use the legacy DOM only when existing selectors or styles require equal spans: - -```svelte - - - -``` - -## Measure a diff - -```svelte - - - (timing = nextTiming)} -/> - -
-
Core algorithm
{timing.main.toFixed(2)} ms
-
Cleanup
{timing.cleanup.toFixed(2)} ms
-
Total
{timing.total.toFixed(2)} ms
-
-``` - -## Timeout - -`timeout` is measured in seconds and maps to the underlying diff-match-patch timeout. - -```svelte - -``` - -The default is one second. Use `0` for no time limit. An unlimited timeout can be appropriate for controlled offline inputs, but is a poor default for arbitrary user content on the main thread. - -The algorithm returns the best diff it has when the deadline is reached; timeout is not reported as an exception. - -## Reactive input guidance - -For large editor documents, debounce text input before updating the values passed to SvelteDiff. This keeps typing responsive and avoids recomputing intermediate states the reader never sees. - -```typescript -let timer: ReturnType - -function scheduleDiff(value: string) { - clearTimeout(timer) - timer = setTimeout(() => { - modifiedText = value - }, 200) -} -``` - -## Cleanup cost - -`timing.cleanup` includes whichever cleanup pass was selected. Semantic cleanup generally does more readability work than efficiency cleanup. Measure with representative data instead of assuming the faster choice. - -## Scope - -The component performs character-level text diffing and renders the result. It does not virtualize large output, move computation to a worker, or expose incremental diff computation. For extremely large documents, consider preprocessing by line or using a specialized editor diff engine. - -Use the [timing example](/examples/timing) to edit inputs and watch the callback values update. diff --git a/docs/static/docs/migration.md b/docs/static/docs/migration.md deleted file mode 100644 index f1e1199..0000000 --- a/docs/static/docs/migration.md +++ /dev/null @@ -1,96 +0,0 @@ - - -# Migration Guide - -> Migrate from the previous SvelteDiffMatchPatch name or a hand-built diff rendering loop to SvelteDiff. - -**Source:** [https://diff.svelte.page/docs/migration](https://diff.svelte.page/docs/migration) - ---- - -## 0.3.x to 0.4.0: compact equal text by default - -Starting in 0.4.0, `compact` defaults to `true`. Unstyled built-in equal text no longer receives -unstyled wrapper `` elements. Text content and intrinsic line breaks are unchanged when no -selectors or styles depend on the legacy wrapper, and custom equal snippets, `renderers.equal`, -and `rendererClasses.equal` keep their requested markup. - -If application CSS, tests, or DOM queries depend on the former equal spans, opt out while -migrating: - -```svelte - - - -``` - -Remove the opt-out after replacing selectors and styles that depend on unstyled equal `` -elements. - -## From `SvelteDiffMatchPatch` - -The component was renamed to `SvelteDiff`. The old export remains as a deprecated alias, so migration can be incremental. - -```diff -- import { SvelteDiffMatchPatch } from '@humanspeak/svelte-diff' -+ import { SvelteDiff } from '@humanspeak/svelte-diff' - -- -+ -``` - -The default import already resolves to `SvelteDiff`: - -```svelte - -``` - -Rename deprecated types the same way: - -| Deprecated | Current | -|---|---| -| `SvelteDiffMatchPatchProps` | `SvelteDiffProps` | -| `SvelteDiffMatchPatchTiming` | `SvelteDiffTiming` | -| `SvelteDiffMatchPatchDiff` | `SvelteDiffTuple` | - -## From a custom `diff-match-patch` loop - -A typical manual integration configures an instance, calls `diff_main`, runs cleanup, and maps operations to markup. SvelteDiff owns that wiring. - -```svelte - { - console.log({ timing, diffs }) - }} -/> -``` - -Move your operation-specific markup into `remove`, `insert`, and `equal` snippets. If your old implementation needs fuzzy matching or patch application, keep the lower-level library for that workβ€”SvelteDiff deliberately exposes only the rendered text-diff use case. - -## Callback field names - -Current timing fields are `main`, `cleanup`, and `total`, all in milliseconds. Avoid older examples that refer to `computeTime` or `cleanupTime`. - -## Expected patterns - -Expected patterns are opt-in. Existing plain strings behave exactly as before. Only `originalText` values containing valid named capture groups activate expected-region matching. - -## Verify the migration - -1. Confirm both strings update reactively. -2. Compare cleanup mode output on representative documents. -3. Check custom snippets per segment type. -4. Update callback code to the current timing fields. -5. Add expected patterns only where variation is genuinely intentional. diff --git a/docs/static/examples.md b/docs/static/examples.md deleted file mode 100644 index c5102a2..0000000 --- a/docs/static/examples.md +++ /dev/null @@ -1,22 +0,0 @@ - - -# Interactive Examples - -> Live demos mirrored as markdown with runnable Svelte source for LLMs and agents. - -**Source:** [https://diff.svelte.page/examples](https://diff.svelte.page/examples) - -**Markdown mirror:** [https://diff.svelte.page/examples.md](https://diff.svelte.page/examples.md) - ---- - -Each linked mirror includes the live page description, section notes, and fenced source for the demo components used on that page. - -## Examples - -- [Basic Diff](https://diff.svelte.page/examples/basic-diff.md) - Render a readable Svelte 5 text diff with two strings, semantic cleanup, and class-based styling. (live: [https://diff.svelte.page/examples/basic-diff](https://diff.svelte.page/examples/basic-diff), tag: `START`) -- [Live Editor](https://diff.svelte.page/examples/live-editor.md) - Edit before and after text and watch SvelteDiff recompute semantic output reactively. (live: [https://diff.svelte.page/examples/live-editor](https://diff.svelte.page/examples/live-editor), tag: `REACTIVE`) -- [Expected Patterns](https://diff.svelte.page/examples/expected-patterns.md) - Match dynamic versions, dates, and names as expected values and inspect captured groups live. (live: [https://diff.svelte.page/examples/expected-patterns](https://diff.svelte.page/examples/expected-patterns), tag: `PATTERNS`) -- [Custom Snippets](https://diff.svelte.page/examples/custom-snippets.md) - Replace SvelteDiff fallback spans with semantic del and ins elements using Svelte 5 snippets. (live: [https://diff.svelte.page/examples/custom-snippets](https://diff.svelte.page/examples/custom-snippets), tag: `RENDERING`) -- [Cleanup Modes](https://diff.svelte.page/examples/cleanup-modes.md) - Compare raw, efficiency-cleaned, and semantic diff output for the same before and after strings. (live: [https://diff.svelte.page/examples/cleanup-modes](https://diff.svelte.page/examples/cleanup-modes), tag: `READABILITY`) -- [Timing](https://diff.svelte.page/examples/timing.md) - Scale a generated text diff and inspect core algorithm, cleanup, total time, and segment counts. (live: [https://diff.svelte.page/examples/timing](https://diff.svelte.page/examples/timing), tag: `PERFORMANCE`) diff --git a/docs/static/examples/basic-diff.md b/docs/static/examples/basic-diff.md deleted file mode 100644 index 7828fcd..0000000 --- a/docs/static/examples/basic-diff.md +++ /dev/null @@ -1,65 +0,0 @@ - - -# Basic Diff - -> Render a readable Svelte 5 text diff with two strings, semantic cleanup, and class-based styling. - -**Source:** [https://diff.svelte.page/examples/basic-diff](https://diff.svelte.page/examples/basic-diff) - -**Markdown mirror:** [https://diff.svelte.page/examples/basic-diff.md](https://diff.svelte.page/examples/basic-diff.md) - ---- - -This mirror preserves the prose, implementation notes, and runnable Svelte source behind the live example page. - -## FIG-001: basic diff. - -Start with two plain strings and let `SvelteDiff` own the comparison. Semantic cleanup makes the result readable while stable classes provide the styling hooks. - -**Metadata:** tag: `START` | cleanup: `semantic` | rendering: `classes` - -### Source - -#### BasicDiff.svelte - -Source file: [src/lib/examples/basic-diff/demos/BasicDiff.svelte](https://github.com/humanspeak/svelte-diff/blob/main/docs/src/lib/examples/basic-diff/demos/BasicDiff.svelte) - -```svelte - - -
-
- removed - inserted -
-
- -
-
- - -``` diff --git a/docs/static/examples/cleanup-modes.md b/docs/static/examples/cleanup-modes.md deleted file mode 100644 index f441b1a..0000000 --- a/docs/static/examples/cleanup-modes.md +++ /dev/null @@ -1,48 +0,0 @@ - - -# Cleanup Modes - -> Compare raw, efficiency-cleaned, and semantic diff output for the same before and after strings. - -**Source:** [https://diff.svelte.page/examples/cleanup-modes](https://diff.svelte.page/examples/cleanup-modes) - -**Markdown mirror:** [https://diff.svelte.page/examples/cleanup-modes.md](https://diff.svelte.page/examples/cleanup-modes.md) - ---- - -This mirror preserves the prose, implementation notes, and runnable Svelte source behind the live example page. - -## FIG-001: cleanup modes. - -One edit can have several valid segmentations. Compare raw, efficiency-cleaned, and semantic output for the same input before choosing a default. - -**Metadata:** tag: `READABILITY` | modes: `3` | input: `identical` - -### Source - -#### CleanupModes.svelte - -Source file: [src/lib/examples/cleanup-modes/demos/CleanupModes.svelte](https://github.com/humanspeak/svelte-diff/blob/main/docs/src/lib/examples/cleanup-modes/demos/CleanupModes.svelte) - -```svelte - - -
-

raw / no cleanup

-

efficiency / cost 4

-

semantic / readable

-
- - -``` diff --git a/docs/static/examples/custom-snippets.md b/docs/static/examples/custom-snippets.md deleted file mode 100644 index 1a0a2d2..0000000 --- a/docs/static/examples/custom-snippets.md +++ /dev/null @@ -1,57 +0,0 @@ - - -# Custom Snippets - -> Replace SvelteDiff fallback spans with semantic del and ins elements using Svelte 5 snippets. - -**Source:** [https://diff.svelte.page/examples/custom-snippets](https://diff.svelte.page/examples/custom-snippets) - -**Markdown mirror:** [https://diff.svelte.page/examples/custom-snippets.md](https://diff.svelte.page/examples/custom-snippets.md) - ---- - -This mirror preserves the prose, implementation notes, and runnable Svelte source behind the live example page. - -## FIG-001: custom snippets. - -Direct Svelte 5 snippets replace the fallback renderer one segment at a time. Own the markup you need while every omitted segment keeps its default behavior. - -**Metadata:** tag: `RENDERING` | markup: `del + ins` | precedence: `child first` - -### Source - -#### CustomSnippets.svelte - -Source file: [src/lib/examples/custom-snippets/demos/CustomSnippets.svelte](https://github.com/humanspeak/svelte-diff/blob/main/docs/src/lib/examples/custom-snippets/demos/CustomSnippets.svelte) - -```svelte - - -
- - {#snippet remove(text: string)} - {text} - {/snippet} - {#snippet insert(text: string)} - {text} - {/snippet} - {#snippet equal(text: string)} - {text} - {/snippet} - -
- - -``` diff --git a/docs/static/examples/expected-patterns.md b/docs/static/examples/expected-patterns.md deleted file mode 100644 index 57a0dd4..0000000 --- a/docs/static/examples/expected-patterns.md +++ /dev/null @@ -1,73 +0,0 @@ - - -# Expected Patterns - -> Match dynamic versions, dates, and names as expected values and inspect captured groups live. - -**Source:** [https://diff.svelte.page/examples/expected-patterns](https://diff.svelte.page/examples/expected-patterns) - -**Markdown mirror:** [https://diff.svelte.page/examples/expected-patterns.md](https://diff.svelte.page/examples/expected-patterns.md) - ---- - -This mirror preserves the prose, implementation notes, and runnable Svelte source behind the live example page. - -## FIG-001: expected values. - -Named patterns distinguish intentional dynamic values from genuine edits. Successful matches get expected styling and structured captures; invalid formats remain visible as normal diffs. - -**Metadata:** tag: `PATTERNS` | groups: `3 named` | callback: `captures` - -### Source - -#### ExpectedPatterns.svelte - -Source file: [src/lib/examples/expected-patterns/demos/ExpectedPatterns.svelte](https://github.com/humanspeak/svelte-diff/blob/main/docs/src/lib/examples/expected-patterns/demos/ExpectedPatterns.svelte) - -```svelte - - -
- -
-
-
rendered diff
-
- (captures = next ?? {})} - rendererClasses={{ - remove: 'diff-remove', - insert: 'diff-insert', - equal: 'diff-equal', - expected: 'diff-expected' - }} - /> -
-
-
-
captures
-
{JSON.stringify(captures, null, 2)}
-
-
-
- - -``` diff --git a/docs/static/examples/live-editor.md b/docs/static/examples/live-editor.md deleted file mode 100644 index 0901f89..0000000 --- a/docs/static/examples/live-editor.md +++ /dev/null @@ -1,68 +0,0 @@ - - -# Live Editor - -> Edit before and after text and watch SvelteDiff recompute semantic output reactively. - -**Source:** [https://diff.svelte.page/examples/live-editor](https://diff.svelte.page/examples/live-editor) - -**Markdown mirror:** [https://diff.svelte.page/examples/live-editor.md](https://diff.svelte.page/examples/live-editor.md) - ---- - -This mirror preserves the prose, implementation notes, and runnable Svelte source behind the live example page. - -## FIG-001: live editor. - -Two rune-backed textareas feed `SvelteDiff` directly. Edit either document and normal Svelte reactivity produces the next comparison without an imperative recompute call. - -**Metadata:** tag: `REACTIVE` | inputs: `reactive` | cleanup: `semantic` - -### Source - -#### LiveEditor.svelte - -Source file: [src/lib/examples/live-editor/demos/LiveEditor.svelte](https://github.com/humanspeak/svelte-diff/blob/main/docs/src/lib/examples/live-editor/demos/LiveEditor.svelte) - -```svelte - - -
-
- - -
-
output / semantic
-
- -
-
- - -``` diff --git a/docs/static/examples/timing.md b/docs/static/examples/timing.md deleted file mode 100644 index 273ecfa..0000000 --- a/docs/static/examples/timing.md +++ /dev/null @@ -1,64 +0,0 @@ - - -# Timing - -> Scale a generated text diff and inspect core algorithm, cleanup, total time, and segment counts. - -**Source:** [https://diff.svelte.page/examples/timing](https://diff.svelte.page/examples/timing) - -**Markdown mirror:** [https://diff.svelte.page/examples/timing.md](https://diff.svelte.page/examples/timing.md) - ---- - -This mirror preserves the prose, implementation notes, and runnable Svelte source behind the live example page. - -## FIG-001: processing timing. - -The `onProcessing` callback reports core diff time, cleanup time, total time, and final tuples together. Scale the generated documents to profile realistic content. - -**Metadata:** tag: `PERFORMANCE` | callback: `onProcessing` | unit: `ms` - -### Source - -#### Timing.svelte - -Source file: [src/lib/examples/timing/demos/Timing.svelte](https://github.com/humanspeak/svelte-diff/blob/main/docs/src/lib/examples/timing/demos/Timing.svelte) - -```svelte - - -
- -
-
main{timing.main.toFixed(3)} ms
-
cleanup{timing.cleanup.toFixed(3)} ms
-
total{timing.total.toFixed(3)} ms
-
segments{segmentCount}
-
-
-
- - -``` diff --git a/docs/static/social-cards/og-compare-vs-diff-match-patch.png b/docs/static/social-cards/og-compare-vs-diff-match-patch.png deleted file mode 100644 index 9538851..0000000 Binary files a/docs/static/social-cards/og-compare-vs-diff-match-patch.png and /dev/null differ diff --git a/docs/static/social-cards/og-compare-vs-diff2html.png b/docs/static/social-cards/og-compare-vs-diff2html.png deleted file mode 100644 index 956cefc..0000000 Binary files a/docs/static/social-cards/og-compare-vs-diff2html.png and /dev/null differ diff --git a/docs/static/social-cards/og-compare-vs-jsdiff.png b/docs/static/social-cards/og-compare-vs-jsdiff.png deleted file mode 100644 index d6b8643..0000000 Binary files a/docs/static/social-cards/og-compare-vs-jsdiff.png and /dev/null differ diff --git a/docs/static/social-cards/og-compare.png b/docs/static/social-cards/og-compare.png deleted file mode 100644 index ac97e87..0000000 Binary files a/docs/static/social-cards/og-compare.png and /dev/null differ diff --git a/docs/static/social-cards/og-docs-api-svelte-diff.png b/docs/static/social-cards/og-docs-api-svelte-diff.png deleted file mode 100644 index 61ebbee..0000000 Binary files a/docs/static/social-cards/og-docs-api-svelte-diff.png and /dev/null differ diff --git a/docs/static/social-cards/og-docs-api-types.png b/docs/static/social-cards/og-docs-api-types.png deleted file mode 100644 index 8432315..0000000 Binary files a/docs/static/social-cards/og-docs-api-types.png and /dev/null differ diff --git a/docs/static/social-cards/og-docs-getting-started.png b/docs/static/social-cards/og-docs-getting-started.png deleted file mode 100644 index 1247957..0000000 Binary files a/docs/static/social-cards/og-docs-getting-started.png and /dev/null differ diff --git a/docs/static/social-cards/og-docs-guides-cleanup.png b/docs/static/social-cards/og-docs-guides-cleanup.png deleted file mode 100644 index cf9f6ea..0000000 Binary files a/docs/static/social-cards/og-docs-guides-cleanup.png and /dev/null differ diff --git a/docs/static/social-cards/og-docs-guides-custom-rendering.png b/docs/static/social-cards/og-docs-guides-custom-rendering.png deleted file mode 100644 index 42f92f3..0000000 Binary files a/docs/static/social-cards/og-docs-guides-custom-rendering.png and /dev/null differ diff --git a/docs/static/social-cards/og-docs-guides-expected-patterns.png b/docs/static/social-cards/og-docs-guides-expected-patterns.png deleted file mode 100644 index 2584e97..0000000 Binary files a/docs/static/social-cards/og-docs-guides-expected-patterns.png and /dev/null differ diff --git a/docs/static/social-cards/og-docs-guides-performance.png b/docs/static/social-cards/og-docs-guides-performance.png deleted file mode 100644 index 70e85b8..0000000 Binary files a/docs/static/social-cards/og-docs-guides-performance.png and /dev/null differ diff --git a/docs/static/social-cards/og-docs-migration.png b/docs/static/social-cards/og-docs-migration.png deleted file mode 100644 index e2ed088..0000000 Binary files a/docs/static/social-cards/og-docs-migration.png and /dev/null differ diff --git a/docs/static/social-cards/og-examples-basic-diff.png b/docs/static/social-cards/og-examples-basic-diff.png deleted file mode 100644 index 2ae73e4..0000000 Binary files a/docs/static/social-cards/og-examples-basic-diff.png and /dev/null differ diff --git a/docs/static/social-cards/og-examples-cleanup-modes.png b/docs/static/social-cards/og-examples-cleanup-modes.png deleted file mode 100644 index 6160e2b..0000000 Binary files a/docs/static/social-cards/og-examples-cleanup-modes.png and /dev/null differ diff --git a/docs/static/social-cards/og-examples-custom-snippets.png b/docs/static/social-cards/og-examples-custom-snippets.png deleted file mode 100644 index 06a2c4a..0000000 Binary files a/docs/static/social-cards/og-examples-custom-snippets.png and /dev/null differ diff --git a/docs/static/social-cards/og-examples-expected-patterns.png b/docs/static/social-cards/og-examples-expected-patterns.png deleted file mode 100644 index 939fcad..0000000 Binary files a/docs/static/social-cards/og-examples-expected-patterns.png and /dev/null differ diff --git a/docs/static/social-cards/og-examples-live-editor.png b/docs/static/social-cards/og-examples-live-editor.png deleted file mode 100644 index 753cdd7..0000000 Binary files a/docs/static/social-cards/og-examples-live-editor.png and /dev/null differ diff --git a/docs/static/social-cards/og-examples-timing.png b/docs/static/social-cards/og-examples-timing.png deleted file mode 100644 index f318eec..0000000 Binary files a/docs/static/social-cards/og-examples-timing.png and /dev/null differ diff --git a/docs/static/social-cards/og-examples.png b/docs/static/social-cards/og-examples.png deleted file mode 100644 index a5cb48f..0000000 Binary files a/docs/static/social-cards/og-examples.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-compare-vs-diff-match-patch.png b/docs/static/social-cards/twitter-compare-vs-diff-match-patch.png deleted file mode 100644 index b2aeaae..0000000 Binary files a/docs/static/social-cards/twitter-compare-vs-diff-match-patch.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-compare-vs-diff2html.png b/docs/static/social-cards/twitter-compare-vs-diff2html.png deleted file mode 100644 index 5ea8d42..0000000 Binary files a/docs/static/social-cards/twitter-compare-vs-diff2html.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-compare-vs-jsdiff.png b/docs/static/social-cards/twitter-compare-vs-jsdiff.png deleted file mode 100644 index 5d296b2..0000000 Binary files a/docs/static/social-cards/twitter-compare-vs-jsdiff.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-compare.png b/docs/static/social-cards/twitter-compare.png deleted file mode 100644 index 1051aee..0000000 Binary files a/docs/static/social-cards/twitter-compare.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-docs-api-svelte-diff.png b/docs/static/social-cards/twitter-docs-api-svelte-diff.png deleted file mode 100644 index d45d1f9..0000000 Binary files a/docs/static/social-cards/twitter-docs-api-svelte-diff.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-docs-api-types.png b/docs/static/social-cards/twitter-docs-api-types.png deleted file mode 100644 index 37b098f..0000000 Binary files a/docs/static/social-cards/twitter-docs-api-types.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-docs-getting-started.png b/docs/static/social-cards/twitter-docs-getting-started.png deleted file mode 100644 index 8e1a758..0000000 Binary files a/docs/static/social-cards/twitter-docs-getting-started.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-docs-guides-cleanup.png b/docs/static/social-cards/twitter-docs-guides-cleanup.png deleted file mode 100644 index 25ff6d3..0000000 Binary files a/docs/static/social-cards/twitter-docs-guides-cleanup.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-docs-guides-custom-rendering.png b/docs/static/social-cards/twitter-docs-guides-custom-rendering.png deleted file mode 100644 index 677a319..0000000 Binary files a/docs/static/social-cards/twitter-docs-guides-custom-rendering.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-docs-guides-expected-patterns.png b/docs/static/social-cards/twitter-docs-guides-expected-patterns.png deleted file mode 100644 index 3771ebe..0000000 Binary files a/docs/static/social-cards/twitter-docs-guides-expected-patterns.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-docs-guides-performance.png b/docs/static/social-cards/twitter-docs-guides-performance.png deleted file mode 100644 index 41efc74..0000000 Binary files a/docs/static/social-cards/twitter-docs-guides-performance.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-docs-migration.png b/docs/static/social-cards/twitter-docs-migration.png deleted file mode 100644 index 936ed60..0000000 Binary files a/docs/static/social-cards/twitter-docs-migration.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-examples-basic-diff.png b/docs/static/social-cards/twitter-examples-basic-diff.png deleted file mode 100644 index ea5f48d..0000000 Binary files a/docs/static/social-cards/twitter-examples-basic-diff.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-examples-cleanup-modes.png b/docs/static/social-cards/twitter-examples-cleanup-modes.png deleted file mode 100644 index 6701e99..0000000 Binary files a/docs/static/social-cards/twitter-examples-cleanup-modes.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-examples-custom-snippets.png b/docs/static/social-cards/twitter-examples-custom-snippets.png deleted file mode 100644 index f091466..0000000 Binary files a/docs/static/social-cards/twitter-examples-custom-snippets.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-examples-expected-patterns.png b/docs/static/social-cards/twitter-examples-expected-patterns.png deleted file mode 100644 index 61afb69..0000000 Binary files a/docs/static/social-cards/twitter-examples-expected-patterns.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-examples-live-editor.png b/docs/static/social-cards/twitter-examples-live-editor.png deleted file mode 100644 index db98cb8..0000000 Binary files a/docs/static/social-cards/twitter-examples-live-editor.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-examples-timing.png b/docs/static/social-cards/twitter-examples-timing.png deleted file mode 100644 index 6f7ddfa..0000000 Binary files a/docs/static/social-cards/twitter-examples-timing.png and /dev/null differ diff --git a/docs/static/social-cards/twitter-examples.png b/docs/static/social-cards/twitter-examples.png deleted file mode 100644 index aac72a7..0000000 Binary files a/docs/static/social-cards/twitter-examples.png and /dev/null differ diff --git a/src/lib/expectedPatterns.ts b/src/lib/expectedPatterns.ts index dd0982c..878c67e 100644 --- a/src/lib/expectedPatterns.ts +++ b/src/lib/expectedPatterns.ts @@ -67,15 +67,34 @@ interface CompiledLinePattern { regex: RegExp } -interface ParseResult { +/** + * Compiled result of parsing named capture groups from a template. + * + * Returned by {@link parseExpectedPatterns}; carries the immutable metadata + * reused by {@link extractCaptures} for repeated extraction against modified text. + */ +export interface ParseResult { + /** + * @internal Engine detail β€” not part of the stable public API; may change in + * any future release. Parsed capture groups in source order. + */ groups: ParsedGroup[] - /** Literal text and full group syntax interleaved in source order. */ + /** + * @internal Engine detail β€” not part of the stable public API; may change in + * any future release. Literal text and full group syntax interleaved in source order. + */ parts: string[] - /** Ordered source matches retained from the single template scan. */ + /** + * @internal Engine detail β€” not part of the stable public API; may change in + * any future release. Ordered source matches retained from the single template scan. + */ matches: GroupMatch[] /** Template text with named groups replaced by readable placeholders. */ cleanedText: string - /** Ordered, compiled extraction plans for lines containing named groups. */ + /** + * @internal Engine detail β€” not part of the stable public API; may change in + * any future release. Ordered, compiled extraction plans for lines containing named groups. + */ linePatterns: CompiledLinePattern[] } @@ -372,7 +391,12 @@ export const cleanTemplate = (text: string): string => { return cleanedText + text.slice(lastIndex) } -interface ExtractResult { +/** + * Result of extracting capture values and positions from modified text. + * + * Returned by {@link extractCaptures} when every compiled line pattern matches. + */ +export interface ExtractResult { resolvedText: string captures: Record captureRangesInText2: CaptureRange[] diff --git a/src/lib/index.test.ts b/src/lib/index.test.ts index 8bf5f84..9dbf45d 100644 --- a/src/lib/index.test.ts +++ b/src/lib/index.test.ts @@ -1,6 +1,10 @@ import SvelteDiffDefault, { + cleanTemplate, + extractCaptures, + parseExpectedPatterns, SvelteDiff, SvelteDiffMatchPatch, + tagExpectedRegions, type CaptureRange, type DisplayDiff, type PatternMatchResult, @@ -84,6 +88,13 @@ describe('index exports', () => { expect(expectedDiff).toBeDefined() }) + it('should re-export the expected-pattern engine functions', () => { + expect(typeof parseExpectedPatterns).toBe('function') + expect(typeof extractCaptures).toBe('function') + expect(typeof tagExpectedRegions).toBe('function') + expect(typeof cleanTemplate).toBe('function') + }) + it('should export PatternMatchResult type', () => { const result: PatternMatchResult = { resolvedText: 'hello', @@ -92,4 +103,30 @@ describe('index exports', () => { } expect(result).toBeDefined() }) + + it('should export ParseResult type', () => { + const parse: import('./index.js').ParseResult = { + groups: [{ name: 'year', pattern: '\\d{4}' }], + parts: ['', '(?\\d{4})', ''], + matches: [{ fullMatch: '(?\\d{4})', name: 'year', pattern: '\\d{4}', index: 0 }], + cleanedText: '', + linePatterns: [ + { + lineText: '(?\\d{4})', + groups: [{ name: 'year', pattern: '\\d{4}', indexInLine: 0 }], + regex: /(?\d{4})/d + } + ] + } + expect(parse).toBeDefined() + }) + + it('should export ExtractResult type', () => { + const result: import('./index.js').ExtractResult = { + resolvedText: '2024', + captures: { year: '2024' }, + captureRangesInText2: [{ name: 'year', start: 0, end: 4 }] + } + expect(result).toBeDefined() + }) }) diff --git a/src/lib/index.ts b/src/lib/index.ts index e6408b2..20d7c36 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -11,7 +11,19 @@ export { SvelteDiff } * be removed in a future major version. */ export const SvelteDiffMatchPatch = SvelteDiff -export type { CaptureRange, DisplayDiff, PatternMatchResult } from './expectedPatterns.js' +export { + cleanTemplate, + extractCaptures, + parseExpectedPatterns, + tagExpectedRegions +} from './expectedPatterns.js' +export type { + CaptureRange, + DisplayDiff, + ExtractResult, + ParseResult, + PatternMatchResult +} from './expectedPatterns.js' /** * Custom Svelte 5 snippets for rendering each diff segment type. *