-
-
Notifications
You must be signed in to change notification settings - Fork 79
/
Copy pathlocation-calculator.ts
145 lines (133 loc) · 4.52 KB
/
location-calculator.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
* @author Toru Nagashima <https://github.com/mysticatea>
* @copyright 2017 Toru Nagashima. All rights reserved.
* See LICENSE file in root directory for full license.
*/
import sortedLastIndex from "lodash/sortedLastIndex"
import type { Location } from "../ast/index"
import { LinesAndColumns } from "./lines-and-columns"
/**
* Location calculators.
*/
export interface LocationCalculator {
/**
* Gets the fix location offset of the given offset with using the base offset of this calculator.
* @param offset The offset to modify.
*/
getFixOffset(offset: number, kind: "start" | "end"): number
/**
* Calculate the location of the given index.
* @param index The index to calculate their location.
* @returns The location of the index.
*/
getLocFromIndex(index: number): Location
}
/**
* Location calculators.
*
* HTML tokenizers remove several characters to handle HTML entities and line terminators.
* Tokens have the processed text as their value, but tokens have offsets and locations in the original text.
* This calculator calculates the original locations from the processed texts.
*
* This calculator will be used for:
*
* - Adjusts the locations of script ASTs.
* - Creates expression containers in postprocess.
*/
export class LocationCalculatorForHtml
extends LinesAndColumns
implements LocationCalculator
{
private gapOffsets: number[]
private baseOffset: number
private baseIndexOfGap: number
private shiftOffset: number
/**
* Initialize this calculator.
* @param gapOffsets The list of the offset of removed characters in tokenization phase.
* @param ltOffsets The list of the offset of line terminators.
* @param baseOffset The base offset to calculate locations.
* @param shiftOffset The shift offset to calculate locations.
*/
public constructor(
gapOffsets: number[],
ltOffsets: number[],
baseOffset?: number,
shiftOffset = 0,
) {
super(ltOffsets)
this.gapOffsets = gapOffsets
this.ltOffsets = ltOffsets
this.baseOffset = baseOffset ?? 0
this.baseIndexOfGap =
this.baseOffset === 0
? 0
: sortedLastIndex(gapOffsets, this.baseOffset)
this.shiftOffset = shiftOffset
}
/**
* Get sub calculator which have the given base offset.
* @param offset The base offset of new sub calculator.
* @returns Sub calculator.
*/
public getSubCalculatorAfter(offset: number): LocationCalculatorForHtml {
return new LocationCalculatorForHtml(
this.gapOffsets,
this.ltOffsets,
this.baseOffset + offset,
this.shiftOffset,
)
}
/**
* Get sub calculator that shifts the given offset.
* @param offset The shift of new sub calculator.
* @returns Sub calculator.
*/
public getSubCalculatorShift(offset: number): LocationCalculatorForHtml {
return new LocationCalculatorForHtml(
this.gapOffsets,
this.ltOffsets,
this.baseOffset,
this.shiftOffset + offset,
)
}
/**
* Calculate gap at the given index.
* @param index The index to calculate gap.
*/
private _getGap(index: number): number {
const offsets = this.gapOffsets
let g0 = sortedLastIndex(offsets, index + this.baseOffset)
let pos = index + this.baseOffset + g0 - this.baseIndexOfGap
while (g0 < offsets.length && offsets[g0] <= pos) {
g0 += 1
pos += 1
}
return g0 - this.baseIndexOfGap
}
/**
* Calculate the location of the given index.
* @param index The index to calculate their location.
* @returns The location of the index.
*/
public getLocation(index: number): Location {
return this.getLocFromIndex(this.getOffsetWithGap(index))
}
/**
* Calculate the offset of the given index.
* @param index The index to calculate their location.
* @returns The offset of the index.
*/
public getOffsetWithGap(index: number): number {
return index + this.getFixOffset(index)
}
/**
* Gets the fix location offset of the given offset with using the base offset of this calculator.
* @param offset The offset to modify.
*/
public getFixOffset(offset: number): number {
const shiftOffset = this.shiftOffset
const gap = this._getGap(offset + shiftOffset)
return this.baseOffset + gap + shiftOffset
}
}