fix(compiler): Addressed infinite loop in compiler (#3992)

close #3987
This commit is contained in:
Austin Keener 2021-07-15 14:57:47 -04:00 committed by GitHub
parent 7013e8f578
commit e00aa56658
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 90 additions and 4 deletions

View File

@ -35,3 +35,29 @@ exports[`compiler: codeframe multi-line highlights 1`] = `
4 | \\"> 4 | \\">
| ^" | ^"
`; `;
exports[`compiler: codeframe newline sequences - unix 1`] = `
"8 | <input name=\\"email\\" type=\\"text\\"/>
9 | </div>
10 | <div id=\\"hook\\">
| ^^^^^^^^^^^^^^^
11 | <label for=\\"password\\">Password</label>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12 | <input name=\\"password\\" type=\\"password\\"/>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
13 | </div>
| ^^^^^^^^^^^^"
`;
exports[`compiler: codeframe newline sequences - windows 1`] = `
"8 | <input name=\\"email\\" type=\\"text\\"/>
9 | </div>
10 | <div id=\\"hook\\">
| ^^^^^^^^^^^^^^^
11 | <label for=\\"password\\">Password</label>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12 | <input name=\\"password\\" type=\\"password\\"/>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
13 | </div>
| ^^^^^^^^^^^^"
`;

View File

@ -43,4 +43,49 @@ attr
const attrEnd = source.indexOf(`">`) + 1 const attrEnd = source.indexOf(`">`) + 1
expect(generateCodeFrame(source, attrStart, attrEnd)).toMatchSnapshot() expect(generateCodeFrame(source, attrStart, attrEnd)).toMatchSnapshot()
}) })
{
const source = `
<template>
<div>
<h1>Sign In</h1>
<form>
<div>
<label for="email">Email</label>
<input name="email" type="text"/>
</div>
<div id="hook">
<label for="password">Password</label>
<input name="password" type="password"/>
</div>
</form>
</div>
</template>
`
const startToken = '<div id="hook">'
const endToken = '</div>'
// 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()
})
}
}) })

View File

@ -5,11 +5,22 @@ export function generateCodeFrame(
start = 0, start = 0,
end = source.length end = source.length
): string { ): 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 let count = 0
const res: string[] = [] const res: string[] = []
for (let i = 0; i < lines.length; i++) { 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) { if (count >= start) {
for (let j = i - range; j <= i + range || end > count; j++) { for (let j = i - range; j <= i + range || end > count; j++) {
if (j < 0 || j >= lines.length) continue if (j < 0 || j >= lines.length) continue
@ -20,9 +31,12 @@ export function generateCodeFrame(
}` }`
) )
const lineLength = lines[j].length const lineLength = lines[j].length
const newLineSeqLength =
(newlineSequences[j] && newlineSequences[j].length) || 0
if (j === i) { if (j === i) {
// push underline // push underline
const pad = start - (count - lineLength) + 1 const pad = start - (count - (lineLength + newLineSeqLength))
const length = Math.max( const length = Math.max(
1, 1,
end > count ? lineLength - pad : end - start end > count ? lineLength - pad : end - start
@ -33,7 +47,8 @@ export function generateCodeFrame(
const length = Math.max(Math.min(end - count, lineLength), 1) const length = Math.max(Math.min(end - count, lineLength), 1)
res.push(` | ` + '^'.repeat(length)) res.push(` | ` + '^'.repeat(length))
} }
count += lineLength + 1
count += lineLength + newLineSeqLength
} }
} }
break break