diff --git a/apps/oxlint/src-js/plugins/location.ts b/apps/oxlint/src-js/plugins/location.ts index 5a3bed59f845e..684d4fb5059e2 100644 --- a/apps/oxlint/src-js/plugins/location.ts +++ b/apps/oxlint/src-js/plugins/location.ts @@ -7,7 +7,7 @@ import { ast, initAst, initSourceText, sourceText } from "./source_code.ts"; import visitorKeys from "../generated/keys.ts"; import { debugAssert, debugAssertIsNonNull } from "../utils/asserts.ts"; -import type { Node } from "./types.ts"; +import type { NodeOrToken } from "./types.ts"; import type { Node as ESTreeNode } from "../generated/types.d.ts"; /** @@ -241,28 +241,38 @@ export function getOffsetFromLineColumn(loc: LineColumn): number { } /** - * Get the `Location` for an AST node. Used in `loc` getters on AST nodes. + * Calculate the `Location` for an AST node or token. * - * Overwrites the `loc` getter with the calculated `Location`, so accessing `loc` twice on same node + * Used in `loc` getters on AST nodes. + * + * Defines a `loc` property on the node/token with the calculated `Location`, so accessing `loc` twice on same node * results in the same object each time. * * For internal use only. * - * @param node - AST node object + * @param nodeOrToken - AST node or token * @returns Location */ -export function getNodeLoc(node: Node): Location { +export function getNodeLoc(nodeOrToken: NodeOrToken): Location { // Build `lines` and `lineStartIndices` tables if they haven't been already. // This also decodes `sourceText` if it wasn't already. if (lines.length === 0) initLines(); const loc = { - start: getLineColumnFromOffsetUnchecked(node.start), - end: getLineColumnFromOffsetUnchecked(node.end), + start: getLineColumnFromOffsetUnchecked(nodeOrToken.start), + end: getLineColumnFromOffsetUnchecked(nodeOrToken.end), }; - // Replace `loc` getter with the calculated value - Object.defineProperty(node, "loc", { value: loc, writable: true }); + // Define `loc` property with the calculated `Location`, so accessing `loc` twice on same node/token + // results in the same object each time. + // + // We do not make the `loc` property enumerable, because it wasn't present before. + // It would be weird if `Object.keys(node)` included `loc` if the property had been accessed previously, + // but not if it hadn't. + // + // We also don't make it configurable, because deleting it wouldn't make `node.loc` evaluate to `undefined`, + // because the access would fall through to the getter on the prototype. + Object.defineProperty(nodeOrToken, "loc", { value: loc, writable: true }); return loc; }