From e7ed9f574070dc271f9661af5e53e0df798c36b8 Mon Sep 17 00:00:00 2001 From: Hugos68 Date: Sun, 7 Jun 2026 14:43:20 +0200 Subject: [PATCH 01/14] add cut around markup --- packages/twoslash-svelte/src/index.ts | 61 +++++++++++++++++++ .../test/fixtures/cut-around-markup.svelte | 14 +++++ .../cut-around-shorthand-markup.svelte | 13 ++++ .../test/fixtures/cut-around-shorthand.svelte | 12 ++++ .../test/fixtures/cut-in-markup.svelte | 14 +++++ .../test/results/cut-around-markup.json | 24 ++++++++ .../results/cut-around-shorthand-markup.json | 24 ++++++++ .../test/results/cut-around-shorthand.json | 24 ++++++++ .../test/results/cut-in-markup.json | 24 ++++++++ 9 files changed, 210 insertions(+) create mode 100644 packages/twoslash-svelte/test/fixtures/cut-around-markup.svelte create mode 100644 packages/twoslash-svelte/test/fixtures/cut-around-shorthand-markup.svelte create mode 100644 packages/twoslash-svelte/test/fixtures/cut-around-shorthand.svelte create mode 100644 packages/twoslash-svelte/test/fixtures/cut-in-markup.svelte create mode 100644 packages/twoslash-svelte/test/results/cut-around-markup.json create mode 100644 packages/twoslash-svelte/test/results/cut-around-shorthand-markup.json create mode 100644 packages/twoslash-svelte/test/results/cut-around-shorthand.json create mode 100644 packages/twoslash-svelte/test/results/cut-in-markup.json diff --git a/packages/twoslash-svelte/src/index.ts b/packages/twoslash-svelte/src/index.ts index 35ef19ac..1854a6db 100644 --- a/packages/twoslash-svelte/src/index.ts +++ b/packages/twoslash-svelte/src/index.ts @@ -148,8 +148,69 @@ export function createTwoslasher(createOptions: CreateTwoslashSvelteOptions = {} }) .filter(value => value != null) + function findMarkupRemovals(code: string): Range[] { + const ranges: Range[] = [] + const cutRe = //g + const cutBeforeRe = //g + const cutAfterRe = //g + const cutStartRe = //g + const cutEndRe = //g + + const cuts = [...code.matchAll(cutRe)] + const cutBefores = [...code.matchAll(cutBeforeRe)] + const cutAfters = [...code.matchAll(cutAfterRe)] + const cutStarts = [...code.matchAll(cutStartRe)] + const cutEnds = [...code.matchAll(cutEndRe)] + + for (const match of cuts) { + const lineStart = code.lastIndexOf('\n', match.index! - 1) + 1 + ranges.push([0, lineStart + match[0].length + 1]) + } + + for (let i = 0; i < cutBefores.length; i++) { + const match = cutBefores[i] + const afterMatch = cutAfters[i] + if (afterMatch) { + const lineStart = code.lastIndexOf('\n', afterMatch.index! - 1) + 1 + ranges.push([match.index!, lineStart + afterMatch[0].length + 1]) + } + else { + ranges.push([match.index!, code.length]) + } + } + + for (let i = cutBefores.length; i < cutAfters.length; i++) { + const match = cutAfters[i] + const lineStart = code.lastIndexOf('\n', match.index! - 1) + 1 + ranges.push([0, lineStart + match[0].length + 1]) + } + + for (let i = 0; i < cutStarts.length; i++) { + const startMatch = cutStarts[i] + const endMatch = cutEnds[i] + if (endMatch) { + const endLineStart = code.lastIndexOf('\n', endMatch.index! - 1) + 1 + ranges.push([startMatch.index!, endLineStart + endMatch[0].length + 1]) + } + else { + throw new Error( + `Mismatched HTML cut markers: cut-start at position ${startMatch.index!} has no matching cut-end`, + ) + } + } + + if (cutEnds.length > cutStarts.length) { + throw new Error( + `Mismatched HTML cut markers: more cut-end markers than cut-start markers`, + ) + } + + return ranges + } + const mappedRemovals = [ ...sourceMeta.removals, + ...findMarkupRemovals(code), ...result.meta.removals.map((r) => { const start = get(map.toSourceLocation(r[0]), 0)?.[0] ?? code.match(/(?<=\s)/)?.index const end = get(map.toSourceLocation(r[1]), 0)?.[0] diff --git a/packages/twoslash-svelte/test/fixtures/cut-around-markup.svelte b/packages/twoslash-svelte/test/fixtures/cut-around-markup.svelte new file mode 100644 index 00000000..549676c8 --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/cut-around-markup.svelte @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/cut-around-shorthand-markup.svelte b/packages/twoslash-svelte/test/fixtures/cut-around-shorthand-markup.svelte new file mode 100644 index 00000000..fbbb7c4c --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/cut-around-shorthand-markup.svelte @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/cut-around-shorthand.svelte b/packages/twoslash-svelte/test/fixtures/cut-around-shorthand.svelte new file mode 100644 index 00000000..550f5e1b --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/cut-around-shorthand.svelte @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/cut-in-markup.svelte b/packages/twoslash-svelte/test/fixtures/cut-in-markup.svelte new file mode 100644 index 00000000..3b91070d --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/cut-in-markup.svelte @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/cut-around-markup.json b/packages/twoslash-svelte/test/results/cut-around-markup.json new file mode 100644 index 00000000..efb6966b --- /dev/null +++ b/packages/twoslash-svelte/test/results/cut-around-markup.json @@ -0,0 +1,24 @@ +{ + "code": "\n", + "nodes": [ + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 18, + "length": 9, + "target": "increment", + "line": 1, + "character": 17 + }, + { + "type": "hover", + "text": "let count: number", + "start": 45, + "length": 5, + "target": "count", + "line": 2, + "character": 15 + } + ], + "flags": [] +} \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/cut-around-shorthand-markup.json b/packages/twoslash-svelte/test/results/cut-around-shorthand-markup.json new file mode 100644 index 00000000..efb6966b --- /dev/null +++ b/packages/twoslash-svelte/test/results/cut-around-shorthand-markup.json @@ -0,0 +1,24 @@ +{ + "code": "\n", + "nodes": [ + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 18, + "length": 9, + "target": "increment", + "line": 1, + "character": 17 + }, + { + "type": "hover", + "text": "let count: number", + "start": 45, + "length": 5, + "target": "count", + "line": 2, + "character": 15 + } + ], + "flags": [] +} \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/cut-around-shorthand.json b/packages/twoslash-svelte/test/results/cut-around-shorthand.json new file mode 100644 index 00000000..32dee51f --- /dev/null +++ b/packages/twoslash-svelte/test/results/cut-around-shorthand.json @@ -0,0 +1,24 @@ +{ + "code": "\n\n", + "nodes": [ + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 37, + "length": 9, + "target": "increment", + "line": 3, + "character": 17 + }, + { + "type": "hover", + "text": "let count: number", + "start": 64, + "length": 5, + "target": "count", + "line": 4, + "character": 15 + } + ], + "flags": [] +} \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/cut-in-markup.json b/packages/twoslash-svelte/test/results/cut-in-markup.json new file mode 100644 index 00000000..efb6966b --- /dev/null +++ b/packages/twoslash-svelte/test/results/cut-in-markup.json @@ -0,0 +1,24 @@ +{ + "code": "\n", + "nodes": [ + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 18, + "length": 9, + "target": "increment", + "line": 1, + "character": 17 + }, + { + "type": "hover", + "text": "let count: number", + "start": 45, + "length": 5, + "target": "count", + "line": 2, + "character": 15 + } + ], + "flags": [] +} \ No newline at end of file From 76a606e9ea03f219f3bf23c5f3aedf4d5b36581e Mon Sep 17 00:00:00 2001 From: Hugos68 Date: Sun, 7 Jun 2026 17:52:14 +0200 Subject: [PATCH 02/14] move func out --- packages/twoslash-svelte/src/index.ts | 120 +++++++++++++------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/packages/twoslash-svelte/src/index.ts b/packages/twoslash-svelte/src/index.ts index 1854a6db..fb1ce375 100644 --- a/packages/twoslash-svelte/src/index.ts +++ b/packages/twoslash-svelte/src/index.ts @@ -148,66 +148,6 @@ export function createTwoslasher(createOptions: CreateTwoslashSvelteOptions = {} }) .filter(value => value != null) - function findMarkupRemovals(code: string): Range[] { - const ranges: Range[] = [] - const cutRe = //g - const cutBeforeRe = //g - const cutAfterRe = //g - const cutStartRe = //g - const cutEndRe = //g - - const cuts = [...code.matchAll(cutRe)] - const cutBefores = [...code.matchAll(cutBeforeRe)] - const cutAfters = [...code.matchAll(cutAfterRe)] - const cutStarts = [...code.matchAll(cutStartRe)] - const cutEnds = [...code.matchAll(cutEndRe)] - - for (const match of cuts) { - const lineStart = code.lastIndexOf('\n', match.index! - 1) + 1 - ranges.push([0, lineStart + match[0].length + 1]) - } - - for (let i = 0; i < cutBefores.length; i++) { - const match = cutBefores[i] - const afterMatch = cutAfters[i] - if (afterMatch) { - const lineStart = code.lastIndexOf('\n', afterMatch.index! - 1) + 1 - ranges.push([match.index!, lineStart + afterMatch[0].length + 1]) - } - else { - ranges.push([match.index!, code.length]) - } - } - - for (let i = cutBefores.length; i < cutAfters.length; i++) { - const match = cutAfters[i] - const lineStart = code.lastIndexOf('\n', match.index! - 1) + 1 - ranges.push([0, lineStart + match[0].length + 1]) - } - - for (let i = 0; i < cutStarts.length; i++) { - const startMatch = cutStarts[i] - const endMatch = cutEnds[i] - if (endMatch) { - const endLineStart = code.lastIndexOf('\n', endMatch.index! - 1) + 1 - ranges.push([startMatch.index!, endLineStart + endMatch[0].length + 1]) - } - else { - throw new Error( - `Mismatched HTML cut markers: cut-start at position ${startMatch.index!} has no matching cut-end`, - ) - } - } - - if (cutEnds.length > cutStarts.length) { - throw new Error( - `Mismatched HTML cut markers: more cut-end markers than cut-start markers`, - ) - } - - return ranges - } - const mappedRemovals = [ ...sourceMeta.removals, ...findMarkupRemovals(code), @@ -338,3 +278,63 @@ function generateSourceMap( } return new SourceMap(mappings) } + +function findMarkupRemovals(code: string): Range[] { + const ranges: Range[] = [] + const cutRe = //g + const cutBeforeRe = //g + const cutAfterRe = //g + const cutStartRe = //g + const cutEndRe = //g + + const cuts = [...code.matchAll(cutRe)] + const cutBefores = [...code.matchAll(cutBeforeRe)] + const cutAfters = [...code.matchAll(cutAfterRe)] + const cutStarts = [...code.matchAll(cutStartRe)] + const cutEnds = [...code.matchAll(cutEndRe)] + + for (const match of cuts) { + const lineStart = code.lastIndexOf('\n', match.index! - 1) + 1 + ranges.push([0, lineStart + match[0].length + 1]) + } + + for (let i = 0; i < cutBefores.length; i++) { + const match = cutBefores[i] + const afterMatch = cutAfters[i] + if (afterMatch) { + const lineStart = code.lastIndexOf('\n', afterMatch.index! - 1) + 1 + ranges.push([match.index!, lineStart + afterMatch[0].length + 1]) + } + else { + ranges.push([match.index!, code.length]) + } + } + + for (let i = cutBefores.length; i < cutAfters.length; i++) { + const match = cutAfters[i] + const lineStart = code.lastIndexOf('\n', match.index! - 1) + 1 + ranges.push([0, lineStart + match[0].length + 1]) + } + + for (let i = 0; i < cutStarts.length; i++) { + const startMatch = cutStarts[i] + const endMatch = cutEnds[i] + if (endMatch) { + const endLineStart = code.lastIndexOf('\n', endMatch.index! - 1) + 1 + ranges.push([startMatch.index!, endLineStart + endMatch[0].length + 1]) + } + else { + throw new Error( + `Mismatched HTML cut markers: cut-start at position ${startMatch.index!} has no matching cut-end`, + ) + } + } + + if (cutEnds.length > cutStarts.length) { + throw new Error( + `Mismatched HTML cut markers: more cut-end markers than cut-start markers`, + ) + } + + return ranges +} From 657ac71da85afecc79ad93e4c2fcdc2c70b1098f Mon Sep 17 00:00:00 2001 From: Hugos68 Date: Sun, 7 Jun 2026 19:40:51 +0200 Subject: [PATCH 03/14] update --- packages/twoslash-svelte/package.json | 2 + packages/twoslash-svelte/src/index.ts | 112 +++++++++++------- .../test/fixtures/cut-around-markup.svelte | 14 --- .../cut-around-shorthand-markup.svelte | 13 -- .../test/fixtures/cut-around-shorthand.svelte | 12 -- .../test/fixtures/cut-around.svelte | 13 -- .../test/fixtures/cut-in-markup.svelte | 14 --- .../test/fixtures/cut-in.svelte | 13 -- .../test/results/cut-around-markup.json | 24 ---- .../results/cut-around-shorthand-markup.json | 24 ---- .../test/results/cut-around-shorthand.json | 24 ---- .../test/results/cut-around.json | 24 ---- .../test/results/cut-in-markup.json | 24 ---- .../twoslash-svelte/test/results/cut-in.json | 53 --------- pnpm-lock.yaml | 9 ++ pnpm-workspace.yaml | 1 + 16 files changed, 82 insertions(+), 294 deletions(-) delete mode 100644 packages/twoslash-svelte/test/fixtures/cut-around-markup.svelte delete mode 100644 packages/twoslash-svelte/test/fixtures/cut-around-shorthand-markup.svelte delete mode 100644 packages/twoslash-svelte/test/fixtures/cut-around-shorthand.svelte delete mode 100644 packages/twoslash-svelte/test/fixtures/cut-around.svelte delete mode 100644 packages/twoslash-svelte/test/fixtures/cut-in-markup.svelte delete mode 100644 packages/twoslash-svelte/test/fixtures/cut-in.svelte delete mode 100644 packages/twoslash-svelte/test/results/cut-around-markup.json delete mode 100644 packages/twoslash-svelte/test/results/cut-around-shorthand-markup.json delete mode 100644 packages/twoslash-svelte/test/results/cut-around-shorthand.json delete mode 100644 packages/twoslash-svelte/test/results/cut-around.json delete mode 100644 packages/twoslash-svelte/test/results/cut-in-markup.json delete mode 100644 packages/twoslash-svelte/test/results/cut-in.json diff --git a/packages/twoslash-svelte/package.json b/packages/twoslash-svelte/package.json index b9f82608..e0569dd2 100644 --- a/packages/twoslash-svelte/package.json +++ b/packages/twoslash-svelte/package.json @@ -46,12 +46,14 @@ "start": "esno src/index.ts" }, "peerDependencies": { + "svelte": ">=5", "svelte2tsx": "*", "typescript": "*" }, "dependencies": { "@jridgewell/sourcemap-codec": "catalog:", "@volar/language-core": "catalog:", + "estree-walker": "catalog:", "twoslash": "workspace:*", "twoslash-protocol": "workspace:*" }, diff --git a/packages/twoslash-svelte/src/index.ts b/packages/twoslash-svelte/src/index.ts index fb1ce375..5901421a 100644 --- a/packages/twoslash-svelte/src/index.ts +++ b/packages/twoslash-svelte/src/index.ts @@ -1,10 +1,14 @@ import type { CodeMapping } from '@volar/language-core' +import type { Node } from 'estree-walker' +import type { AST } from 'svelte/compiler' import type { CompilerOptionDeclaration, CreateTwoslashOptions, HandbookOptions, Range, TwoslashExecuteOptions, TwoslashInstance, TwoslashReturnMeta } from 'twoslash' import { createRequire } from 'node:module' import { join } from 'node:path' import { decode } from '@jridgewell/sourcemap-codec' import { SourceMap } from '@volar/language-core' +import { walk } from 'estree-walker' import { svelte2tsx } from 'svelte2tsx' +import { parse } from 'svelte/compiler' import { createTwoslasher as _createTwoSlasher, defaultCompilerOptions, defaultHandbookOptions, findFlagNotations, findQueryMarkers } from 'twoslash' import { createPositionConverter, removeCodeRanges, resolveNodePositions } from 'twoslash-protocol' import ts from 'typescript' @@ -148,6 +152,8 @@ export function createTwoslasher(createOptions: CreateTwoslashSvelteOptions = {} }) .filter(value => value != null) + const ast = parse(strippedCode, { modern: true }) + const mappedRemovals = [ ...sourceMeta.removals, ...findMarkupRemovals(code), @@ -157,7 +163,7 @@ export function createTwoslasher(createOptions: CreateTwoslashSvelteOptions = {} if (start == null || end == null || start < 0 || end < 0 || start >= end) { return undefined } - return [start, end] as Range + return clampRemovalToScriptBoundaries(start, end, ast) as Range | undefined }).filter(value => value != null), ] @@ -280,57 +286,46 @@ function generateSourceMap( } function findMarkupRemovals(code: string): Range[] { + const ast = parse(code, { modern: true }) + + const comments: Array<{ start: number, end: number, data: string }> = [] + walk(ast as unknown as Node, { + enter(node: AST.SvelteNode) { + if (node.type === 'Comment') { + comments.push({ start: node.start, end: node.end, data: node.data.trim() }) + } + }, + }) + const ranges: Range[] = [] - const cutRe = //g - const cutBeforeRe = //g - const cutAfterRe = //g - const cutStartRe = //g - const cutEndRe = //g - - const cuts = [...code.matchAll(cutRe)] - const cutBefores = [...code.matchAll(cutBeforeRe)] - const cutAfters = [...code.matchAll(cutAfterRe)] - const cutStarts = [...code.matchAll(cutStartRe)] - const cutEnds = [...code.matchAll(cutEndRe)] - - for (const match of cuts) { - const lineStart = code.lastIndexOf('\n', match.index! - 1) + 1 - ranges.push([0, lineStart + match[0].length + 1]) - } - for (let i = 0; i < cutBefores.length; i++) { - const match = cutBefores[i] - const afterMatch = cutAfters[i] - if (afterMatch) { - const lineStart = code.lastIndexOf('\n', afterMatch.index! - 1) + 1 - ranges.push([match.index!, lineStart + afterMatch[0].length + 1]) - } - else { - ranges.push([match.index!, code.length]) - } + const cuts = comments.filter(c => c.data === '---cut---' || c.data === '---cut-before---') + const cutAfters = comments.filter(c => c.data === '---cut-after---') + const cutStarts = comments.filter(c => c.data === '---cut-start---') + const cutEnds = comments.filter(c => c.data === '---cut-end---') + + for (const comment of cuts) { + const end = code[comment.end] === '\n' ? comment.end + 1 : comment.end + ranges.push([0, end]) } - for (let i = cutBefores.length; i < cutAfters.length; i++) { - const match = cutAfters[i] - const lineStart = code.lastIndexOf('\n', match.index! - 1) + 1 - ranges.push([0, lineStart + match[0].length + 1]) + for (const comment of cutAfters) { + ranges.push([comment.start, code.length]) } for (let i = 0; i < cutStarts.length; i++) { - const startMatch = cutStarts[i] - const endMatch = cutEnds[i] - if (endMatch) { - const endLineStart = code.lastIndexOf('\n', endMatch.index! - 1) + 1 - ranges.push([startMatch.index!, endLineStart + endMatch[0].length + 1]) - } - else { + const start = cutStarts[i] + const end = cutEnds[i] + const rangeEnd = code[end.end] === '\n' ? end.end + 1 : end.end + ranges.push([start.start, rangeEnd]) + } + + if (cutStarts.length !== cutEnds.length) { + if (cutStarts.length > cutEnds.length) { throw new Error( - `Mismatched HTML cut markers: cut-start at position ${startMatch.index!} has no matching cut-end`, + `Mismatched HTML cut markers: cut-start at position ${cutStarts[cutEnds.length].start} has no matching cut-end`, ) } - } - - if (cutEnds.length > cutStarts.length) { throw new Error( `Mismatched HTML cut markers: more cut-end markers than cut-start markers`, ) @@ -338,3 +333,36 @@ function findMarkupRemovals(code: string): Range[] { return ranges } + +function clampRemovalToScriptBoundaries( + start: number, + end: number, + ast: ReturnType, +): [number, number] | undefined { + const scriptBlocks = [ + ast.instance, + ast.module, + ].filter(block => block != null) + + for (const block of scriptBlocks) { + const tagStart = block.start // start of `` + const contentEnd = block.content.end // just before `` + const tagEnd = block.end // end of `` + + // removal starts before script block content, clamp it forward + if (start < contentStart && end > tagStart) { + start = contentStart + } + // removal ends after script block content, clamp it back + if (end > contentEnd && start < tagEnd) { + end = contentEnd + } + // after clamping, the range may have become invalid + if (start >= end) { + return undefined + } + } + + return [start, end] +} diff --git a/packages/twoslash-svelte/test/fixtures/cut-around-markup.svelte b/packages/twoslash-svelte/test/fixtures/cut-around-markup.svelte deleted file mode 100644 index 549676c8..00000000 --- a/packages/twoslash-svelte/test/fixtures/cut-around-markup.svelte +++ /dev/null @@ -1,14 +0,0 @@ - - - - - \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/cut-around-shorthand-markup.svelte b/packages/twoslash-svelte/test/fixtures/cut-around-shorthand-markup.svelte deleted file mode 100644 index fbbb7c4c..00000000 --- a/packages/twoslash-svelte/test/fixtures/cut-around-shorthand-markup.svelte +++ /dev/null @@ -1,13 +0,0 @@ - - - - \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/cut-around-shorthand.svelte b/packages/twoslash-svelte/test/fixtures/cut-around-shorthand.svelte deleted file mode 100644 index 550f5e1b..00000000 --- a/packages/twoslash-svelte/test/fixtures/cut-around-shorthand.svelte +++ /dev/null @@ -1,12 +0,0 @@ - - - \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/cut-around.svelte b/packages/twoslash-svelte/test/fixtures/cut-around.svelte deleted file mode 100644 index 3e25b2d0..00000000 --- a/packages/twoslash-svelte/test/fixtures/cut-around.svelte +++ /dev/null @@ -1,13 +0,0 @@ - - - \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/cut-in-markup.svelte b/packages/twoslash-svelte/test/fixtures/cut-in-markup.svelte deleted file mode 100644 index 3b91070d..00000000 --- a/packages/twoslash-svelte/test/fixtures/cut-in-markup.svelte +++ /dev/null @@ -1,14 +0,0 @@ - - - - - \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/cut-in.svelte b/packages/twoslash-svelte/test/fixtures/cut-in.svelte deleted file mode 100644 index f5c9365d..00000000 --- a/packages/twoslash-svelte/test/fixtures/cut-in.svelte +++ /dev/null @@ -1,13 +0,0 @@ - - - \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/cut-around-markup.json b/packages/twoslash-svelte/test/results/cut-around-markup.json deleted file mode 100644 index efb6966b..00000000 --- a/packages/twoslash-svelte/test/results/cut-around-markup.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "code": "\n", - "nodes": [ - { - "type": "hover", - "text": "(local function) increment(): void", - "start": 18, - "length": 9, - "target": "increment", - "line": 1, - "character": 17 - }, - { - "type": "hover", - "text": "let count: number", - "start": 45, - "length": 5, - "target": "count", - "line": 2, - "character": 15 - } - ], - "flags": [] -} \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/cut-around-shorthand-markup.json b/packages/twoslash-svelte/test/results/cut-around-shorthand-markup.json deleted file mode 100644 index efb6966b..00000000 --- a/packages/twoslash-svelte/test/results/cut-around-shorthand-markup.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "code": "\n", - "nodes": [ - { - "type": "hover", - "text": "(local function) increment(): void", - "start": 18, - "length": 9, - "target": "increment", - "line": 1, - "character": 17 - }, - { - "type": "hover", - "text": "let count: number", - "start": 45, - "length": 5, - "target": "count", - "line": 2, - "character": 15 - } - ], - "flags": [] -} \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/cut-around-shorthand.json b/packages/twoslash-svelte/test/results/cut-around-shorthand.json deleted file mode 100644 index 32dee51f..00000000 --- a/packages/twoslash-svelte/test/results/cut-around-shorthand.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "code": "\n\n", - "nodes": [ - { - "type": "hover", - "text": "(local function) increment(): void", - "start": 37, - "length": 9, - "target": "increment", - "line": 3, - "character": 17 - }, - { - "type": "hover", - "text": "let count: number", - "start": 64, - "length": 5, - "target": "count", - "line": 4, - "character": 15 - } - ], - "flags": [] -} \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/cut-around.json b/packages/twoslash-svelte/test/results/cut-around.json deleted file mode 100644 index 75817fde..00000000 --- a/packages/twoslash-svelte/test/results/cut-around.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "code": "\n\n", - "nodes": [ - { - "type": "hover", - "text": "(local function) increment(): void", - "start": 22, - "length": 9, - "target": "increment", - "line": 1, - "character": 13 - }, - { - "type": "hover", - "text": "let count: number", - "start": 44, - "length": 5, - "target": "count", - "line": 2, - "character": 8 - } - ], - "flags": [] -} \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/cut-in-markup.json b/packages/twoslash-svelte/test/results/cut-in-markup.json deleted file mode 100644 index efb6966b..00000000 --- a/packages/twoslash-svelte/test/results/cut-in-markup.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "code": "\n", - "nodes": [ - { - "type": "hover", - "text": "(local function) increment(): void", - "start": 18, - "length": 9, - "target": "increment", - "line": 1, - "character": 17 - }, - { - "type": "hover", - "text": "let count: number", - "start": 45, - "length": 5, - "target": "count", - "line": 2, - "character": 15 - } - ], - "flags": [] -} \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/cut-in.json b/packages/twoslash-svelte/test/results/cut-in.json deleted file mode 100644 index 7b69cb24..00000000 --- a/packages/twoslash-svelte/test/results/cut-in.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "code": "\n\n", - "nodes": [ - { - "type": "hover", - "text": "let count: number", - "start": 17, - "length": 5, - "target": "count", - "line": 1, - "character": 8 - }, - { - "type": "hover", - "text": "function $state<0>(initial: 0): 0 (+1 overload)\nnamespace $state", - "docs": "Declares reactive state.\n\nExample:\n```ts\nlet count = $state(0);\n```", - "tags": [ - [ - "see", - "{@link https://svelte.dev/docs/svelte/$state Documentation}" - ], - [ - "param", - "initial The initial value" - ] - ], - "start": 25, - "length": 6, - "target": "$state", - "line": 1, - "character": 16 - }, - { - "type": "hover", - "text": "(local function) increment(): void", - "start": 69, - "length": 9, - "target": "increment", - "line": 5, - "character": 17 - }, - { - "type": "hover", - "text": "let count: number", - "start": 96, - "length": 5, - "target": "count", - "line": 6, - "character": 15 - } - ], - "flags": [] -} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 01e8bc7f..fc9108f2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -75,6 +75,9 @@ catalogs: esno: specifier: ^4.8.0 version: 4.8.0 + estree-walker: + specifier: ^3.0.3 + version: 3.0.3 fast-glob: specifier: ^3.3.3 version: 3.3.3 @@ -447,6 +450,12 @@ importers: '@volar/language-core': specifier: 'catalog:' version: 2.4.28 + estree-walker: + specifier: 'catalog:' + version: 3.0.3 + svelte: + specifier: '>=5' + version: 5.56.1(@typescript-eslint/types@8.58.1) svelte2tsx: specifier: '*' version: 0.7.56(svelte@5.56.1(@typescript-eslint/types@8.58.1))(typescript@6.0.2) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 251dd9bc..e3c6f578 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -42,6 +42,7 @@ catalog: chokidar: ^5.0.0 eslint: ^10.2.0 esno: ^4.8.0 + estree-walker: ^3.0.3 fast-glob: ^3.3.3 floating-vue: ^5.2.2 fuse.js: ^7.3.0 From 90e7fcacbd42c828a557523b66d75b285340a564 Mon Sep 17 00:00:00 2001 From: Hugos68 Date: Sun, 7 Jun 2026 20:10:03 +0200 Subject: [PATCH 04/14] update tests --- .../twoslash-svelte/test/fixtures.test.ts | 17 ++- .../fixtures/{ => script}/completion.svelte | 2 - .../test/fixtures/script/cut-after.svelte | 10 ++ .../test/fixtures/script/cut-before.svelte | 10 ++ .../test/fixtures/script/cut-region.svelte | 11 ++ .../test/fixtures/script/cut.svelte | 10 ++ .../test/fixtures/{ => script}/hover.svelte | 2 - .../test/fixtures/{ => script}/query.svelte | 2 - .../test/fixtures/template/cut-after.svelte | 10 ++ .../test/fixtures/template/cut-before.svelte | 10 ++ .../test/fixtures/template/cut-region.svelte | 11 ++ .../test/fixtures/template/cut.svelte | 10 ++ .../test/results/{ => script}/completion.json | 0 .../test/results/script/cut-after.json | 35 +++++ .../test/results/script/cut-before.json | 42 ++++++ .../test/results/script/cut-region.json | 53 +++++++ .../test/results/script/cut.json | 42 ++++++ .../test/results/{ => script}/hover.json | 0 .../test/results/{ => script}/query.json | 0 .../test/results/template/cut-after.json | 53 +++++++ .../test/results/template/cut-before.json | 24 ++++ .../test/results/template/cut-region.json | 53 +++++++ .../test/results/template/cut.json | 24 ++++ results/script/completion.json | 136 ++++++++++++++++++ results/script/cut-after.json | 5 + results/script/cut-before.json | 5 + results/script/cut-region.json | 5 + results/script/cut.json | 5 + results/script/hover.json | 71 +++++++++ results/script/query.json | 91 ++++++++++++ results/template/cut-after.json | 5 + results/template/cut-before.json | 5 + results/template/cut-region.json | 5 + results/template/cut.json | 5 + 34 files changed, 760 insertions(+), 9 deletions(-) rename packages/twoslash-svelte/test/fixtures/{ => script}/completion.svelte (98%) create mode 100644 packages/twoslash-svelte/test/fixtures/script/cut-after.svelte create mode 100644 packages/twoslash-svelte/test/fixtures/script/cut-before.svelte create mode 100644 packages/twoslash-svelte/test/fixtures/script/cut-region.svelte create mode 100644 packages/twoslash-svelte/test/fixtures/script/cut.svelte rename packages/twoslash-svelte/test/fixtures/{ => script}/hover.svelte (98%) rename packages/twoslash-svelte/test/fixtures/{ => script}/query.svelte (98%) create mode 100644 packages/twoslash-svelte/test/fixtures/template/cut-after.svelte create mode 100644 packages/twoslash-svelte/test/fixtures/template/cut-before.svelte create mode 100644 packages/twoslash-svelte/test/fixtures/template/cut-region.svelte create mode 100644 packages/twoslash-svelte/test/fixtures/template/cut.svelte rename packages/twoslash-svelte/test/results/{ => script}/completion.json (100%) create mode 100644 packages/twoslash-svelte/test/results/script/cut-after.json create mode 100644 packages/twoslash-svelte/test/results/script/cut-before.json create mode 100644 packages/twoslash-svelte/test/results/script/cut-region.json create mode 100644 packages/twoslash-svelte/test/results/script/cut.json rename packages/twoslash-svelte/test/results/{ => script}/hover.json (100%) rename packages/twoslash-svelte/test/results/{ => script}/query.json (100%) create mode 100644 packages/twoslash-svelte/test/results/template/cut-after.json create mode 100644 packages/twoslash-svelte/test/results/template/cut-before.json create mode 100644 packages/twoslash-svelte/test/results/template/cut-region.json create mode 100644 packages/twoslash-svelte/test/results/template/cut.json create mode 100644 results/script/completion.json create mode 100644 results/script/cut-after.json create mode 100644 results/script/cut-before.json create mode 100644 results/script/cut-region.json create mode 100644 results/script/cut.json create mode 100644 results/script/hover.json create mode 100644 results/script/query.json create mode 100644 results/template/cut-after.json create mode 100644 results/template/cut-before.json create mode 100644 results/template/cut-region.json create mode 100644 results/template/cut.json diff --git a/packages/twoslash-svelte/test/fixtures.test.ts b/packages/twoslash-svelte/test/fixtures.test.ts index 2e83ed52..ca39d730 100644 --- a/packages/twoslash-svelte/test/fixtures.test.ts +++ b/packages/twoslash-svelte/test/fixtures.test.ts @@ -1,7 +1,8 @@ /// import type { TwoslashReturn } from 'twoslash' -import { extname } from 'node:path' +import { access, mkdir, writeFile } from 'node:fs/promises' +import { dirname, extname } from 'node:path' import process from 'node:process' import { expect, it } from 'vitest' import { createTwoslasher } from '../src/index' @@ -55,8 +56,18 @@ Object.entries(fixtures).forEach(([path, fixture]) => { throw new Error('Expected to throw') } else { - await expect(cleanFixture(result)) - .toMatchFileSnapshot(outPath) + const output = cleanFixture(result) + + try { + await access(outPath) + await expect(output) + .toMatchFileSnapshot(outPath) + } + catch { + // Create result if result does not exist + await mkdir(dirname(outPath), { recursive: true }) + await writeFile(outPath, output) + } } }, ) diff --git a/packages/twoslash-svelte/test/fixtures/completion.svelte b/packages/twoslash-svelte/test/fixtures/script/completion.svelte similarity index 98% rename from packages/twoslash-svelte/test/fixtures/completion.svelte rename to packages/twoslash-svelte/test/fixtures/script/completion.svelte index 51c32c48..16de0977 100644 --- a/packages/twoslash-svelte/test/fixtures/completion.svelte +++ b/packages/twoslash-svelte/test/fixtures/script/completion.svelte @@ -1,12 +1,10 @@ - \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/script/cut-after.svelte b/packages/twoslash-svelte/test/fixtures/script/cut-after.svelte new file mode 100644 index 00000000..8f641aff --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/script/cut-after.svelte @@ -0,0 +1,10 @@ + + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/script/cut-before.svelte b/packages/twoslash-svelte/test/fixtures/script/cut-before.svelte new file mode 100644 index 00000000..7230c851 --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/script/cut-before.svelte @@ -0,0 +1,10 @@ + + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/script/cut-region.svelte b/packages/twoslash-svelte/test/fixtures/script/cut-region.svelte new file mode 100644 index 00000000..de7803ae --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/script/cut-region.svelte @@ -0,0 +1,11 @@ + + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/script/cut.svelte b/packages/twoslash-svelte/test/fixtures/script/cut.svelte new file mode 100644 index 00000000..7dbf3e91 --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/script/cut.svelte @@ -0,0 +1,10 @@ + + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/hover.svelte b/packages/twoslash-svelte/test/fixtures/script/hover.svelte similarity index 98% rename from packages/twoslash-svelte/test/fixtures/hover.svelte rename to packages/twoslash-svelte/test/fixtures/script/hover.svelte index 17188e75..188fe471 100644 --- a/packages/twoslash-svelte/test/fixtures/hover.svelte +++ b/packages/twoslash-svelte/test/fixtures/script/hover.svelte @@ -1,11 +1,9 @@ - \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/query.svelte b/packages/twoslash-svelte/test/fixtures/script/query.svelte similarity index 98% rename from packages/twoslash-svelte/test/fixtures/query.svelte rename to packages/twoslash-svelte/test/fixtures/script/query.svelte index e2b073bb..2132af7c 100644 --- a/packages/twoslash-svelte/test/fixtures/query.svelte +++ b/packages/twoslash-svelte/test/fixtures/script/query.svelte @@ -1,12 +1,10 @@ - \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/template/cut-after.svelte b/packages/twoslash-svelte/test/fixtures/template/cut-after.svelte new file mode 100644 index 00000000..c63e1c03 --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/template/cut-after.svelte @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/template/cut-before.svelte b/packages/twoslash-svelte/test/fixtures/template/cut-before.svelte new file mode 100644 index 00000000..980745b2 --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/template/cut-before.svelte @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/template/cut-region.svelte b/packages/twoslash-svelte/test/fixtures/template/cut-region.svelte new file mode 100644 index 00000000..011191a9 --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/template/cut-region.svelte @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/template/cut.svelte b/packages/twoslash-svelte/test/fixtures/template/cut.svelte new file mode 100644 index 00000000..5b3076d8 --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/template/cut.svelte @@ -0,0 +1,10 @@ + + + diff --git a/packages/twoslash-svelte/test/results/completion.json b/packages/twoslash-svelte/test/results/script/completion.json similarity index 100% rename from packages/twoslash-svelte/test/results/completion.json rename to packages/twoslash-svelte/test/results/script/completion.json diff --git a/packages/twoslash-svelte/test/results/script/cut-after.json b/packages/twoslash-svelte/test/results/script/cut-after.json new file mode 100644 index 00000000..b1eb8011 --- /dev/null +++ b/packages/twoslash-svelte/test/results/script/cut-after.json @@ -0,0 +1,35 @@ +{ + "code": "\n", + "nodes": [ + { + "type": "hover", + "text": "let count: number", + "start": 17, + "length": 5, + "target": "count", + "line": 1, + "character": 8 + }, + { + "type": "hover", + "text": "function $state<0>(initial: 0): 0 (+1 overload)\nnamespace $state", + "docs": "Declares reactive state.\n\nExample:\n```ts\nlet count = $state(0);\n```", + "tags": [ + [ + "see", + "{@link https://svelte.dev/docs/svelte/$state Documentation}" + ], + [ + "param", + "initial The initial value" + ] + ], + "start": 25, + "length": 6, + "target": "$state", + "line": 1, + "character": 16 + } + ], + "flags": [] +} \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/script/cut-before.json b/packages/twoslash-svelte/test/results/script/cut-before.json new file mode 100644 index 00000000..845f6b2b --- /dev/null +++ b/packages/twoslash-svelte/test/results/script/cut-before.json @@ -0,0 +1,42 @@ +{ + "code": "\n", + "nodes": [ + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 22, + "length": 9, + "target": "increment", + "line": 1, + "character": 13 + }, + { + "type": "hover", + "text": "let count: number", + "start": 44, + "length": 5, + "target": "count", + "line": 2, + "character": 8 + }, + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 86, + "length": 9, + "target": "increment", + "line": 5, + "character": 17 + }, + { + "type": "hover", + "text": "let count: number", + "start": 113, + "length": 5, + "target": "count", + "line": 6, + "character": 15 + } + ], + "flags": [] +} \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/script/cut-region.json b/packages/twoslash-svelte/test/results/script/cut-region.json new file mode 100644 index 00000000..2d31fc88 --- /dev/null +++ b/packages/twoslash-svelte/test/results/script/cut-region.json @@ -0,0 +1,53 @@ +{ + "code": "\n", + "nodes": [ + { + "type": "hover", + "text": "let count: number", + "start": 17, + "length": 5, + "target": "count", + "line": 1, + "character": 8 + }, + { + "type": "hover", + "text": "function $state<0>(initial: 0): 0 (+1 overload)\nnamespace $state", + "docs": "Declares reactive state.\n\nExample:\n```ts\nlet count = $state(0);\n```", + "tags": [ + [ + "see", + "{@link https://svelte.dev/docs/svelte/$state Documentation}" + ], + [ + "param", + "initial The initial value" + ] + ], + "start": 25, + "length": 6, + "target": "$state", + "line": 1, + "character": 16 + }, + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 63, + "length": 9, + "target": "increment", + "line": 3, + "character": 17 + }, + { + "type": "hover", + "text": "let count: number", + "start": 90, + "length": 5, + "target": "count", + "line": 4, + "character": 15 + } + ], + "flags": [] +} \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/script/cut.json b/packages/twoslash-svelte/test/results/script/cut.json new file mode 100644 index 00000000..845f6b2b --- /dev/null +++ b/packages/twoslash-svelte/test/results/script/cut.json @@ -0,0 +1,42 @@ +{ + "code": "\n", + "nodes": [ + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 22, + "length": 9, + "target": "increment", + "line": 1, + "character": 13 + }, + { + "type": "hover", + "text": "let count: number", + "start": 44, + "length": 5, + "target": "count", + "line": 2, + "character": 8 + }, + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 86, + "length": 9, + "target": "increment", + "line": 5, + "character": 17 + }, + { + "type": "hover", + "text": "let count: number", + "start": 113, + "length": 5, + "target": "count", + "line": 6, + "character": 15 + } + ], + "flags": [] +} \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/hover.json b/packages/twoslash-svelte/test/results/script/hover.json similarity index 100% rename from packages/twoslash-svelte/test/results/hover.json rename to packages/twoslash-svelte/test/results/script/hover.json diff --git a/packages/twoslash-svelte/test/results/query.json b/packages/twoslash-svelte/test/results/script/query.json similarity index 100% rename from packages/twoslash-svelte/test/results/query.json rename to packages/twoslash-svelte/test/results/script/query.json diff --git a/packages/twoslash-svelte/test/results/template/cut-after.json b/packages/twoslash-svelte/test/results/template/cut-after.json new file mode 100644 index 00000000..002c8a67 --- /dev/null +++ b/packages/twoslash-svelte/test/results/template/cut-after.json @@ -0,0 +1,53 @@ +{ + "code": "\n", + "nodes": [ + { + "type": "hover", + "text": "let count: number", + "start": 17, + "length": 5, + "target": "count", + "line": 1, + "character": 8 + }, + { + "type": "hover", + "text": "function $state<0>(initial: 0): 0 (+1 overload)\nnamespace $state", + "docs": "Declares reactive state.\n\nExample:\n```ts\nlet count = $state(0);\n```", + "tags": [ + [ + "see", + "{@link https://svelte.dev/docs/svelte/$state Documentation}" + ], + [ + "param", + "initial The initial value" + ] + ], + "start": 25, + "length": 6, + "target": "$state", + "line": 1, + "character": 16 + }, + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 49, + "length": 9, + "target": "increment", + "line": 2, + "character": 13 + }, + { + "type": "hover", + "text": "let count: number", + "start": 71, + "length": 5, + "target": "count", + "line": 3, + "character": 8 + } + ], + "flags": [] +} \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/template/cut-before.json b/packages/twoslash-svelte/test/results/template/cut-before.json new file mode 100644 index 00000000..f412d47b --- /dev/null +++ b/packages/twoslash-svelte/test/results/template/cut-before.json @@ -0,0 +1,24 @@ +{ + "code": "", + "nodes": [ + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 17, + "length": 9, + "target": "increment", + "line": 0, + "character": 17 + }, + { + "type": "hover", + "text": "let count: number", + "start": 44, + "length": 5, + "target": "count", + "line": 1, + "character": 15 + } + ], + "flags": [] +} \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/template/cut-region.json b/packages/twoslash-svelte/test/results/template/cut-region.json new file mode 100644 index 00000000..002c8a67 --- /dev/null +++ b/packages/twoslash-svelte/test/results/template/cut-region.json @@ -0,0 +1,53 @@ +{ + "code": "\n", + "nodes": [ + { + "type": "hover", + "text": "let count: number", + "start": 17, + "length": 5, + "target": "count", + "line": 1, + "character": 8 + }, + { + "type": "hover", + "text": "function $state<0>(initial: 0): 0 (+1 overload)\nnamespace $state", + "docs": "Declares reactive state.\n\nExample:\n```ts\nlet count = $state(0);\n```", + "tags": [ + [ + "see", + "{@link https://svelte.dev/docs/svelte/$state Documentation}" + ], + [ + "param", + "initial The initial value" + ] + ], + "start": 25, + "length": 6, + "target": "$state", + "line": 1, + "character": 16 + }, + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 49, + "length": 9, + "target": "increment", + "line": 2, + "character": 13 + }, + { + "type": "hover", + "text": "let count: number", + "start": 71, + "length": 5, + "target": "count", + "line": 3, + "character": 8 + } + ], + "flags": [] +} \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/template/cut.json b/packages/twoslash-svelte/test/results/template/cut.json new file mode 100644 index 00000000..2ba673d7 --- /dev/null +++ b/packages/twoslash-svelte/test/results/template/cut.json @@ -0,0 +1,24 @@ +{ + "code": "\n", + "nodes": [ + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 17, + "length": 9, + "target": "increment", + "line": 0, + "character": 17 + }, + { + "type": "hover", + "text": "let count: number", + "start": 44, + "length": 5, + "target": "count", + "line": 1, + "character": 15 + } + ], + "flags": [] +} \ No newline at end of file diff --git a/results/script/completion.json b/results/script/completion.json new file mode 100644 index 00000000..81c1b16e --- /dev/null +++ b/results/script/completion.json @@ -0,0 +1,136 @@ +{ + "code": "\n", + "nodes": [ + { + "type": "hover", + "text": "let count: number", + "start": 17, + "length": 5, + "target": "count", + "line": 1, + "character": 8 + }, + { + "type": "hover", + "text": "function $state<0>(initial: 0): 0 (+1 overload)\nnamespace $state", + "docs": "Declares reactive state.\n\nExample:\n```ts\nlet count = $state(0);\n```", + "tags": [ + [ + "see", + "{@link https://svelte.dev/docs/svelte/$state Documentation}" + ], + [ + "param", + "initial The initial value" + ] + ], + "start": 25, + "length": 6, + "target": "$state", + "line": 1, + "character": 16 + }, + { + "type": "completion", + "start": 26, + "length": 0, + "completions": [ + { + "name": "$$Component", + "kind": "const", + "kindModifiers": "", + "sortText": "11" + }, + { + "name": "$$render", + "kind": "function", + "kindModifiers": "", + "sortText": "11" + }, + { + "name": "$bindable", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "$derived", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "$effect", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "$host", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "$inspect", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "$props", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "$state", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + } + ], + "completionsPrefix": "$", + "line": 1, + "character": 17, + "target": "" + }, + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 49, + "length": 9, + "target": "increment", + "line": 2, + "character": 13 + }, + { + "type": "hover", + "text": "let count: number", + "start": 71, + "length": 5, + "target": "count", + "line": 3, + "character": 8 + }, + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 113, + "length": 9, + "target": "increment", + "line": 6, + "character": 17 + }, + { + "type": "hover", + "text": "let count: number", + "start": 140, + "length": 5, + "target": "count", + "line": 7, + "character": 15 + } + ], + "flags": [] +} diff --git a/results/script/cut-after.json b/results/script/cut-after.json new file mode 100644 index 00000000..ae1bb812 --- /dev/null +++ b/results/script/cut-after.json @@ -0,0 +1,5 @@ +{ + "code": "", + "nodes": [], + "flags": [] +} diff --git a/results/script/cut-before.json b/results/script/cut-before.json new file mode 100644 index 00000000..ae1bb812 --- /dev/null +++ b/results/script/cut-before.json @@ -0,0 +1,5 @@ +{ + "code": "", + "nodes": [], + "flags": [] +} diff --git a/results/script/cut-region.json b/results/script/cut-region.json new file mode 100644 index 00000000..ae1bb812 --- /dev/null +++ b/results/script/cut-region.json @@ -0,0 +1,5 @@ +{ + "code": "", + "nodes": [], + "flags": [] +} diff --git a/results/script/cut.json b/results/script/cut.json new file mode 100644 index 00000000..ae1bb812 --- /dev/null +++ b/results/script/cut.json @@ -0,0 +1,5 @@ +{ + "code": "", + "nodes": [], + "flags": [] +} diff --git a/results/script/hover.json b/results/script/hover.json new file mode 100644 index 00000000..33caad7b --- /dev/null +++ b/results/script/hover.json @@ -0,0 +1,71 @@ +{ + "code": "\n", + "nodes": [ + { + "type": "hover", + "text": "let count: number", + "start": 17, + "length": 5, + "target": "count", + "line": 1, + "character": 8 + }, + { + "type": "hover", + "text": "function $state<0>(initial: 0): 0 (+1 overload)\nnamespace $state", + "docs": "Declares reactive state.\n\nExample:\n```ts\nlet count = $state(0);\n```", + "tags": [ + [ + "see", + "{@link https://svelte.dev/docs/svelte/$state Documentation}" + ], + [ + "param", + "initial The initial value" + ] + ], + "start": 25, + "length": 6, + "target": "$state", + "line": 1, + "character": 16 + }, + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 49, + "length": 9, + "target": "increment", + "line": 2, + "character": 13 + }, + { + "type": "hover", + "text": "let count: number", + "start": 71, + "length": 5, + "target": "count", + "line": 3, + "character": 8 + }, + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 113, + "length": 9, + "target": "increment", + "line": 6, + "character": 17 + }, + { + "type": "hover", + "text": "let count: number", + "start": 140, + "length": 5, + "target": "count", + "line": 7, + "character": 15 + } + ], + "flags": [] +} diff --git a/results/script/query.json b/results/script/query.json new file mode 100644 index 00000000..dc5d2cdb --- /dev/null +++ b/results/script/query.json @@ -0,0 +1,91 @@ +{ + "code": "\n", + "nodes": [ + { + "type": "hover", + "text": "let count: number", + "start": 17, + "length": 5, + "target": "count", + "line": 1, + "character": 8 + }, + { + "type": "hover", + "text": "function $state<0>(initial: 0): 0 (+1 overload)\nnamespace $state", + "docs": "Declares reactive state.\n\nExample:\n```ts\nlet count = $state(0);\n```", + "tags": [ + [ + "see", + "{@link https://svelte.dev/docs/svelte/$state Documentation}" + ], + [ + "param", + "initial The initial value" + ] + ], + "start": 25, + "length": 6, + "target": "$state", + "line": 1, + "character": 16 + }, + { + "type": "query", + "text": "function $state<0>(initial: 0): 0 (+1 overload)\nnamespace $state", + "docs": "Declares reactive state.\n\nExample:\n```ts\nlet count = $state(0);\n```", + "tags": [ + [ + "see", + "{@link https://svelte.dev/docs/svelte/$state Documentation}" + ], + [ + "param", + "initial The initial value" + ] + ], + "start": 25, + "length": 6, + "target": "$state", + "line": 1, + "character": 16 + }, + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 49, + "length": 9, + "target": "increment", + "line": 2, + "character": 13 + }, + { + "type": "hover", + "text": "let count: number", + "start": 71, + "length": 5, + "target": "count", + "line": 3, + "character": 8 + }, + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 113, + "length": 9, + "target": "increment", + "line": 6, + "character": 17 + }, + { + "type": "hover", + "text": "let count: number", + "start": 140, + "length": 5, + "target": "count", + "line": 7, + "character": 15 + } + ], + "flags": [] +} diff --git a/results/template/cut-after.json b/results/template/cut-after.json new file mode 100644 index 00000000..ae1bb812 --- /dev/null +++ b/results/template/cut-after.json @@ -0,0 +1,5 @@ +{ + "code": "", + "nodes": [], + "flags": [] +} diff --git a/results/template/cut-before.json b/results/template/cut-before.json new file mode 100644 index 00000000..ae1bb812 --- /dev/null +++ b/results/template/cut-before.json @@ -0,0 +1,5 @@ +{ + "code": "", + "nodes": [], + "flags": [] +} diff --git a/results/template/cut-region.json b/results/template/cut-region.json new file mode 100644 index 00000000..ae1bb812 --- /dev/null +++ b/results/template/cut-region.json @@ -0,0 +1,5 @@ +{ + "code": "", + "nodes": [], + "flags": [] +} diff --git a/results/template/cut.json b/results/template/cut.json new file mode 100644 index 00000000..ae1bb812 --- /dev/null +++ b/results/template/cut.json @@ -0,0 +1,5 @@ +{ + "code": "", + "nodes": [], + "flags": [] +} From f3d264ba908c2e99a65a06bc8a5fb32aaf0b75e3 Mon Sep 17 00:00:00 2001 From: Hugos68 Date: Sun, 7 Jun 2026 20:12:38 +0200 Subject: [PATCH 05/14] update --- packages/twoslash-svelte/test/fixtures.test.ts | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/packages/twoslash-svelte/test/fixtures.test.ts b/packages/twoslash-svelte/test/fixtures.test.ts index ca39d730..2e83ed52 100644 --- a/packages/twoslash-svelte/test/fixtures.test.ts +++ b/packages/twoslash-svelte/test/fixtures.test.ts @@ -1,8 +1,7 @@ /// import type { TwoslashReturn } from 'twoslash' -import { access, mkdir, writeFile } from 'node:fs/promises' -import { dirname, extname } from 'node:path' +import { extname } from 'node:path' import process from 'node:process' import { expect, it } from 'vitest' import { createTwoslasher } from '../src/index' @@ -56,18 +55,8 @@ Object.entries(fixtures).forEach(([path, fixture]) => { throw new Error('Expected to throw') } else { - const output = cleanFixture(result) - - try { - await access(outPath) - await expect(output) - .toMatchFileSnapshot(outPath) - } - catch { - // Create result if result does not exist - await mkdir(dirname(outPath), { recursive: true }) - await writeFile(outPath, output) - } + await expect(cleanFixture(result)) + .toMatchFileSnapshot(outPath) } }, ) From 11772df031f1f7a44cf02dea502593d0f562dcb1 Mon Sep 17 00:00:00 2001 From: Hugos68 Date: Sun, 7 Jun 2026 20:17:19 +0200 Subject: [PATCH 06/14] fix newline removals --- .../test/results/script/completion.json | 18 +++++++++--------- .../test/results/script/hover.json | 18 +++++++++--------- .../test/results/script/query.json | 18 +++++++++--------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/packages/twoslash-svelte/test/results/script/completion.json b/packages/twoslash-svelte/test/results/script/completion.json index 8a8816e6..66abf840 100644 --- a/packages/twoslash-svelte/test/results/script/completion.json +++ b/packages/twoslash-svelte/test/results/script/completion.json @@ -1,5 +1,5 @@ { - "code": "\n\n", + "code": "\n", "nodes": [ { "type": "hover", @@ -98,37 +98,37 @@ { "type": "hover", "text": "(local function) increment(): void", - "start": 50, + "start": 49, "length": 9, "target": "increment", - "line": 3, + "line": 2, "character": 13 }, { "type": "hover", "text": "let count: number", - "start": 72, + "start": 71, "length": 5, "target": "count", - "line": 4, + "line": 3, "character": 8 }, { "type": "hover", "text": "(local function) increment(): void", - "start": 115, + "start": 113, "length": 9, "target": "increment", - "line": 8, + "line": 6, "character": 17 }, { "type": "hover", "text": "let count: number", - "start": 142, + "start": 140, "length": 5, "target": "count", - "line": 9, + "line": 7, "character": 15 } ], diff --git a/packages/twoslash-svelte/test/results/script/hover.json b/packages/twoslash-svelte/test/results/script/hover.json index 99056edd..43642528 100644 --- a/packages/twoslash-svelte/test/results/script/hover.json +++ b/packages/twoslash-svelte/test/results/script/hover.json @@ -1,5 +1,5 @@ { - "code": "\n\n", + "code": "\n", "nodes": [ { "type": "hover", @@ -33,37 +33,37 @@ { "type": "hover", "text": "(local function) increment(): void", - "start": 50, + "start": 49, "length": 9, "target": "increment", - "line": 3, + "line": 2, "character": 13 }, { "type": "hover", "text": "let count: number", - "start": 72, + "start": 71, "length": 5, "target": "count", - "line": 4, + "line": 3, "character": 8 }, { "type": "hover", "text": "(local function) increment(): void", - "start": 115, + "start": 113, "length": 9, "target": "increment", - "line": 8, + "line": 6, "character": 17 }, { "type": "hover", "text": "let count: number", - "start": 142, + "start": 140, "length": 5, "target": "count", - "line": 9, + "line": 7, "character": 15 } ], diff --git a/packages/twoslash-svelte/test/results/script/query.json b/packages/twoslash-svelte/test/results/script/query.json index 13e09080..33f6d133 100644 --- a/packages/twoslash-svelte/test/results/script/query.json +++ b/packages/twoslash-svelte/test/results/script/query.json @@ -1,5 +1,5 @@ { - "code": "\n\n", + "code": "\n", "nodes": [ { "type": "hover", @@ -53,37 +53,37 @@ { "type": "hover", "text": "(local function) increment(): void", - "start": 50, + "start": 49, "length": 9, "target": "increment", - "line": 3, + "line": 2, "character": 13 }, { "type": "hover", "text": "let count: number", - "start": 72, + "start": 71, "length": 5, "target": "count", - "line": 4, + "line": 3, "character": 8 }, { "type": "hover", "text": "(local function) increment(): void", - "start": 115, + "start": 113, "length": 9, "target": "increment", - "line": 8, + "line": 6, "character": 17 }, { "type": "hover", "text": "let count: number", - "start": 142, + "start": 140, "length": 5, "target": "count", - "line": 9, + "line": 7, "character": 15 } ], From 45b7974b06a30b5a08761cb4bcbbf2c1c1c98d54 Mon Sep 17 00:00:00 2001 From: Hugos68 Date: Sun, 7 Jun 2026 20:18:04 +0200 Subject: [PATCH 07/14] fix test --- packages/twoslash-svelte/test/results/script/cut-after.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/twoslash-svelte/test/results/script/cut-after.json b/packages/twoslash-svelte/test/results/script/cut-after.json index b1eb8011..dda4a1ee 100644 --- a/packages/twoslash-svelte/test/results/script/cut-after.json +++ b/packages/twoslash-svelte/test/results/script/cut-after.json @@ -1,5 +1,5 @@ { - "code": "\n", + "code": "\n", "nodes": [ { "type": "hover", From 4fda32ffb9e686ca5a3c1a23146d7be2e54f8dae Mon Sep 17 00:00:00 2001 From: Hugos68 Date: Sun, 7 Jun 2026 20:36:23 +0200 Subject: [PATCH 08/14] fix --- packages/twoslash-svelte/src/index.ts | 19 ++++++++++++++++-- .../test/results/script/cut-after.json | 2 +- .../test/results/script/cut-before.json | 20 +++++++++---------- .../test/results/script/cut.json | 20 +++++++++---------- 4 files changed, 38 insertions(+), 23 deletions(-) diff --git a/packages/twoslash-svelte/src/index.ts b/packages/twoslash-svelte/src/index.ts index 5901421a..fe62bc5c 100644 --- a/packages/twoslash-svelte/src/index.ts +++ b/packages/twoslash-svelte/src/index.ts @@ -158,8 +158,14 @@ export function createTwoslasher(createOptions: CreateTwoslashSvelteOptions = {} ...sourceMeta.removals, ...findMarkupRemovals(code), ...result.meta.removals.map((r) => { - const start = get(map.toSourceLocation(r[0]), 0)?.[0] ?? code.match(/(?<=\s)/)?.index - const end = get(map.toSourceLocation(r[1]), 0)?.[0] + const scriptContentStart = hasRange(ast.instance?.content) ? ast.instance.content.start : 0 + const scriptContentEnd = hasRange(ast.instance?.content) ? ast.instance.content.end : 0 + const start = get(map.toSourceLocation(r[0]), 0)?.[0] ?? scriptContentStart + const end = get(map.toSourceLocation(r[1]), 0)?.[0] ?? ( + start != null && scriptContentEnd != null && r[1] > scriptContentEnd + ? scriptContentEnd + : undefined + ) if (start == null || end == null || start < 0 || end < 0 || start >= end) { return undefined } @@ -366,3 +372,12 @@ function clampRemovalToScriptBoundaries( return [start, end] } + +function hasRange(range: unknown): range is { start: number, end: number } { + return typeof range === 'object' + && range != null + && 'start' in range + && 'end' in range + && typeof range.start === 'number' + && typeof range.end === 'number' +} diff --git a/packages/twoslash-svelte/test/results/script/cut-after.json b/packages/twoslash-svelte/test/results/script/cut-after.json index dda4a1ee..1f4872e8 100644 --- a/packages/twoslash-svelte/test/results/script/cut-after.json +++ b/packages/twoslash-svelte/test/results/script/cut-after.json @@ -1,5 +1,5 @@ { - "code": "\n", + "code": "\n", "nodes": [ { "type": "hover", diff --git a/packages/twoslash-svelte/test/results/script/cut-before.json b/packages/twoslash-svelte/test/results/script/cut-before.json index 845f6b2b..3482dc8a 100644 --- a/packages/twoslash-svelte/test/results/script/cut-before.json +++ b/packages/twoslash-svelte/test/results/script/cut-before.json @@ -1,40 +1,40 @@ { - "code": "\n", + "code": "\n", "nodes": [ { "type": "hover", "text": "(local function) increment(): void", - "start": 22, + "start": 21, "length": 9, "target": "increment", - "line": 1, - "character": 13 + "line": 0, + "character": 21 }, { "type": "hover", "text": "let count: number", - "start": 44, + "start": 43, "length": 5, "target": "count", - "line": 2, + "line": 1, "character": 8 }, { "type": "hover", "text": "(local function) increment(): void", - "start": 86, + "start": 85, "length": 9, "target": "increment", - "line": 5, + "line": 4, "character": 17 }, { "type": "hover", "text": "let count: number", - "start": 113, + "start": 112, "length": 5, "target": "count", - "line": 6, + "line": 5, "character": 15 } ], diff --git a/packages/twoslash-svelte/test/results/script/cut.json b/packages/twoslash-svelte/test/results/script/cut.json index 845f6b2b..3482dc8a 100644 --- a/packages/twoslash-svelte/test/results/script/cut.json +++ b/packages/twoslash-svelte/test/results/script/cut.json @@ -1,40 +1,40 @@ { - "code": "\n", + "code": "\n", "nodes": [ { "type": "hover", "text": "(local function) increment(): void", - "start": 22, + "start": 21, "length": 9, "target": "increment", - "line": 1, - "character": 13 + "line": 0, + "character": 21 }, { "type": "hover", "text": "let count: number", - "start": 44, + "start": 43, "length": 5, "target": "count", - "line": 2, + "line": 1, "character": 8 }, { "type": "hover", "text": "(local function) increment(): void", - "start": 86, + "start": 85, "length": 9, "target": "increment", - "line": 5, + "line": 4, "character": 17 }, { "type": "hover", "text": "let count: number", - "start": 113, + "start": 112, "length": 5, "target": "count", - "line": 6, + "line": 5, "character": 15 } ], From 576a8f2aae8306503a102b5e2a289a5f7316d28d Mon Sep 17 00:00:00 2001 From: Hugos68 Date: Sun, 7 Jun 2026 20:54:20 +0200 Subject: [PATCH 09/14] remove whoopsies results, add module script test cases --- packages/twoslash-svelte/src/index.ts | 25 ++-- .../test/fixtures/script/cut-after.svelte | 7 + .../test/fixtures/script/cut-before.svelte | 7 + .../test/fixtures/script/cut.svelte | 7 + .../test/results/script/cut-after.json | 18 +-- .../test/results/script/cut-before.json | 10 +- .../test/results/script/cut.json | 10 +- results/script/completion.json | 136 ------------------ results/script/cut-after.json | 5 - results/script/cut-before.json | 5 - results/script/cut-region.json | 5 - results/script/cut.json | 5 - results/script/hover.json | 71 --------- results/script/query.json | 91 ------------ results/template/cut-after.json | 5 - results/template/cut-before.json | 5 - results/template/cut-region.json | 5 - results/template/cut.json | 5 - 18 files changed, 57 insertions(+), 365 deletions(-) delete mode 100644 results/script/completion.json delete mode 100644 results/script/cut-after.json delete mode 100644 results/script/cut-before.json delete mode 100644 results/script/cut-region.json delete mode 100644 results/script/cut.json delete mode 100644 results/script/hover.json delete mode 100644 results/script/query.json delete mode 100644 results/template/cut-after.json delete mode 100644 results/template/cut-before.json delete mode 100644 results/template/cut-region.json delete mode 100644 results/template/cut.json diff --git a/packages/twoslash-svelte/src/index.ts b/packages/twoslash-svelte/src/index.ts index fe62bc5c..85be836b 100644 --- a/packages/twoslash-svelte/src/index.ts +++ b/packages/twoslash-svelte/src/index.ts @@ -158,14 +158,23 @@ export function createTwoslasher(createOptions: CreateTwoslashSvelteOptions = {} ...sourceMeta.removals, ...findMarkupRemovals(code), ...result.meta.removals.map((r) => { - const scriptContentStart = hasRange(ast.instance?.content) ? ast.instance.content.start : 0 - const scriptContentEnd = hasRange(ast.instance?.content) ? ast.instance.content.end : 0 - const start = get(map.toSourceLocation(r[0]), 0)?.[0] ?? scriptContentStart - const end = get(map.toSourceLocation(r[1]), 0)?.[0] ?? ( - start != null && scriptContentEnd != null && r[1] > scriptContentEnd - ? scriptContentEnd - : undefined - ) + const instanceContent = hasRange(ast.instance?.content) ? ast.instance.content : undefined + const moduleContent = hasRange(ast.module?.content) ? ast.module.content : undefined + + let start = get(map.toSourceLocation(r[0]), 0)?.[0] + let end = get(map.toSourceLocation(r[1]), 0)?.[0] + + // Determine which script block this removal belongs to based on start position + const scriptContent = start != null + ? (instanceContent && start >= instanceContent.start && start <= instanceContent.end ? instanceContent : undefined) + ?? (moduleContent && start >= moduleContent.start && start <= moduleContent.end ? moduleContent : undefined) + : instanceContent ?? moduleContent + + start ??= scriptContent?.start + if (end == null && scriptContent != null && r[1] > scriptContent.end) { + end = scriptContent.end + } + if (start == null || end == null || start < 0 || end < 0 || start >= end) { return undefined } diff --git a/packages/twoslash-svelte/test/fixtures/script/cut-after.svelte b/packages/twoslash-svelte/test/fixtures/script/cut-after.svelte index 8f641aff..4e81b570 100644 --- a/packages/twoslash-svelte/test/fixtures/script/cut-after.svelte +++ b/packages/twoslash-svelte/test/fixtures/script/cut-after.svelte @@ -5,6 +5,13 @@ count++; } + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/script/cut-before.svelte b/packages/twoslash-svelte/test/fixtures/script/cut-before.svelte index 7230c851..b127cab3 100644 --- a/packages/twoslash-svelte/test/fixtures/script/cut-before.svelte +++ b/packages/twoslash-svelte/test/fixtures/script/cut-before.svelte @@ -5,6 +5,13 @@ count++; } + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/script/cut.svelte b/packages/twoslash-svelte/test/fixtures/script/cut.svelte index 7dbf3e91..3aad0ede 100644 --- a/packages/twoslash-svelte/test/fixtures/script/cut.svelte +++ b/packages/twoslash-svelte/test/fixtures/script/cut.svelte @@ -5,6 +5,13 @@ count++; } + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/script/cut-after.json b/packages/twoslash-svelte/test/results/script/cut-after.json index 1f4872e8..507f370c 100644 --- a/packages/twoslash-svelte/test/results/script/cut-after.json +++ b/packages/twoslash-svelte/test/results/script/cut-after.json @@ -1,13 +1,13 @@ { - "code": "\n", + "code": "\n\n", "nodes": [ { "type": "hover", - "text": "let count: number", - "start": 17, - "length": 5, - "target": "count", - "line": 1, + "text": "let count2: number", + "start": 143, + "length": 6, + "target": "count2", + "line": 8, "character": 8 }, { @@ -24,11 +24,11 @@ "initial The initial value" ] ], - "start": 25, + "start": 152, "length": 6, "target": "$state", - "line": 1, - "character": 16 + "line": 8, + "character": 17 } ], "flags": [] diff --git a/packages/twoslash-svelte/test/results/script/cut-before.json b/packages/twoslash-svelte/test/results/script/cut-before.json index 3482dc8a..9098bf7e 100644 --- a/packages/twoslash-svelte/test/results/script/cut-before.json +++ b/packages/twoslash-svelte/test/results/script/cut-before.json @@ -1,5 +1,5 @@ { - "code": "\n", + "code": "\n\n", "nodes": [ { "type": "hover", @@ -22,19 +22,19 @@ { "type": "hover", "text": "(local function) increment(): void", - "start": 85, + "start": 215, "length": 9, "target": "increment", - "line": 4, + "line": 11, "character": 17 }, { "type": "hover", "text": "let count: number", - "start": 112, + "start": 242, "length": 5, "target": "count", - "line": 5, + "line": 12, "character": 15 } ], diff --git a/packages/twoslash-svelte/test/results/script/cut.json b/packages/twoslash-svelte/test/results/script/cut.json index 3482dc8a..9b441175 100644 --- a/packages/twoslash-svelte/test/results/script/cut.json +++ b/packages/twoslash-svelte/test/results/script/cut.json @@ -1,5 +1,5 @@ { - "code": "\n", + "code": "\n\n", "nodes": [ { "type": "hover", @@ -22,19 +22,19 @@ { "type": "hover", "text": "(local function) increment(): void", - "start": 85, + "start": 208, "length": 9, "target": "increment", - "line": 4, + "line": 11, "character": 17 }, { "type": "hover", "text": "let count: number", - "start": 112, + "start": 235, "length": 5, "target": "count", - "line": 5, + "line": 12, "character": 15 } ], diff --git a/results/script/completion.json b/results/script/completion.json deleted file mode 100644 index 81c1b16e..00000000 --- a/results/script/completion.json +++ /dev/null @@ -1,136 +0,0 @@ -{ - "code": "\n", - "nodes": [ - { - "type": "hover", - "text": "let count: number", - "start": 17, - "length": 5, - "target": "count", - "line": 1, - "character": 8 - }, - { - "type": "hover", - "text": "function $state<0>(initial: 0): 0 (+1 overload)\nnamespace $state", - "docs": "Declares reactive state.\n\nExample:\n```ts\nlet count = $state(0);\n```", - "tags": [ - [ - "see", - "{@link https://svelte.dev/docs/svelte/$state Documentation}" - ], - [ - "param", - "initial The initial value" - ] - ], - "start": 25, - "length": 6, - "target": "$state", - "line": 1, - "character": 16 - }, - { - "type": "completion", - "start": 26, - "length": 0, - "completions": [ - { - "name": "$$Component", - "kind": "const", - "kindModifiers": "", - "sortText": "11" - }, - { - "name": "$$render", - "kind": "function", - "kindModifiers": "", - "sortText": "11" - }, - { - "name": "$bindable", - "kind": "function", - "kindModifiers": "declare", - "sortText": "15" - }, - { - "name": "$derived", - "kind": "function", - "kindModifiers": "declare", - "sortText": "15" - }, - { - "name": "$effect", - "kind": "function", - "kindModifiers": "declare", - "sortText": "15" - }, - { - "name": "$host", - "kind": "function", - "kindModifiers": "declare", - "sortText": "15" - }, - { - "name": "$inspect", - "kind": "function", - "kindModifiers": "declare", - "sortText": "15" - }, - { - "name": "$props", - "kind": "function", - "kindModifiers": "declare", - "sortText": "15" - }, - { - "name": "$state", - "kind": "function", - "kindModifiers": "declare", - "sortText": "15" - } - ], - "completionsPrefix": "$", - "line": 1, - "character": 17, - "target": "" - }, - { - "type": "hover", - "text": "(local function) increment(): void", - "start": 49, - "length": 9, - "target": "increment", - "line": 2, - "character": 13 - }, - { - "type": "hover", - "text": "let count: number", - "start": 71, - "length": 5, - "target": "count", - "line": 3, - "character": 8 - }, - { - "type": "hover", - "text": "(local function) increment(): void", - "start": 113, - "length": 9, - "target": "increment", - "line": 6, - "character": 17 - }, - { - "type": "hover", - "text": "let count: number", - "start": 140, - "length": 5, - "target": "count", - "line": 7, - "character": 15 - } - ], - "flags": [] -} diff --git a/results/script/cut-after.json b/results/script/cut-after.json deleted file mode 100644 index ae1bb812..00000000 --- a/results/script/cut-after.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "code": "", - "nodes": [], - "flags": [] -} diff --git a/results/script/cut-before.json b/results/script/cut-before.json deleted file mode 100644 index ae1bb812..00000000 --- a/results/script/cut-before.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "code": "", - "nodes": [], - "flags": [] -} diff --git a/results/script/cut-region.json b/results/script/cut-region.json deleted file mode 100644 index ae1bb812..00000000 --- a/results/script/cut-region.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "code": "", - "nodes": [], - "flags": [] -} diff --git a/results/script/cut.json b/results/script/cut.json deleted file mode 100644 index ae1bb812..00000000 --- a/results/script/cut.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "code": "", - "nodes": [], - "flags": [] -} diff --git a/results/script/hover.json b/results/script/hover.json deleted file mode 100644 index 33caad7b..00000000 --- a/results/script/hover.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "code": "\n", - "nodes": [ - { - "type": "hover", - "text": "let count: number", - "start": 17, - "length": 5, - "target": "count", - "line": 1, - "character": 8 - }, - { - "type": "hover", - "text": "function $state<0>(initial: 0): 0 (+1 overload)\nnamespace $state", - "docs": "Declares reactive state.\n\nExample:\n```ts\nlet count = $state(0);\n```", - "tags": [ - [ - "see", - "{@link https://svelte.dev/docs/svelte/$state Documentation}" - ], - [ - "param", - "initial The initial value" - ] - ], - "start": 25, - "length": 6, - "target": "$state", - "line": 1, - "character": 16 - }, - { - "type": "hover", - "text": "(local function) increment(): void", - "start": 49, - "length": 9, - "target": "increment", - "line": 2, - "character": 13 - }, - { - "type": "hover", - "text": "let count: number", - "start": 71, - "length": 5, - "target": "count", - "line": 3, - "character": 8 - }, - { - "type": "hover", - "text": "(local function) increment(): void", - "start": 113, - "length": 9, - "target": "increment", - "line": 6, - "character": 17 - }, - { - "type": "hover", - "text": "let count: number", - "start": 140, - "length": 5, - "target": "count", - "line": 7, - "character": 15 - } - ], - "flags": [] -} diff --git a/results/script/query.json b/results/script/query.json deleted file mode 100644 index dc5d2cdb..00000000 --- a/results/script/query.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "code": "\n", - "nodes": [ - { - "type": "hover", - "text": "let count: number", - "start": 17, - "length": 5, - "target": "count", - "line": 1, - "character": 8 - }, - { - "type": "hover", - "text": "function $state<0>(initial: 0): 0 (+1 overload)\nnamespace $state", - "docs": "Declares reactive state.\n\nExample:\n```ts\nlet count = $state(0);\n```", - "tags": [ - [ - "see", - "{@link https://svelte.dev/docs/svelte/$state Documentation}" - ], - [ - "param", - "initial The initial value" - ] - ], - "start": 25, - "length": 6, - "target": "$state", - "line": 1, - "character": 16 - }, - { - "type": "query", - "text": "function $state<0>(initial: 0): 0 (+1 overload)\nnamespace $state", - "docs": "Declares reactive state.\n\nExample:\n```ts\nlet count = $state(0);\n```", - "tags": [ - [ - "see", - "{@link https://svelte.dev/docs/svelte/$state Documentation}" - ], - [ - "param", - "initial The initial value" - ] - ], - "start": 25, - "length": 6, - "target": "$state", - "line": 1, - "character": 16 - }, - { - "type": "hover", - "text": "(local function) increment(): void", - "start": 49, - "length": 9, - "target": "increment", - "line": 2, - "character": 13 - }, - { - "type": "hover", - "text": "let count: number", - "start": 71, - "length": 5, - "target": "count", - "line": 3, - "character": 8 - }, - { - "type": "hover", - "text": "(local function) increment(): void", - "start": 113, - "length": 9, - "target": "increment", - "line": 6, - "character": 17 - }, - { - "type": "hover", - "text": "let count: number", - "start": 140, - "length": 5, - "target": "count", - "line": 7, - "character": 15 - } - ], - "flags": [] -} diff --git a/results/template/cut-after.json b/results/template/cut-after.json deleted file mode 100644 index ae1bb812..00000000 --- a/results/template/cut-after.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "code": "", - "nodes": [], - "flags": [] -} diff --git a/results/template/cut-before.json b/results/template/cut-before.json deleted file mode 100644 index ae1bb812..00000000 --- a/results/template/cut-before.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "code": "", - "nodes": [], - "flags": [] -} diff --git a/results/template/cut-region.json b/results/template/cut-region.json deleted file mode 100644 index ae1bb812..00000000 --- a/results/template/cut-region.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "code": "", - "nodes": [], - "flags": [] -} diff --git a/results/template/cut.json b/results/template/cut.json deleted file mode 100644 index ae1bb812..00000000 --- a/results/template/cut.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "code": "", - "nodes": [], - "flags": [] -} From e38cf6eebd70b8a5869b11411c2f8b3e814d6e68 Mon Sep 17 00:00:00 2001 From: Hugos68 Date: Sun, 7 Jun 2026 21:10:51 +0200 Subject: [PATCH 10/14] update tests --- packages/twoslash-svelte/src/index.ts | 1 + .../test/fixtures/script/cut-after.svelte | 7 ------- .../test/fixtures/script/cut-before.svelte | 7 ------- .../test/fixtures/script/cut.svelte | 7 ------- .../test/results/script/cut-after.json | 18 +++++++++--------- .../test/results/script/cut-before.json | 10 +++++----- .../test/results/script/cut.json | 10 +++++----- 7 files changed, 20 insertions(+), 40 deletions(-) diff --git a/packages/twoslash-svelte/src/index.ts b/packages/twoslash-svelte/src/index.ts index 85be836b..3ed73817 100644 --- a/packages/twoslash-svelte/src/index.ts +++ b/packages/twoslash-svelte/src/index.ts @@ -83,6 +83,7 @@ export function createTwoslasher(createOptions: CreateTwoslashSvelteOptions = {} } const compiled = svelte2tsx(strippedCode) + const map = generateSourceMap(strippedCode, compiled.code, compiled.map.mappings) function getLastGeneratedOffset(pos: number) { diff --git a/packages/twoslash-svelte/test/fixtures/script/cut-after.svelte b/packages/twoslash-svelte/test/fixtures/script/cut-after.svelte index 4e81b570..8f641aff 100644 --- a/packages/twoslash-svelte/test/fixtures/script/cut-after.svelte +++ b/packages/twoslash-svelte/test/fixtures/script/cut-after.svelte @@ -5,13 +5,6 @@ count++; } - \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/script/cut-before.svelte b/packages/twoslash-svelte/test/fixtures/script/cut-before.svelte index b127cab3..7230c851 100644 --- a/packages/twoslash-svelte/test/fixtures/script/cut-before.svelte +++ b/packages/twoslash-svelte/test/fixtures/script/cut-before.svelte @@ -5,13 +5,6 @@ count++; } - \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/script/cut.svelte b/packages/twoslash-svelte/test/fixtures/script/cut.svelte index 3aad0ede..7dbf3e91 100644 --- a/packages/twoslash-svelte/test/fixtures/script/cut.svelte +++ b/packages/twoslash-svelte/test/fixtures/script/cut.svelte @@ -5,13 +5,6 @@ count++; } - \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/script/cut-after.json b/packages/twoslash-svelte/test/results/script/cut-after.json index 507f370c..1f4872e8 100644 --- a/packages/twoslash-svelte/test/results/script/cut-after.json +++ b/packages/twoslash-svelte/test/results/script/cut-after.json @@ -1,13 +1,13 @@ { - "code": "\n\n", + "code": "\n", "nodes": [ { "type": "hover", - "text": "let count2: number", - "start": 143, - "length": 6, - "target": "count2", - "line": 8, + "text": "let count: number", + "start": 17, + "length": 5, + "target": "count", + "line": 1, "character": 8 }, { @@ -24,11 +24,11 @@ "initial The initial value" ] ], - "start": 152, + "start": 25, "length": 6, "target": "$state", - "line": 8, - "character": 17 + "line": 1, + "character": 16 } ], "flags": [] diff --git a/packages/twoslash-svelte/test/results/script/cut-before.json b/packages/twoslash-svelte/test/results/script/cut-before.json index 9098bf7e..3482dc8a 100644 --- a/packages/twoslash-svelte/test/results/script/cut-before.json +++ b/packages/twoslash-svelte/test/results/script/cut-before.json @@ -1,5 +1,5 @@ { - "code": "\n\n", + "code": "\n", "nodes": [ { "type": "hover", @@ -22,19 +22,19 @@ { "type": "hover", "text": "(local function) increment(): void", - "start": 215, + "start": 85, "length": 9, "target": "increment", - "line": 11, + "line": 4, "character": 17 }, { "type": "hover", "text": "let count: number", - "start": 242, + "start": 112, "length": 5, "target": "count", - "line": 12, + "line": 5, "character": 15 } ], diff --git a/packages/twoslash-svelte/test/results/script/cut.json b/packages/twoslash-svelte/test/results/script/cut.json index 9b441175..3482dc8a 100644 --- a/packages/twoslash-svelte/test/results/script/cut.json +++ b/packages/twoslash-svelte/test/results/script/cut.json @@ -1,5 +1,5 @@ { - "code": "\n\n", + "code": "\n", "nodes": [ { "type": "hover", @@ -22,19 +22,19 @@ { "type": "hover", "text": "(local function) increment(): void", - "start": 208, + "start": 85, "length": 9, "target": "increment", - "line": 11, + "line": 4, "character": 17 }, { "type": "hover", "text": "let count: number", - "start": 235, + "start": 112, "length": 5, "target": "count", - "line": 12, + "line": 5, "character": 15 } ], From ff979e9c4030bba666a03f8a441d02c0120f1894 Mon Sep 17 00:00:00 2001 From: Hugos68 Date: Sun, 7 Jun 2026 22:35:24 +0200 Subject: [PATCH 11/14] coverage for throwing code --- packages/twoslash-svelte/src/index.ts | 27 ++++++++++++++----- .../throws/cut-region-missing-end.svelte | 10 +++++++ .../throws/cut-region-missing-start.svelte | 10 +++++++ .../throws/cut-region-missing-end.svelte | 10 +++++++ .../throws/cut-region-missing-start.svelte | 10 +++++++ .../script/throws/cut-region-missing-end.txt | 6 +++++ .../throws/cut-region-missing-start.txt | 6 +++++ .../throws/cut-region-missing-end.txt | 6 +++++ .../throws/cut-region-missing-start.txt | 6 +++++ 9 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 packages/twoslash-svelte/test/fixtures/script/throws/cut-region-missing-end.svelte create mode 100644 packages/twoslash-svelte/test/fixtures/script/throws/cut-region-missing-start.svelte create mode 100644 packages/twoslash-svelte/test/fixtures/template/throws/cut-region-missing-end.svelte create mode 100644 packages/twoslash-svelte/test/fixtures/template/throws/cut-region-missing-start.svelte create mode 100644 packages/twoslash-svelte/test/results/script/throws/cut-region-missing-end.txt create mode 100644 packages/twoslash-svelte/test/results/script/throws/cut-region-missing-start.txt create mode 100644 packages/twoslash-svelte/test/results/template/throws/cut-region-missing-end.txt create mode 100644 packages/twoslash-svelte/test/results/template/throws/cut-region-missing-start.txt diff --git a/packages/twoslash-svelte/src/index.ts b/packages/twoslash-svelte/src/index.ts index 3ed73817..31858fe7 100644 --- a/packages/twoslash-svelte/src/index.ts +++ b/packages/twoslash-svelte/src/index.ts @@ -332,18 +332,31 @@ function findMarkupRemovals(code: string): Range[] { for (let i = 0; i < cutStarts.length; i++) { const start = cutStarts[i] const end = cutEnds[i] + if (!start || !end) { + continue + } const rangeEnd = code[end.end] === '\n' ? end.end + 1 : end.end ranges.push([start.start, rangeEnd]) } - if (cutStarts.length !== cutEnds.length) { - if (cutStarts.length > cutEnds.length) { - throw new Error( - `Mismatched HTML cut markers: cut-start at position ${cutStarts[cutEnds.length].start} has no matching cut-end`, - ) - } + if (cutStarts.length > cutEnds.length) { throw new Error( - `Mismatched HTML cut markers: more cut-end markers than cut-start markers`, + ` +## Mismatched cut markers + +You have unclosed cut-starts at lines ${cutStarts.slice(cutEnds.length).map(c => c.start).join(', ')} + +Make sure you have a matching pair for each.`, + ) + } + if (cutEnds.length > cutStarts.length) { + throw new Error( + ` +## Mismatched cut markers + +You have unclosed cut-ends at lines ${cutEnds.slice(cutStarts.length).map(c => c.start).join(', ')} + +Make sure you have a matching pair for each.`, ) } diff --git a/packages/twoslash-svelte/test/fixtures/script/throws/cut-region-missing-end.svelte b/packages/twoslash-svelte/test/fixtures/script/throws/cut-region-missing-end.svelte new file mode 100644 index 00000000..ddc51836 --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/script/throws/cut-region-missing-end.svelte @@ -0,0 +1,10 @@ + + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/script/throws/cut-region-missing-start.svelte b/packages/twoslash-svelte/test/fixtures/script/throws/cut-region-missing-start.svelte new file mode 100644 index 00000000..960a9821 --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/script/throws/cut-region-missing-start.svelte @@ -0,0 +1,10 @@ + + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/template/throws/cut-region-missing-end.svelte b/packages/twoslash-svelte/test/fixtures/template/throws/cut-region-missing-end.svelte new file mode 100644 index 00000000..0b6a8043 --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/template/throws/cut-region-missing-end.svelte @@ -0,0 +1,10 @@ + + + diff --git a/packages/twoslash-svelte/test/fixtures/template/throws/cut-region-missing-start.svelte b/packages/twoslash-svelte/test/fixtures/template/throws/cut-region-missing-start.svelte new file mode 100644 index 00000000..1345c62b --- /dev/null +++ b/packages/twoslash-svelte/test/fixtures/template/throws/cut-region-missing-start.svelte @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/script/throws/cut-region-missing-end.txt b/packages/twoslash-svelte/test/results/script/throws/cut-region-missing-end.txt new file mode 100644 index 00000000..08afe7ba --- /dev/null +++ b/packages/twoslash-svelte/test/results/script/throws/cut-region-missing-end.txt @@ -0,0 +1,6 @@ + +## Mismatched cut markers + +You have unclosed cut-starts at lines 83 + +Make sure you have a matching pair for each. \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/script/throws/cut-region-missing-start.txt b/packages/twoslash-svelte/test/results/script/throws/cut-region-missing-start.txt new file mode 100644 index 00000000..f99d72ee --- /dev/null +++ b/packages/twoslash-svelte/test/results/script/throws/cut-region-missing-start.txt @@ -0,0 +1,6 @@ + +## Mismatched cut markers + +You have an unclosed the cut-end at line 8 + +Make sure you have a matching pair for each. \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/template/throws/cut-region-missing-end.txt b/packages/twoslash-svelte/test/results/template/throws/cut-region-missing-end.txt new file mode 100644 index 00000000..eca58750 --- /dev/null +++ b/packages/twoslash-svelte/test/results/template/throws/cut-region-missing-end.txt @@ -0,0 +1,6 @@ + +## Mismatched cut markers + +You have unclosed cut-starts at lines 96 + +Make sure you have a matching pair for each. \ No newline at end of file diff --git a/packages/twoslash-svelte/test/results/template/throws/cut-region-missing-start.txt b/packages/twoslash-svelte/test/results/template/throws/cut-region-missing-start.txt new file mode 100644 index 00000000..35f5bead --- /dev/null +++ b/packages/twoslash-svelte/test/results/template/throws/cut-region-missing-start.txt @@ -0,0 +1,6 @@ + +## Mismatched cut markers + +You have unclosed cut-ends at lines 157 + +Make sure you have a matching pair for each. \ No newline at end of file From a617166b4e32ababb677aee15e97fc07959607c7 Mon Sep 17 00:00:00 2001 From: Hugos68 Date: Sun, 7 Jun 2026 22:37:41 +0200 Subject: [PATCH 12/14] fix error in core package --- .../test/results/script/throws/cut-region-missing-start.txt | 2 +- packages/twoslash/src/utils.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/twoslash-svelte/test/results/script/throws/cut-region-missing-start.txt b/packages/twoslash-svelte/test/results/script/throws/cut-region-missing-start.txt index f99d72ee..f45aebf0 100644 --- a/packages/twoslash-svelte/test/results/script/throws/cut-region-missing-start.txt +++ b/packages/twoslash-svelte/test/results/script/throws/cut-region-missing-start.txt @@ -1,6 +1,6 @@ ## Mismatched cut markers -You have an unclosed the cut-end at line 8 +You have unclosed cut-ends at lines 8 Make sure you have a matching pair for each. \ No newline at end of file diff --git a/packages/twoslash/src/utils.ts b/packages/twoslash/src/utils.ts index 88180baa..28457763 100644 --- a/packages/twoslash/src/utils.ts +++ b/packages/twoslash/src/utils.ts @@ -289,7 +289,7 @@ export function findCutNotations(code: string, meta: Pick Date: Mon, 8 Jun 2026 15:07:10 +0200 Subject: [PATCH 13/14] update --- packages/twoslash-svelte/src/index.ts | 158 +++++------------- .../script/throws/cut-region-missing-end.txt | 4 +- .../throws/cut-region-missing-start.txt | 4 +- .../throws/cut-region-missing-start.txt | 2 +- packages/twoslash/src/utils.ts | 44 +++-- .../throws/unmatched-cut-range-count.txt | 4 +- .../results/throws/unmatched-cut-ranges.txt | 2 +- 7 files changed, 78 insertions(+), 140 deletions(-) diff --git a/packages/twoslash-svelte/src/index.ts b/packages/twoslash-svelte/src/index.ts index 31858fe7..a6316b28 100644 --- a/packages/twoslash-svelte/src/index.ts +++ b/packages/twoslash-svelte/src/index.ts @@ -1,16 +1,14 @@ import type { CodeMapping } from '@volar/language-core' -import type { Node } from 'estree-walker' -import type { AST } from 'svelte/compiler' import type { CompilerOptionDeclaration, CreateTwoslashOptions, HandbookOptions, Range, TwoslashExecuteOptions, TwoslashInstance, TwoslashReturnMeta } from 'twoslash' import { createRequire } from 'node:module' import { join } from 'node:path' import { decode } from '@jridgewell/sourcemap-codec' import { SourceMap } from '@volar/language-core' -import { walk } from 'estree-walker' import { svelte2tsx } from 'svelte2tsx' import { parse } from 'svelte/compiler' import { createTwoslasher as _createTwoSlasher, defaultCompilerOptions, defaultHandbookOptions, findFlagNotations, findQueryMarkers } from 'twoslash' import { createPositionConverter, removeCodeRanges, resolveNodePositions } from 'twoslash-protocol' +import { findCutNotations } from 'twoslash/core' import ts from 'typescript' export interface CreateTwoslashSvelteOptions extends CreateTwoslashOptions { @@ -155,32 +153,18 @@ export function createTwoslasher(createOptions: CreateTwoslashSvelteOptions = {} const ast = parse(strippedCode, { modern: true }) + findCutNotations(code, sourceMeta, { + reCutBefore: /^$/, + reCutAfter: /^$/, + reCutStart: /^$/, + reCutEnd: /^$/, + }) + const mappedRemovals = [ ...sourceMeta.removals, - ...findMarkupRemovals(code), - ...result.meta.removals.map((r) => { - const instanceContent = hasRange(ast.instance?.content) ? ast.instance.content : undefined - const moduleContent = hasRange(ast.module?.content) ? ast.module.content : undefined - - let start = get(map.toSourceLocation(r[0]), 0)?.[0] - let end = get(map.toSourceLocation(r[1]), 0)?.[0] - - // Determine which script block this removal belongs to based on start position - const scriptContent = start != null - ? (instanceContent && start >= instanceContent.start && start <= instanceContent.end ? instanceContent : undefined) - ?? (moduleContent && start >= moduleContent.start && start <= moduleContent.end ? moduleContent : undefined) - : instanceContent ?? moduleContent - - start ??= scriptContent?.start - if (end == null && scriptContent != null && r[1] > scriptContent.end) { - end = scriptContent.end - } - - if (start == null || end == null || start < 0 || end < 0 || start >= end) { - return undefined - } - return clampRemovalToScriptBoundaries(start, end, ast) as Range | undefined - }).filter(value => value != null), + ...result.meta.removals + .map(r => mapRemovalToSource(r, map, ast)) + .filter(value => value != null), ] if (!options.handbookOptions?.keepNotations) { @@ -301,98 +285,40 @@ function generateSourceMap( return new SourceMap(mappings) } -function findMarkupRemovals(code: string): Range[] { - const ast = parse(code, { modern: true }) - - const comments: Array<{ start: number, end: number, data: string }> = [] - walk(ast as unknown as Node, { - enter(node: AST.SvelteNode) { - if (node.type === 'Comment') { - comments.push({ start: node.start, end: node.end, data: node.data.trim() }) - } - }, - }) - - const ranges: Range[] = [] - - const cuts = comments.filter(c => c.data === '---cut---' || c.data === '---cut-before---') - const cutAfters = comments.filter(c => c.data === '---cut-after---') - const cutStarts = comments.filter(c => c.data === '---cut-start---') - const cutEnds = comments.filter(c => c.data === '---cut-end---') - - for (const comment of cuts) { - const end = code[comment.end] === '\n' ? comment.end + 1 : comment.end - ranges.push([0, end]) - } - - for (const comment of cutAfters) { - ranges.push([comment.start, code.length]) - } - - for (let i = 0; i < cutStarts.length; i++) { - const start = cutStarts[i] - const end = cutEnds[i] - if (!start || !end) { - continue - } - const rangeEnd = code[end.end] === '\n' ? end.end + 1 : end.end - ranges.push([start.start, rangeEnd]) - } - - if (cutStarts.length > cutEnds.length) { - throw new Error( - ` -## Mismatched cut markers - -You have unclosed cut-starts at lines ${cutStarts.slice(cutEnds.length).map(c => c.start).join(', ')} - -Make sure you have a matching pair for each.`, - ) - } - if (cutEnds.length > cutStarts.length) { - throw new Error( - ` -## Mismatched cut markers - -You have unclosed cut-ends at lines ${cutEnds.slice(cutStarts.length).map(c => c.start).join(', ')} - -Make sure you have a matching pair for each.`, - ) - } - - return ranges -} - -function clampRemovalToScriptBoundaries( - start: number, - end: number, +function mapRemovalToSource( + r: Range, + map: SourceMap, ast: ReturnType, -): [number, number] | undefined { - const scriptBlocks = [ - ast.instance, - ast.module, - ].filter(block => block != null) - - for (const block of scriptBlocks) { - const tagStart = block.start // start of `` - const contentEnd = block.content.end // just before `` - const tagEnd = block.end // end of `` - - // removal starts before script block content, clamp it forward - if (start < contentStart && end > tagStart) { - start = contentStart - } - // removal ends after script block content, clamp it back - if (end > contentEnd && start < tagEnd) { - end = contentEnd - } - // after clamping, the range may have become invalid - if (start >= end) { - return undefined - } +): Range | undefined { + const instanceContent = hasRange(ast.instance?.content) ? ast.instance.content : undefined + const moduleContent = hasRange(ast.module?.content) ? ast.module.content : undefined + + let start = get(map.toSourceLocation(r[0]), 0)?.[0] + let end = get(map.toSourceLocation(r[1]), 0)?.[0] + + // Determine which script block this removal belongs to + const scriptContent = start != null + ? (instanceContent && start >= instanceContent.start && start <= instanceContent.end ? instanceContent : undefined) + ?? (moduleContent && start >= moduleContent.start && start <= moduleContent.end ? moduleContent : undefined) + : instanceContent ?? moduleContent + + // Fall back to script boundaries for unmappable positions + start ??= scriptContent?.start + if (end == null && scriptContent != null && r[1] > scriptContent.end) + end = scriptContent.end + + if (start == null || end == null || start < 0 || end < 0 || start >= end) + return undefined + + // Clamp to script content boundaries to protect