Skip to content

Commit ad0d03f

Browse files
[7.x backport] feat: Allow specifying startLine in code frame (#17739)
Co-authored-by: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
1 parent 908e515 commit ad0d03f

4 files changed

Lines changed: 58 additions & 5 deletions

File tree

packages/babel-code-frame/src/index.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ export interface Options {
2222
linesAbove?: number;
2323
/** The number of lines to show below the error. default: 3 */
2424
linesBelow?: number;
25+
/** The line number corresponding to the first line in `rawLines`. default: 1 */
26+
startLine?: number;
2527
/**
2628
* Forcibly syntax highlight the code as JavaScript (for non-terminals);
2729
* overrides highlightCode.
@@ -53,6 +55,7 @@ function getMarkerLines(
5355
loc: NodeLocation,
5456
source: string[],
5557
opts: Options,
58+
startLineBaseZero: number,
5659
): {
5760
start: number;
5861
end: number;
@@ -68,9 +71,9 @@ function getMarkerLines(
6871
...loc.end,
6972
};
7073
const { linesAbove = 2, linesBelow = 3 } = opts || {};
71-
const startLine = startLoc.line;
74+
const startLine = startLoc.line - startLineBaseZero;
7275
const startColumn = startLoc.column;
73-
const endLine = endLoc.line;
76+
const endLine = endLoc.line - startLineBaseZero;
7477
const endColumn = endLoc.column;
7578

7679
let start = Math.max(startLine - (linesAbove + 1), 0);
@@ -127,13 +130,19 @@ export function codeFrameColumns(
127130
): string {
128131
const shouldHighlight =
129132
opts.forceColor || (isColorSupported() && opts.highlightCode);
133+
const startLineBaseZero = (opts.startLine || 1) - 1;
130134
const defs = getDefs(shouldHighlight);
131135

132136
const lines = rawLines.split(NEWLINE);
133-
const { start, end, markerLines } = getMarkerLines(loc, lines, opts);
137+
const { start, end, markerLines } = getMarkerLines(
138+
loc,
139+
lines,
140+
opts,
141+
startLineBaseZero,
142+
);
134143
const hasColumns = loc.start && typeof loc.start.column === "number";
135144

136-
const numberMaxWidth = String(end).length;
145+
const numberMaxWidth = String(end + startLineBaseZero).length;
137146

138147
const highlightedLines = shouldHighlight ? highlight(rawLines) : rawLines;
139148

@@ -142,7 +151,9 @@ export function codeFrameColumns(
142151
.slice(start, end)
143152
.map((line, index) => {
144153
const number = start + 1 + index;
145-
const paddedNumber = ` ${number}`.slice(-numberMaxWidth);
154+
const paddedNumber = ` ${number + startLineBaseZero}`.slice(
155+
-numberMaxWidth,
156+
);
146157
const gutter = ` ${paddedNumber} |`;
147158
const hasMarker = markerLines[number];
148159
const lastMarkerLine = !markerLines[number + 1];

packages/babel-code-frame/test/index.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,4 +420,14 @@ describe("@babel/code-frame", function () {
420420
expect(stripAnsi(highlighted)).toBe(raw);
421421
expect(highlighted.length).toBeGreaterThan(raw.length);
422422
});
423+
424+
test("opts.startLine", function () {
425+
const rawLines = "const a = 1;\nconst b = 1";
426+
expect(
427+
codeFrameColumns(rawLines, { start: { line: 102 } }, { startLine: 101 }),
428+
).toMatchInlineSnapshot(`
429+
" 101 | const a = 1;
430+
> 102 | const b = 1"
431+
`);
432+
});
423433
});

packages/babel-core/src/parser/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ export default function* parser(
5050
// err.code will be changed to BABEL_PARSE_ERROR later.
5151
}
5252

53+
const startLine = parserOpts?.startLine;
54+
const startColumn = parserOpts?.startColumn;
55+
56+
if (startColumn != null) {
57+
code = " ".repeat(startColumn) + code;
58+
}
59+
5360
const { loc, missingPlugin } = err;
5461
if (loc) {
5562
const codeFrame = codeFrameColumns(
@@ -62,6 +69,7 @@ export default function* parser(
6269
},
6370
{
6471
highlightCode,
72+
startLine,
6573
},
6674
);
6775
if (missingPlugin) {

packages/babel-core/test/parse.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,28 @@ describe("parseSync", function () {
3939
});
4040
expect(JSON.parse(JSON.stringify(result))).toEqual(output);
4141
});
42+
43+
it("should show correct codeFrame with startLine and startColumn", function () {
44+
const input = `const* a = 1;`;
45+
let err;
46+
try {
47+
parseSync(input, {
48+
parserOpts: {
49+
startLine: 3,
50+
startColumn: 3,
51+
},
52+
highlightCode: false,
53+
configFile: false,
54+
babelrc: false,
55+
});
56+
} catch (e) {
57+
err = e;
58+
}
59+
expect(err.message).toMatchInlineSnapshot(`
60+
"unknown: Unexpected token (3:8)
61+
62+
> 3 | const* a = 1;
63+
| ^"
64+
`);
65+
});
4266
});

0 commit comments

Comments
 (0)