Skip to content

Commit cb3e2a4

Browse files
authored
fix(twoslash): improve cuts parser & error messages (#77)
1 parent 73df28e commit cb3e2a4

File tree

5 files changed

+60
-32
lines changed

5 files changed

+60
-32
lines changed

packages/twoslash/src/regexp.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ export const reConfigBoolean = /^\/\/\s?@(\w+)$/gm
22
export const reConfigValue = /^\/\/\s?@(\w+):\s?(.+)$/gm
33
export const reAnnonateMarkers = /^\s*\/\/\s*\^(\?|\||\^+)( .*)?$/gm
44

5-
export const reCutBefore = /^[\t\v\f ]*\/\/\s?---cut(-before)?---\r?\n/gm
6-
export const reCutAfter = /^[\t\v\f ]*\/\/\s?---cut-after---$/gm
7-
export const reCutStart = /^[\t\v\f ]*\/\/\s?---cut-start---$/gm
8-
export const reCutEnd = /^[\t\v\f ]*\/\/\s?---cut-end---\r?\n/gm
5+
export const reCutBefore = /^\/\/\s?---cut(-before)?---$/
6+
export const reCutAfter = /^\/\/\s?---cut-after---$/
7+
export const reCutStart = /^\/\/\s?---cut-start---$/
8+
export const reCutEnd = /^\/\/\s?---cut-end---$/
99
export const reFilenamesMakers = /^[\t\v\f ]*\/\/\s?@filename: (.+)$/gm

packages/twoslash/src/utils.ts

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -260,40 +260,61 @@ export function findFlagNotations(code: string, customTags: string[], tsOptionDe
260260
}
261261

262262
export function findCutNotations(code: string, meta: Pick<TwoslashReturnMeta, 'removals'>) {
263-
const removals: Range[] = []
263+
let removals: Range[] = []
264+
const lines = code.split('\n')
265+
const cutStarts: number[] = []
266+
// start character after \n
267+
let idx = 0
268+
let lineIndex = 0
269+
270+
for (const line of lines) {
271+
const comment = line.trim()
272+
273+
if (comment.match(reCutBefore)) {
274+
removals = [[0, idx + line.length + 1]]
275+
}
276+
else if (comment.match(reCutAfter)) {
277+
removals.push([idx, code.length])
278+
break
279+
}
280+
else if (comment.match(reCutStart)) {
281+
cutStarts.push(idx)
282+
}
283+
else if (comment.match(reCutEnd)) {
284+
const startIdx = cutStarts.pop()
285+
286+
if (startIdx === undefined) {
287+
const startLine = lines.findIndex((line, i) => i > lineIndex && line.trim().match(reCutStart))
288+
289+
if (startLine === -1) {
290+
throw new TwoslashError(
291+
`Mismatched cut markers`,
292+
`You have an unclosed the cut-end at line ${lineIndex + 1}`,
293+
`Make sure you have a matching pair for each.`,
294+
)
295+
}
264296

265-
const cutBefore = [...code.matchAll(reCutBefore)]
266-
const cutAfter = [...code.matchAll(reCutAfter)]
267-
const cutStart = [...code.matchAll(reCutStart)]
268-
const cutEnd = [...code.matchAll(reCutEnd)]
297+
throw new TwoslashError(
298+
`Mismatched cut markers`,
299+
`You have a cut-start at line ${startLine + 1} which is after the cut-end at line ${lineIndex + 1}`,
300+
`Make sure you have a matching pair for each.`,
301+
)
302+
}
269303

270-
if (cutBefore.length) {
271-
const last = cutBefore[cutBefore.length - 1]
272-
removals.push([0, last.index! + last[0].length])
273-
}
274-
if (cutAfter.length) {
275-
const first = cutAfter[0]
276-
removals.push([first.index!, code.length])
304+
removals.push([startIdx, idx + line.length + 1])
305+
}
306+
307+
lineIndex++
308+
idx += line.length + 1
277309
}
278-
if (cutStart.length !== cutEnd.length) {
310+
311+
if (cutStarts.length > 0) {
279312
throw new TwoslashError(
280313
`Mismatched cut markers`,
281-
`You have ${cutStart.length} cut-starts and ${cutEnd.length} cut-ends`,
314+
`You have unclosed cut-starts at lines ${cutStarts.join(', ')}`,
282315
`Make sure you have a matching pair for each.`,
283316
)
284317
}
285-
for (let i = 0; i < cutStart.length; i++) {
286-
const start = cutStart[i]
287-
const end = cutEnd[i]
288-
if (start.index! > end.index!) {
289-
throw new TwoslashError(
290-
`Mismatched cut markers`,
291-
`You have a cut-start at ${start.index} which is after the cut-end at ${end.index}`,
292-
`Make sure you have a matching pair for each.`,
293-
)
294-
}
295-
removals.push([start.index!, end.index! + end[0].length])
296-
}
297318

298319
if (meta)
299320
meta.removals.push(...removals)

packages/twoslash/test/cutting.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,10 @@ describe('supports space before cut comments', () => {
140140
expect(hover1?.line).toEqual(hover2?.line)
141141
})
142142
})
143+
144+
describe('supports cut comments at end of file', () => {
145+
const file1 = `const x = "123"\n// ---cut-start---\n /** @type {"345"} */\n// ---cut-end---`
146+
it('works without error', () => {
147+
twoslasher(file1, 'ts')
148+
})
149+
})

packages/twoslash/test/results/throws/unmatched-cut-range-count.txt

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/twoslash/test/results/throws/unmatched-cut-ranges.txt

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)