diff --git a/packages/twoslash-svelte/package.json b/packages/twoslash-svelte/package.json index a326c115..a1771ab0 100644 --- a/packages/twoslash-svelte/package.json +++ b/packages/twoslash-svelte/package.json @@ -46,11 +46,13 @@ "start": "esno src/index.ts" }, "peerDependencies": { + "svelte": ">=5", "typescript": "*" }, "dependencies": { "@jridgewell/sourcemap-codec": "catalog:", "@volar/language-core": "catalog:", + "estree-walker": "catalog:", "svelte2tsx": "catalog:", "twoslash": "workspace:*", "twoslash-protocol": "workspace:*" diff --git a/packages/twoslash-svelte/src/index.ts b/packages/twoslash-svelte/src/index.ts index 49e260bd..c0736c9e 100644 --- a/packages/twoslash-svelte/src/index.ts +++ b/packages/twoslash-svelte/src/index.ts @@ -4,8 +4,10 @@ import { createRequire } from 'node:module' import { decode } from '@jridgewell/sourcemap-codec' import { SourceMap } from '@volar/language-core' import { svelte2tsx } from 'svelte2tsx' +import { parse } from 'svelte/compiler' import { createTwoslasher as createTwoSlasherBase, 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 { @@ -78,6 +80,7 @@ export function createTwoslasher(createOptions: CreateTwoslashSvelteOptions = {} } const compiled = svelte2tsx(strippedCode) + const map = generateSourceMap(strippedCode, compiled.code, compiled.map.mappings) function getLastGeneratedOffset(pos: number) { @@ -146,16 +149,20 @@ export function createTwoslasher(createOptions: CreateTwoslashSvelteOptions = {} }) .filter(value => value != null) + const ast = parse(strippedCode, { modern: true }) + + findCutNotations(code, sourceMeta, { + reCutBefore: /^$/, + reCutAfter: /^$/, + reCutStart: /^$/, + reCutEnd: /^$/, + }) + const mappedRemovals = [ ...sourceMeta.removals, - ...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] - if (start == null || end == null || start < 0 || end < 0 || start >= end) { - return undefined - } - return [start, end] as Range - }).filter(value => value != null), + ...result.meta.removals + .map(r => mapRemovalToSource(r, map, ast)) + .filter(value => value != null), ] if (!options.handbookOptions?.keepNotations) { @@ -275,3 +282,49 @@ function generateSourceMap( } return new SourceMap(mappings) } + +function mapRemovalToSource( + r: Range, + map: SourceMap, + ast: ReturnType, +): 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 - \ 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/cut-around.svelte b/packages/twoslash-svelte/test/fixtures/script/cut-before.svelte similarity index 86% rename from packages/twoslash-svelte/test/fixtures/cut-around.svelte rename to packages/twoslash-svelte/test/fixtures/script/cut-before.svelte index 3e25b2d0..7230c851 100644 --- a/packages/twoslash-svelte/test/fixtures/cut-around.svelte +++ b/packages/twoslash-svelte/test/fixtures/script/cut-before.svelte @@ -1,13 +1,10 @@ - \ No newline at end of file diff --git a/packages/twoslash-svelte/test/fixtures/cut-in.svelte b/packages/twoslash-svelte/test/fixtures/script/cut-region.svelte similarity index 97% rename from packages/twoslash-svelte/test/fixtures/cut-in.svelte rename to packages/twoslash-svelte/test/fixtures/script/cut-region.svelte index f5c9365d..de7803ae 100644 --- a/packages/twoslash-svelte/test/fixtures/cut-in.svelte +++ b/packages/twoslash-svelte/test/fixtures/script/cut-region.svelte @@ -1,13 +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/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/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/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/completion.json b/packages/twoslash-svelte/test/results/script/completion.json similarity index 90% rename from packages/twoslash-svelte/test/results/completion.json rename to packages/twoslash-svelte/test/results/script/completion.json index 8a8816e6..66abf840 100644 --- a/packages/twoslash-svelte/test/results/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/cut-after.json b/packages/twoslash-svelte/test/results/script/cut-after.json new file mode 100644 index 00000000..1f4872e8 --- /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..3482dc8a --- /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": 21, + "length": 9, + "target": "increment", + "line": 0, + "character": 21 + }, + { + "type": "hover", + "text": "let count: number", + "start": 43, + "length": 5, + "target": "count", + "line": 1, + "character": 8 + }, + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 85, + "length": 9, + "target": "increment", + "line": 4, + "character": 17 + }, + { + "type": "hover", + "text": "let count: number", + "start": 112, + "length": 5, + "target": "count", + "line": 5, + "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/script/cut-region.json similarity index 83% rename from packages/twoslash-svelte/test/results/cut-in.json rename to packages/twoslash-svelte/test/results/script/cut-region.json index 7b69cb24..2d31fc88 100644 --- a/packages/twoslash-svelte/test/results/cut-in.json +++ b/packages/twoslash-svelte/test/results/script/cut-region.json @@ -1,5 +1,5 @@ { - "code": "\n\n", + "code": "\n", "nodes": [ { "type": "hover", @@ -33,19 +33,19 @@ { "type": "hover", "text": "(local function) increment(): void", - "start": 69, + "start": 63, "length": 9, "target": "increment", - "line": 5, + "line": 3, "character": 17 }, { "type": "hover", "text": "let count: number", - "start": 96, + "start": 90, "length": 5, "target": "count", - "line": 6, + "line": 4, "character": 15 } ], 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..3482dc8a --- /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": 21, + "length": 9, + "target": "increment", + "line": 0, + "character": 21 + }, + { + "type": "hover", + "text": "let count: number", + "start": 43, + "length": 5, + "target": "count", + "line": 1, + "character": 8 + }, + { + "type": "hover", + "text": "(local function) increment(): void", + "start": 85, + "length": 9, + "target": "increment", + "line": 4, + "character": 17 + }, + { + "type": "hover", + "text": "let count: number", + "start": 112, + "length": 5, + "target": "count", + "line": 5, + "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 81% rename from packages/twoslash-svelte/test/results/hover.json rename to packages/twoslash-svelte/test/results/script/hover.json index 99056edd..43642528 100644 --- a/packages/twoslash-svelte/test/results/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/query.json b/packages/twoslash-svelte/test/results/script/query.json similarity index 85% rename from packages/twoslash-svelte/test/results/query.json rename to packages/twoslash-svelte/test/results/script/query.json index 13e09080..33f6d133 100644 --- a/packages/twoslash-svelte/test/results/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 } ], 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..a5030398 --- /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 line(s) 5 + +Add a cut-end after each cut-start. \ 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..b28a698b --- /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 cut-end at line 8 + +Add a cut-start before line 8. \ No newline at end of file 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/cut-around.json b/packages/twoslash-svelte/test/results/template/cut-before.json similarity index 55% rename from packages/twoslash-svelte/test/results/cut-around.json rename to packages/twoslash-svelte/test/results/template/cut-before.json index 75817fde..f412d47b 100644 --- a/packages/twoslash-svelte/test/results/cut-around.json +++ b/packages/twoslash-svelte/test/results/template/cut-before.json @@ -1,14 +1,14 @@ { - "code": "\n\n", + "code": "", "nodes": [ { "type": "hover", "text": "(local function) increment(): void", - "start": 22, + "start": 17, "length": 9, "target": "increment", - "line": 1, - "character": 13 + "line": 0, + "character": 17 }, { "type": "hover", @@ -16,8 +16,8 @@ "start": 44, "length": 5, "target": "count", - "line": 2, - "character": 8 + "line": 1, + "character": 15 } ], "flags": [] 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/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..1f1b463c --- /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 line(s) 7 + +Add a cut-end after each cut-start. \ 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..a385c5a1 --- /dev/null +++ b/packages/twoslash-svelte/test/results/template/throws/cut-region-missing-start.txt @@ -0,0 +1,6 @@ + +## Mismatched cut markers + +You have an unclosed cut-end at line 10 + +Add a cut-start before line 10. \ No newline at end of file diff --git a/packages/twoslash/src/utils.ts b/packages/twoslash/src/utils.ts index 88180baa..473f955c 100644 --- a/packages/twoslash/src/utils.ts +++ b/packages/twoslash/src/utils.ts @@ -259,10 +259,22 @@ export function findFlagNotations(code: string, customTags: string[], tsOptionDe return flagNotations } -export function findCutNotations(code: string, meta: Pick) { +export interface FindCutNotationsOptions { + reCutBefore?: RegExp + reCutAfter?: RegExp + reCutStart?: RegExp + reCutEnd?: RegExp +} + +export function findCutNotations(code: string, meta: Pick, options: FindCutNotationsOptions = {}) { + const mergedReCutBefore = options.reCutBefore || reCutBefore + const mergedReCutAfter = options.reCutAfter || reCutAfter + const mergedReCutStart = options.reCutStart || reCutStart + const mergedReCutEnd = options.reCutEnd || reCutEnd + let removals: Range[] = [] const lines = code.split('\n') - const cutStarts: number[] = [] + const cutStarts: Array<{ idx: number, line: number }> = [] // start character after \n let idx = 0 let lineIndex = 0 @@ -270,38 +282,38 @@ export function findCutNotations(code: string, meta: Pick i > lineIndex && line.trim().match(reCutStart)) + if (start === undefined) { + const startLine = lines.findIndex((l, i) => i > lineIndex && l.trim().match(mergedReCutStart)) if (startLine === -1) { throw new TwoslashError( `Mismatched cut markers`, - `You have an unclosed the cut-end at line ${lineIndex + 1}`, - `Make sure you have a matching pair for each.`, + `You have an unclosed cut-end at line ${lineIndex + 1}`, + `Add a cut-start before line ${lineIndex + 1}.`, ) } throw new TwoslashError( `Mismatched cut markers`, `You have a cut-start at line ${startLine + 1} which is after the cut-end at line ${lineIndex + 1}`, - `Make sure you have a matching pair for each.`, + `Move the cut-start to before line ${lineIndex + 1}.`, ) } - removals.push([startIdx, idx + line.length + 1]) + removals.push([start.idx, idx + line.length + 1]) } lineIndex++ @@ -311,8 +323,8 @@ export function findCutNotations(code: string, meta: Pick 0) { throw new TwoslashError( `Mismatched cut markers`, - `You have unclosed cut-starts at lines ${cutStarts.join(', ')}`, - `Make sure you have a matching pair for each.`, + `You have unclosed cut-starts at line(s) ${cutStarts.map(s => s.line + 1).join(', ')}`, + `Add a cut-end after each cut-start.`, ) } diff --git a/packages/twoslash/test/results/throws/unmatched-cut-range-count.txt b/packages/twoslash/test/results/throws/unmatched-cut-range-count.txt index f214c475..a5030398 100644 --- a/packages/twoslash/test/results/throws/unmatched-cut-range-count.txt +++ b/packages/twoslash/test/results/throws/unmatched-cut-range-count.txt @@ -1,6 +1,6 @@ ## Mismatched cut markers -You have unclosed cut-starts at lines 60 +You have unclosed cut-starts at line(s) 5 -Make sure you have a matching pair for each. \ No newline at end of file +Add a cut-end after each cut-start. \ No newline at end of file diff --git a/packages/twoslash/test/results/throws/unmatched-cut-ranges.txt b/packages/twoslash/test/results/throws/unmatched-cut-ranges.txt index 5e4c1b62..236a52a4 100644 --- a/packages/twoslash/test/results/throws/unmatched-cut-ranges.txt +++ b/packages/twoslash/test/results/throws/unmatched-cut-ranges.txt @@ -3,4 +3,4 @@ You have a cut-start at line 4 which is after the cut-end at line 2 -Make sure you have a matching pair for each. \ No newline at end of file +Move the cut-start to before line 2. \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eac12cdb..5593f1c4 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 @@ -450,6 +453,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: 'catalog:' 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 43bb88dd..014a3901 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