|
1 | 1 | import { initSourceText, sourceText } from './source_code.js'; |
2 | 2 |
|
3 | | -import type { LineColumn } from './types.ts'; |
| 3 | +import type { LineColumn, Location, Node } from './types.ts'; |
| 4 | + |
| 5 | +const { defineProperty } = Object; |
4 | 6 |
|
5 | 7 | // Pattern for splitting source text into lines |
6 | 8 | const LINE_BREAK_PATTERN = /\r\n|[\r\n\u2028\u2029]/gu; |
@@ -69,6 +71,18 @@ export function getLineColumnFromOffset(offset: number): LineColumn { |
69 | 71 | ); |
70 | 72 | } |
71 | 73 |
|
| 74 | + return getLineColumnFromOffsetUnchecked(offset); |
| 75 | +} |
| 76 | + |
| 77 | +/** |
| 78 | + * Convert a source text index into a (line, column) pair without: |
| 79 | + * 1. Checking type of `offset`, or that it's in range. |
| 80 | + * 2. Initializing `lineStartOffsets`. Caller must do that before calling this method. |
| 81 | + * |
| 82 | + * @param offset - The index of a character in a file. |
| 83 | + * @returns `{line, column}` location object with 1-indexed line and 0-indexed column. |
| 84 | + */ |
| 85 | +function getLineColumnFromOffsetUnchecked(offset: number): LineColumn { |
72 | 86 | // Binary search `lineStartOffsets` for the line containing `offset` |
73 | 87 | let low = 0, high = lineStartOffsets.length, mid: number; |
74 | 88 | do { |
@@ -138,3 +152,30 @@ export function getOffsetFromLineColumn(loc: LineColumn): number { |
138 | 152 |
|
139 | 153 | throw new TypeError('Expected `loc` to be an object with integer `line` and `column` properties.'); |
140 | 154 | } |
| 155 | + |
| 156 | +/** |
| 157 | + * Get the `Location` for an AST node. Used in `loc` getters on AST nodes. |
| 158 | + * |
| 159 | + * Overwrites the `loc` getter with the calculated `Location`, so accessing `loc` twice on same node |
| 160 | + * results in the same object each time. |
| 161 | + * |
| 162 | + * For internal use only. |
| 163 | + * |
| 164 | + * @param node - AST node object |
| 165 | + * @returns Location |
| 166 | + */ |
| 167 | +export function getNodeLoc(node: Node): Location { |
| 168 | + // Build `lines` and `lineStartOffsets` tables if they haven't been already. |
| 169 | + // This also decodes `sourceText` if it wasn't already. |
| 170 | + if (lines.length === 0) initLines(); |
| 171 | + |
| 172 | + const loc = { |
| 173 | + start: getLineColumnFromOffsetUnchecked(node.start), |
| 174 | + end: getLineColumnFromOffsetUnchecked(node.end), |
| 175 | + }; |
| 176 | + |
| 177 | + // Replace `loc` getter with the calculated value |
| 178 | + defineProperty(node, 'loc', { value: loc, writable: true }); |
| 179 | + |
| 180 | + return loc; |
| 181 | +} |
0 commit comments