Files
babel/packages/babel-parser/test/helpers/to-contextual-syntax-error.js
Nehemiya WickramasingheandGitHub 936a3bc8b6 breaking(code-frame): use 0-based columns to match Babel AST locations (#1… (#17849)
fix(code-frame): use 0-based columns to match Babel AST locations (#17316)

`codeFrameColumns` treated the `column` property as 1-based, but Babel
AST locations use 0-based columns. This caused the caret/underline to
be off by one character when passing AST `.loc` objects directly.

- Removed the `- 1` offset in marker spacing calculation
- Removed the `+ 1` in multiline start marker count
- Changed default column sentinel from `0` to `null` so that
  `column: 0` is treated as a valid position
- Updated falsiness checks (`!startColumn`) to null checks
- Removed `+ 1` workarounds in babel-core and babel-traverse callers

This is a breaking change for external consumers of `@babel/code-frame`
who passed 1-based columns manually.
2026-05-11 09:38:53 -04:00

46 lines
1.5 KiB
JavaScript

import { codeFrameColumns } from "@babel/code-frame";
import { runInThisContext } from "node:vm";
export default function toContextualSyntaxError(
error,
source,
filename,
options,
) {
if (!(error instanceof SyntaxError)) return error;
const { startLine = 1, startColumn = 0 } = options || {};
const line = error.loc.line - startLine + 1;
const column = line === 1 ? error.loc.column - startColumn : error.loc.column;
const frame = codeFrameColumns(
source,
{ start: { line, column } },
{ highlightCode: true },
);
// We make this a lazy property since we don't want pay the price of creating
// this new error unless we are going to display it.
Object.defineProperty(error, "context", {
get() {
const message = JSON.stringify(`${error.message}\n${frame}`);
const originalStackTraceLimit = Error.stackTraceLimit;
// Limit this stack trace to 1. Everything after that is just stuff from
// the test.
Error.stackTraceLimit = 1;
// The only way to manipulate the file in which a SyntaxError reports it
// is coming from is to roundtrip through vm.runInThisContext. If v8
// supported Firefox's non-standard Error.fileName property, that could be
// used instead, but unfortunately it does not.
const context = runInThisContext(`SyntaxError(${message})`, { filename });
Error.stackTraceLimit = originalStackTraceLimit;
return Object.assign(context, { cause: this });
},
});
return error;
}