Skip to content

Commit ca614f4

Browse files
authored
Fixed wrong location calculation when including CRLF. (#74)
* Fixed wrong location calculation when including CRLF. * Fixed error
1 parent c627e36 commit ca614f4

File tree

11 files changed

+6494
-20
lines changed

11 files changed

+6494
-20
lines changed

src/common/location-calculator.ts

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,20 @@ export class LocationCalculator {
2323
private ltOffsets: number[]
2424
private baseOffset: number
2525
private baseIndexOfGap: number
26+
private shiftOffset: number
2627

2728
/**
2829
* Initialize this calculator.
2930
* @param gapOffsets The list of the offset of removed characters in tokenization phase.
3031
* @param ltOffsets The list of the offset of line terminators.
3132
* @param baseOffset The base offset to calculate locations.
33+
* @param shiftOffset The shift offset to calculate locations.
3234
*/
3335
public constructor(
3436
gapOffsets: number[],
3537
ltOffsets: number[],
3638
baseOffset?: number,
39+
shiftOffset: number = 0,
3740
) {
3841
this.gapOffsets = gapOffsets
3942
this.ltOffsets = ltOffsets
@@ -42,6 +45,7 @@ export class LocationCalculator {
4245
this.baseOffset === 0
4346
? 0
4447
: sortedLastIndex(gapOffsets, this.baseOffset)
48+
this.shiftOffset = shiftOffset
4549
}
4650

4751
/**
@@ -54,6 +58,21 @@ export class LocationCalculator {
5458
this.gapOffsets,
5559
this.ltOffsets,
5660
this.baseOffset + offset,
61+
this.shiftOffset,
62+
)
63+
}
64+
65+
/**
66+
* Get sub calculator that shifts the given offset.
67+
* @param offset The shift of new sub calculator.
68+
* @returns Sub calculator.
69+
*/
70+
public getSubCalculatorShift(offset: number): LocationCalculator {
71+
return new LocationCalculator(
72+
this.gapOffsets,
73+
this.ltOffsets,
74+
this.baseOffset,
75+
this.shiftOffset + offset,
5776
)
5877
}
5978

@@ -91,7 +110,7 @@ export class LocationCalculator {
91110
* @returns The location of the index.
92111
*/
93112
public getLocation(index: number): Location {
94-
return this._getLocation(this.baseOffset + index)
113+
return this._getLocation(this.baseOffset + index + this.shiftOffset)
95114
}
96115

97116
/**
@@ -100,20 +119,27 @@ export class LocationCalculator {
100119
* @returns The offset of the index.
101120
*/
102121
public getOffsetWithGap(index: number): number {
103-
return this.baseOffset + index + this._getGap(index)
122+
const shiftOffset = this.shiftOffset
123+
return (
124+
this.baseOffset +
125+
index +
126+
shiftOffset +
127+
this._getGap(index + shiftOffset)
128+
)
104129
}
105130

106131
/**
107132
* Modify the location information of the given node with using the base offset and gaps of this calculator.
108133
* @param node The node to modify their location.
109134
*/
110135
public fixLocation<T extends HasLocation>(node: T): T {
136+
const shiftOffset = this.shiftOffset
111137
const range = node.range
112138
const loc = node.loc
113-
const gap0 = this._getGap(range[0])
114-
const gap1 = this._getGap(range[1])
115-
const d0 = this.baseOffset + Math.max(0, gap0)
116-
const d1 = this.baseOffset + Math.max(0, gap1)
139+
const gap0 = this._getGap(range[0] + shiftOffset)
140+
const gap1 = this._getGap(range[1] + shiftOffset)
141+
const d0 = this.baseOffset + Math.max(0, gap0) + shiftOffset
142+
const d1 = this.baseOffset + Math.max(0, gap1) + shiftOffset
117143

118144
if (d0 !== 0) {
119145
range[0] += d0
@@ -138,8 +164,9 @@ export class LocationCalculator {
138164
* @param error The error to modify their location.
139165
*/
140166
public fixErrorLocation(error: ParseError) {
141-
const gap = this._getGap(error.index)
142-
const diff = this.baseOffset + Math.max(0, gap)
167+
const shiftOffset = this.shiftOffset
168+
const gap = this._getGap(error.index + shiftOffset)
169+
const diff = this.baseOffset + Math.max(0, gap) + shiftOffset
143170

144171
error.index += diff
145172

src/script/index.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ function parseExpressionBody(
361361
try {
362362
const ast = parseScriptFragment(
363363
`0(${code})`,
364-
locationCalculator.getSubCalculatorAfter(-2),
364+
locationCalculator.getSubCalculatorShift(-2),
365365
parserOptions,
366366
).ast
367367
const tokens = ast.tokens || []
@@ -431,9 +431,12 @@ function parseFilter(
431431
// Parse the callee.
432432
if (calleeCode.trim()) {
433433
const spaces = /^\s*/u.exec(calleeCode)![0]
434+
const subCalculator = locationCalculator.getSubCalculatorShift(
435+
spaces.length,
436+
)
434437
const { ast } = parseScriptFragment(
435-
`${spaces}"${calleeCode.trim()}"`,
436-
locationCalculator,
438+
`"${calleeCode.trim()}"`,
439+
subCalculator,
437440
parserOptions,
438441
)
439442
const statement = ast.body[0] as ESLintExpressionStatement
@@ -455,12 +458,13 @@ function parseFilter(
455458
expression.callee = {
456459
type: "Identifier",
457460
parent: expression,
458-
range: [callee.range[0], callee.range[1] - 2],
461+
range: [
462+
callee.range[0],
463+
subCalculator.getOffsetWithGap(calleeCode.trim().length),
464+
],
459465
loc: {
460466
start: callee.loc.start,
461-
end: locationCalculator.getLocation(
462-
callee.range[1] - callee.range[0] - 1,
463-
),
467+
end: subCalculator.getLocation(calleeCode.trim().length),
464468
},
465469
name: String(callee.value),
466470
}
@@ -478,7 +482,9 @@ function parseFilter(
478482
if (argsCode != null) {
479483
const { ast } = parseScriptFragment(
480484
`0${argsCode}`,
481-
locationCalculator.getSubCalculatorAfter(paren - 1),
485+
locationCalculator
486+
.getSubCalculatorAfter(paren)
487+
.getSubCalculatorShift(-1),
482488
parserOptions,
483489
)
484490
const statement = ast.body[0] as ESLintExpressionStatement
@@ -684,7 +690,7 @@ export function parseExpression(
684690
// Parse a filter
685691
const retF = parseFilter(
686692
filterCode,
687-
locationCalculator.getSubCalculatorAfter(prevLoc + 1),
693+
locationCalculator.getSubCalculatorShift(prevLoc + 1),
688694
parserOptions,
689695
)
690696
if (retF) {
@@ -731,7 +737,7 @@ export function parseVForExpression(
731737
const replaced = processedCode !== code
732738
const ast = parseScriptFragment(
733739
`for(let ${processedCode});`,
734-
locationCalculator.getSubCalculatorAfter(-8),
740+
locationCalculator.getSubCalculatorShift(-8),
735741
parserOptions,
736742
).ast
737743
const tokens = ast.tokens || []
@@ -829,7 +835,7 @@ function parseVOnExpressionBody(
829835
try {
830836
const ast = parseScriptFragment(
831837
`void function($event){${code}}`,
832-
locationCalculator.getSubCalculatorAfter(-22),
838+
locationCalculator.getSubCalculatorShift(-22),
833839
parserOptions,
834840
).ast
835841
const references = analyzeExternalReferences(ast, parserOptions)
@@ -905,7 +911,7 @@ export function parseSlotScopeExpression(
905911
try {
906912
const ast = parseScriptFragment(
907913
`void function(${code}) {}`,
908-
locationCalculator.getSubCalculatorAfter(-14),
914+
locationCalculator.getSubCalculatorShift(-14),
909915
parserOptions,
910916
).ast
911917
const statement = ast.body[0] as ESLintExpressionStatement

test/ast.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,25 @@ describe("Template AST", () => {
198198
assert.strictEqual(actualText, expectedText)
199199
})
200200

201+
it("should have correct range on windows(CRLF).", () => {
202+
const sourceForWin = source.replace(/\r?\n/gu, "\r\n")
203+
const actualForWin = parser.parseForESLint(
204+
sourceForWin,
205+
Object.assign({ filePath: sourcePath }, PARSER_OPTIONS)
206+
)
207+
208+
const resultPath = path.join(ROOT, `${name}/token-ranges.json`)
209+
const expectedText = fs.readFileSync(resultPath, "utf8")
210+
const tokens = getAllTokens(actualForWin.ast).map(t =>
211+
sourceForWin
212+
.slice(t.range[0], t.range[1])
213+
.replace(/\r?\n/gu, "\n")
214+
)
215+
const actualText = JSON.stringify(tokens, null, 4)
216+
217+
assert.strictEqual(actualText, expectedText)
218+
})
219+
201220
it("should have correct location.", () => {
202221
const lines = source.match(/[^\r\n]*(?:\r?\n|$)/gu) || []
203222
lines.push(String.fromCodePoint(0))

0 commit comments

Comments
 (0)