diff --git a/packages/vite/src/node/__tests__/__snapshots__/utils.spec.ts.snap b/packages/vite/src/node/__tests__/__snapshots__/utils.spec.ts.snap index 806e9eba2be8ce..ccf43c253a01b3 100644 --- a/packages/vite/src/node/__tests__/__snapshots__/utils.spec.ts.snap +++ b/packages/vite/src/node/__tests__/__snapshots__/utils.spec.ts.snap @@ -60,6 +60,62 @@ exports[`generateCodeFrames > invalid start > end 1`] = ` " `; +exports[`generateCodeFrames > long line (center) 1`] = ` +" +1 | ...aaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccccc... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2 | short line +3 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb... +" +`; + +exports[`generateCodeFrames > long line (end) 1`] = ` +" +1 | ...bbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2 | short line +3 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb... +" +`; + +exports[`generateCodeFrames > long line (multiline 1) 1`] = ` +" +1 | ...bbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc + | ^^^^^^^^^^ +2 | short line + | ^^^^^^ +3 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb... +" +`; + +exports[`generateCodeFrames > long line (multiline 2) 1`] = ` +" +1 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb... +2 | short line + | ^^^^^ +3 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +" +`; + +exports[`generateCodeFrames > long line (start) 1`] = ` +" +1 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2 | short line +3 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb... +" +`; + +exports[`generateCodeFrames > long line (whole) 1`] = ` +" +1 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2 | short line +3 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb... +" +`; + exports[`generateCodeFrames > range 1`] = ` " 1 | import foo from './foo' diff --git a/packages/vite/src/node/__tests__/utils.spec.ts b/packages/vite/src/node/__tests__/utils.spec.ts index 9dbf6784994f07..2382179292c87b 100644 --- a/packages/vite/src/node/__tests__/utils.spec.ts +++ b/packages/vite/src/node/__tests__/utils.spec.ts @@ -347,6 +347,72 @@ foo() test('supports more than 1000 lines', () => { expectSnapshot(generateCodeFrame(veryLongSource, { line: 1200, column: 0 })) }) + + test('long line (start)', () => { + const longLine = 'a'.repeat(60) + 'b'.repeat(60) + 'c'.repeat(60) + const src = `${longLine}\nshort line\n${longLine}` + const frame = generateCodeFrame( + src, + { line: 1, column: 0 }, + { line: 1, column: 30 }, + ) + expectSnapshot(frame) + }) + + test('long line (center)', () => { + const longLine = 'a'.repeat(60) + 'b'.repeat(60) + 'c'.repeat(60) + const src = `${longLine}\nshort line\n${longLine}` + const frame = generateCodeFrame( + src, + { line: 1, column: 90 }, + { line: 1, column: 120 }, + ) + expectSnapshot(frame) + }) + + test('long line (end)', () => { + const longLine = 'a'.repeat(60) + 'b'.repeat(60) + 'c'.repeat(60) + const src = `${longLine}\nshort line\n${longLine}` + const frame = generateCodeFrame( + src, + { line: 1, column: 150 }, + { line: 1, column: 180 }, + ) + expectSnapshot(frame) + }) + + test('long line (whole)', () => { + const longLine = 'a'.repeat(60) + 'b'.repeat(60) + 'c'.repeat(60) + const src = `${longLine}\nshort line\n${longLine}` + const frame = generateCodeFrame( + src, + { line: 1, column: 0 }, + { line: 1, column: 180 }, + ) + expectSnapshot(frame) + }) + + test('long line (multiline 1)', () => { + const longLine = 'a'.repeat(60) + 'b'.repeat(60) + 'c'.repeat(60) + const src = `${longLine}\nshort line\n${longLine}` + const frame = generateCodeFrame( + src, + { line: 1, column: 170 }, + { line: 2, column: 5 }, + ) + expectSnapshot(frame) + }) + + test('long line (multiline 2)', () => { + const longLine = 'a'.repeat(60) + 'b'.repeat(60) + 'c'.repeat(60) + const src = `${longLine}\nshort line\n${longLine}` + const frame = generateCodeFrame( + src, + { line: 2, column: 5 }, + { line: 3, column: 30 }, + ) + expectSnapshot(frame) + }) }) describe('getHash', () => { diff --git a/packages/vite/src/node/plugins/html.ts b/packages/vite/src/node/plugins/html.ts index 4bdc175c72e5dc..18eb44d2294ef1 100644 --- a/packages/vite/src/node/plugins/html.ts +++ b/packages/vite/src/node/plugins/html.ts @@ -336,7 +336,7 @@ function handleParseError( warnings[parseError.code] ??= `Unable to parse HTML; ${parseError.message}\n` + ` at ${parseError.loc.file}:${parseError.loc.line}:${parseError.loc.column}\n` + - `${parseError.frame.length > 300 ? '[this code frame is omitted as the content was too long] ' : parseError.frame}` + parseError.frame } /** diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index 912ba0172e9139..937c4cc8c2300d 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -498,6 +498,9 @@ export function numberToPos(source: string, offset: number | Pos): Pos { } } +const MAX_DISPLAY_LEN = 120 +const ELLIPSIS = '...' + export function generateCodeFrame( source: string, start: number | Pos = 0, @@ -522,28 +525,51 @@ export function generateCodeFrame( for (let j = i - range; j <= i + range || end > count; j++) { if (j < 0 || j >= lines.length) continue const line = j + 1 + const lineLength = lines[j].length + const pad = Math.max(start - (count - lineLength), 0) + const underlineLength = Math.max( + 1, + end > count ? lineLength - pad : end - start, + ) + + let displayLine = lines[j] + let underlinePad = pad + if (lineLength > MAX_DISPLAY_LEN) { + let startIdx = 0 + if (j === i) { + if (underlineLength > MAX_DISPLAY_LEN) { + startIdx = pad + } else { + const center = pad + Math.floor(underlineLength / 2) + startIdx = Math.max(0, center - Math.floor(MAX_DISPLAY_LEN / 2)) + } + underlinePad = + Math.max(0, pad - startIdx) + (startIdx > 0 ? ELLIPSIS.length : 0) + } + const prefix = startIdx > 0 ? ELLIPSIS : '' + const suffix = lineLength - startIdx > MAX_DISPLAY_LEN ? ELLIPSIS : '' + const sliceLen = MAX_DISPLAY_LEN - prefix.length - suffix.length + displayLine = + prefix + displayLine.slice(startIdx, startIdx + sliceLen) + suffix + } res.push( - `${line}${' '.repeat(lineNumberWidth - String(line).length)}| ${ - lines[j] - }`, + `${line}${' '.repeat(lineNumberWidth - String(line).length)}| ${displayLine}`, ) - const lineLength = lines[j].length if (j === i) { // push underline - const pad = Math.max(start - (count - lineLength), 0) - const length = Math.max( - 1, - end > count ? lineLength - pad : end - start, + const underline = '^'.repeat( + Math.min(underlineLength, MAX_DISPLAY_LEN), ) res.push( `${' '.repeat(lineNumberWidth)}| ` + - ' '.repeat(pad) + - '^'.repeat(length), + ' '.repeat(underlinePad) + + underline, ) } else if (j > i) { if (end > count) { const length = Math.max(Math.min(end - count, lineLength), 1) - res.push(`${' '.repeat(lineNumberWidth)}| ` + '^'.repeat(length)) + const underline = '^'.repeat(Math.min(length, MAX_DISPLAY_LEN)) + res.push(`${' '.repeat(lineNumberWidth)}| ` + underline) } count += lineLength + 1 }