|
1 | 1 | /// <reference path="../typings.d.ts" /> |
2 | 2 |
|
3 | 3 | import type { Linter } from 'eslint' |
4 | | -import type { SourceLocation } from 'estree' |
5 | | -import type { Position } from 'unist' |
| 4 | +import type { Position as ESPosition, SourceLocation } from 'estree' |
| 5 | +import type { Point, Position } from 'unist' |
6 | 6 |
|
7 | | -import type { Arrayable, JsxNode, ParserFn, ParserOptions } from './types' |
| 7 | +import type { |
| 8 | + Arrayable, |
| 9 | + JsxNode, |
| 10 | + ParserFn, |
| 11 | + ParserOptions, |
| 12 | + ValueOf, |
| 13 | +} from './types' |
8 | 14 |
|
9 | 15 | export const FALLBACK_PARSERS = [ |
10 | 16 | '@typescript-eslint/parser', |
@@ -90,43 +96,55 @@ export const hasProperties = <T, P extends keyof T = keyof T>( |
90 | 96 | obj && |
91 | 97 | properties.every(property => property in obj) |
92 | 98 |
|
93 | | -export const restoreNodeLocation = <T>( |
94 | | - node: T, |
95 | | - startLine: number, |
96 | | - offset: number, |
97 | | -): T => { |
| 99 | +// fix #292 |
| 100 | +export const getPositionAt = (code: string, offset: number): ESPosition => { |
| 101 | + let currOffset = 0 |
| 102 | + |
| 103 | + for (const [index, { length }] of code.split('\n').entries()) { |
| 104 | + const line = index + 1 |
| 105 | + const nextOffset = currOffset + length |
| 106 | + |
| 107 | + if (nextOffset >= offset) { |
| 108 | + return { |
| 109 | + line, |
| 110 | + column: offset - currOffset, |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + currOffset = nextOffset + 1 // add a line break `\n` offset |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +export const restoreNodeLocation = <T>(node: T, point: Point): T => { |
98 | 119 | if (node && typeof node === 'object') { |
99 | | - for (const value of Object.values(node)) { |
100 | | - restoreNodeLocation(value, startLine, offset) |
| 120 | + for (const value of Object.values(node) as Array<ValueOf<T>>) { |
| 121 | + restoreNodeLocation(value, point) |
101 | 122 | } |
102 | 123 | } |
103 | 124 |
|
104 | 125 | if (!hasProperties<BaseNode>(node, ['loc', 'range'])) { |
105 | 126 | return node |
106 | 127 | } |
107 | 128 |
|
108 | | - const { |
| 129 | + let { |
109 | 130 | loc: { start: startLoc, end: endLoc }, |
110 | | - range, |
| 131 | + range: [start, end], |
111 | 132 | } = node |
112 | | - const start = range[0] + offset |
113 | | - const end = range[1] + offset |
114 | 133 |
|
115 | | - const restoredStartLine = startLine + startLoc.line |
116 | | - const restoredEndLine = startLine + endLoc.line |
| 134 | + const range = [(start += point.offset), (end += point.offset)] as const |
117 | 135 |
|
118 | 136 | return Object.assign(node, { |
119 | 137 | start, |
120 | 138 | end, |
121 | | - range: [start, end], |
| 139 | + range, |
122 | 140 | loc: { |
123 | 141 | start: { |
124 | | - line: restoredStartLine, |
125 | | - column: startLoc.column + (restoredStartLine === 1 ? offset : 0), |
| 142 | + line: point.line + startLoc.line, |
| 143 | + column: startLoc.column + (startLoc.line === 1 ? point.column : 0), |
126 | 144 | }, |
127 | 145 | end: { |
128 | | - line: restoredEndLine, |
129 | | - column: endLoc.column + (restoredEndLine === 1 ? offset : 0), |
| 146 | + line: point.line + endLoc.line, |
| 147 | + column: endLoc.column + (endLoc.line === 1 ? point.column : 0), |
130 | 148 | }, |
131 | 149 | }, |
132 | 150 | }) |
|
0 commit comments