diff --git a/packages/shared/__tests__/__snapshots__/codeframe.spec.ts.snap b/packages/shared/__tests__/__snapshots__/codeframe.spec.ts.snap
index 89a4c2635..579a4507d 100644
--- a/packages/shared/__tests__/__snapshots__/codeframe.spec.ts.snap
+++ b/packages/shared/__tests__/__snapshots__/codeframe.spec.ts.snap
@@ -35,3 +35,29 @@ exports[`compiler: codeframe multi-line highlights 1`] = `
4 | \\">
| ^"
`;
+
+exports[`compiler: codeframe newline sequences - unix 1`] = `
+"8 |
+9 |
+10 |
+ | ^^^^^^^^^^^^^^^
+11 |
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+12 |
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+13 |
+ | ^^^^^^^^^^^^"
+`;
+
+exports[`compiler: codeframe newline sequences - windows 1`] = `
+"8 |
+9 |
+10 |
+ | ^^^^^^^^^^^^^^^
+11 |
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+12 |
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+13 |
+ | ^^^^^^^^^^^^"
+`;
diff --git a/packages/shared/__tests__/codeframe.spec.ts b/packages/shared/__tests__/codeframe.spec.ts
index eb86a6784..508310048 100644
--- a/packages/shared/__tests__/codeframe.spec.ts
+++ b/packages/shared/__tests__/codeframe.spec.ts
@@ -43,4 +43,49 @@ attr
const attrEnd = source.indexOf(`">`) + 1
expect(generateCodeFrame(source, attrStart, attrEnd)).toMatchSnapshot()
})
+
+ {
+ const source = `
+
+
+
+`
+ const startToken = ''
+ const endToken = '
'
+
+ // Explicitly ensure the line-ending for the platform instead of assuming
+ // the newline sequences used in the source above.
+ const unixNewlineSource = source.replace(/\r\n/g, '\n')
+ const windowsNewLineSource = unixNewlineSource.replace(/\n/g, '\r\n')
+
+ test('newline sequences - windows', () => {
+ const keyStart = windowsNewLineSource.indexOf(startToken)
+ const keyEnd =
+ windowsNewLineSource.indexOf(endToken, keyStart) + endToken.length
+ expect(
+ generateCodeFrame(windowsNewLineSource, keyStart, keyEnd)
+ ).toMatchSnapshot()
+ })
+
+ test('newline sequences - unix', () => {
+ const keyStart = unixNewlineSource.indexOf(startToken)
+ const keyEnd =
+ unixNewlineSource.indexOf(endToken, keyStart) + endToken.length
+ expect(
+ generateCodeFrame(unixNewlineSource, keyStart, keyEnd)
+ ).toMatchSnapshot()
+ })
+ }
})
diff --git a/packages/shared/src/codeframe.ts b/packages/shared/src/codeframe.ts
index f11432cd9..82b38bfb3 100644
--- a/packages/shared/src/codeframe.ts
+++ b/packages/shared/src/codeframe.ts
@@ -5,11 +5,22 @@ export function generateCodeFrame(
start = 0,
end = source.length
): string {
- const lines = source.split(/\r?\n/)
+ // Split the content into individual lines but capture the newline sequence
+ // that separated each line. This is important because the actual sequence is
+ // needed to properly take into account the full line length for offset
+ // comparison
+ let lines = source.split(/(\r?\n)/)
+
+ // Separate the lines and newline sequences into separate arrays for easier referencing
+ const newlineSequences = lines.filter((_, idx) => idx % 2 === 1)
+ lines = lines.filter((_, idx) => idx % 2 === 0)
+
let count = 0
const res: string[] = []
for (let i = 0; i < lines.length; i++) {
- count += lines[i].length + 1
+ count +=
+ lines[i].length +
+ ((newlineSequences[i] && newlineSequences[i].length) || 0)
if (count >= start) {
for (let j = i - range; j <= i + range || end > count; j++) {
if (j < 0 || j >= lines.length) continue
@@ -20,9 +31,12 @@ export function generateCodeFrame(
}`
)
const lineLength = lines[j].length
+ const newLineSeqLength =
+ (newlineSequences[j] && newlineSequences[j].length) || 0
+
if (j === i) {
// push underline
- const pad = start - (count - lineLength) + 1
+ const pad = start - (count - (lineLength + newLineSeqLength))
const length = Math.max(
1,
end > count ? lineLength - pad : end - start
@@ -33,7 +47,8 @@ export function generateCodeFrame(
const length = Math.max(Math.min(end - count, lineLength), 1)
res.push(` | ` + '^'.repeat(length))
}
- count += lineLength + 1
+
+ count += lineLength + newLineSeqLength
}
}
break