Skip to content

Commit

Permalink
Fix crash on parse error when custom line or offset is specified
Browse files Browse the repository at this point in the history
  • Loading branch information
lahmatiy committed Oct 15, 2023
1 parent fcf61f4 commit ba6dfd8
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -11,6 +11,7 @@
- Added `TokenStream#lookupTypeNonSC()` method
- Fixed initialization when `Object.prototype` is extended or polluted (#262)
- Fixed `speak` syntax patch (#241)
- Fixed crash on parse error when custom `line` or `offset` is specified via options (#251)
- Changed `parseWithFallback()` to rollback `tokenIndex` before calling a fallback
- Changed `Block` to not include `{` and `}`
- Changed `Atrule` and `Rule` to include `{` and `}` for a block
Expand Down
29 changes: 29 additions & 0 deletions lib/__tests/parse.js
Expand Up @@ -286,6 +286,35 @@ describe('parse', () => {
}
);
});

it('with custom offset/line/column', () => {
assert.throws(
() => parse(
'#.classname\n\n\n',
{ context: 'selector', positions: true, offset: 10, line: 10, column: 10 }
),
(e) => {
assert.strictEqual(e.formattedMessage,
'Parse error: Name is expected\n' +
' 10 | #.classname\n' +
'-----------------^'
);
assert.deepStrictEqual({
source: '#.classname\n\n\n',
offset: 11,
line: 10,
column: 11
}, {
source: e.source,
offset: e.offset,
line: e.line,
column: e.column
});

return true;
}
);
});
});

describe('onComment', () => {
Expand Down
17 changes: 11 additions & 6 deletions lib/parser/SyntaxError.js
Expand Up @@ -4,7 +4,7 @@ const MAX_LINE_LENGTH = 100;
const OFFSET_CORRECTION = 60;
const TAB_REPLACEMENT = ' ';

function sourceFragment({ source, line, column }, extraLines) {
function sourceFragment({ source, line, column, baseLine, baseColumn }, extraLines) {
function processLines(start, end) {
return lines
.slice(start, end)
Expand All @@ -13,7 +13,9 @@ function sourceFragment({ source, line, column }, extraLines) {
).join('\n');
}

const lines = source.split(/\r\n?|\n|\f/);
const prelines = '\n'.repeat(Math.max(baseLine - 1, 0));
const precolumns = ' '.repeat(Math.max(baseColumn - 1, 0));
const lines = (prelines + precolumns + source).split(/\r\n?|\n|\f/);
const startLine = Math.max(1, line - extraLines) - 1;
const endLine = Math.min(line + extraLines, lines.length + 1);
const maxNumLength = Math.max(4, String(endLine).length) + 1;
Expand Down Expand Up @@ -41,22 +43,25 @@ function sourceFragment({ source, line, column }, extraLines) {
processLines(startLine, line),
new Array(column + maxNumLength + 2).join('-') + '^',
processLines(line, endLine)
].filter(Boolean).join('\n');
].filter(Boolean)
.join('\n')
.replace(/^(\s+\d+\s+\|\n)+/, '')
.replace(/\n(\s+\d+\s+\|)+$/, '');
}

export function SyntaxError(message, source, offset, line, column) {
export function SyntaxError(message, source, offset, line, column, baseLine = 1, baseColumn = 1) {
const error = Object.assign(createCustomError('SyntaxError', message), {
source,
offset,
line,
column,
sourceFragment(extraLines) {
return sourceFragment({ source, line, column }, isNaN(extraLines) ? 0 : extraLines);
return sourceFragment({ source, line, column, baseLine, baseColumn }, isNaN(extraLines) ? 0 : extraLines);
},
get formattedMessage() {
return (
`Parse error: ${message}\n` +
sourceFragment({ source, line, column }, 2)
sourceFragment({ source, line, column, baseLine, baseColumn }, 2)
);
}
});
Expand Down
4 changes: 3 additions & 1 deletion lib/parser/create.js
Expand Up @@ -286,7 +286,9 @@ export function createParser(config) {
source,
location.offset,
location.line,
location.column
location.column,
locationMap.startLine,
locationMap.startColumn
);
}
});
Expand Down

0 comments on commit ba6dfd8

Please sign in to comment.