Skip to content

Commit

Permalink
fix: compatibility with eol-last rule (#191)
Browse files Browse the repository at this point in the history
* fix: compatibility with eol-last rule

* Create .changeset/modern-windows-glow.md
  • Loading branch information
ota-meshi authored Mar 22, 2023
1 parent 11fc8fe commit 8fb33ff
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 25 deletions.
5 changes: 5 additions & 0 deletions .changeset/modern-windows-glow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eslint-plugin-astro": patch
---

fix: compatibility with `eol-last` rule
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"@eslint-community/eslint-utils": "^4.2.0",
"@jridgewell/sourcemap-codec": "^1.4.14",
"@typescript-eslint/types": "^5.25.0",
"astro-eslint-parser": "^0.13.0",
"astro-eslint-parser": "^0.13.1",
"postcss": "^8.4.14",
"postcss-selector-parser": "^6.0.10"
},
Expand Down
78 changes: 58 additions & 20 deletions src/shared/client-script/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export class ClientScript {
const indent = getIndent(lines)
for (let index = 0; index < lines.length; index++) {
const line = lines[index]
const lineIndent = Math.min(indent, line.length - 1)
const lineIndent = Math.min(indent, line.length)
textLines.push(line.slice(lineIndent))
remapLines.push(startLoc.line + index + 1)
remapColumnOffsets.push(lineIndent)
Expand All @@ -109,28 +109,44 @@ export class ClientScript {
const textLocs = new Locs(textLines)

/** Remap loc */
const remapRange = (range: [number, number]): [number, number] => {
return [
this.parsed.getIndexFromLoc(
remapLoc(textLocs.getLocFromIndex(range[0])),
),
this.parsed.getIndexFromLoc(
remapLoc(textLocs.getLocFromIndex(range[1])),
),
]
}

/** Remap loc */
function remapLoc(loc: { line: number; column: number }): {
const remapLoc = (loc: {
line: number
column: number
} {
}): {
line: number
column: number
} => {
const lineIndex = loc.line - 1
if (remapLines.length > lineIndex) {
return {
line: remapLines[lineIndex],
column: loc.column + remapColumnOffsets[lineIndex],
}
}
if (remapLines.length === lineIndex) {
return this.parsed.getLocFromIndex(endOffset + loc.column)
}
return {
line: remapLines[loc.line - 1] ?? -1,
column: loc.column + (remapColumnOffsets[loc.line - 1] ?? 0),
line: -1,
column: loc.column + 0,
}
}

/** Remap range */
const remapRange = (range: [number, number]): [number, number] | null => {
const startLoc = textLocs.getLocFromIndex(range[0])
const endLoc = textLocs.getLocFromIndex(range[1])
const remappedStartLoc = remapLoc(startLoc)
const remappedEndLoc = remapLoc(endLoc)
if (remappedStartLoc.line < 0 || remappedEndLoc.line < 0) {
return null
}
return [
this.parsed.getIndexFromLoc(remappedStartLoc),
this.parsed.getIndexFromLoc(remappedEndLoc),
]
}

return {
text,
remapMessage(message: Linter.LintMessage): Linter.LintMessage {
Expand All @@ -150,11 +166,24 @@ export class ClientScript {
}

if (message.fix) {
message.fix.range = remapRange(message.fix.range)
const remappedRange = remapRange(message.fix.range)
if (remappedRange) {
message.fix.range = remappedRange
} else {
delete message.fix
}
}
if (message.suggestions) {
for (const suggestion of message.suggestions) {
suggestion.fix.range = remapRange(suggestion.fix.range)
for (const suggestion of [...message.suggestions]) {
const remappedRange = remapRange(suggestion.fix.range)
if (remappedRange) {
suggestion.fix.range = remappedRange
} else {
message.suggestions.splice(
message.suggestions.indexOf(suggestion),
1,
)
}
}
}

Expand Down Expand Up @@ -208,9 +237,18 @@ export class ClientScript {

public remapMessages(messages: Linter.LintMessage[]): Linter.LintMessage[] {
return messages
.filter((m) => !this.isIgnoreMessage(m))
.map((m) => this.block.remapMessage(m))
.filter((m) => m.line >= 0)
}

private isIgnoreMessage(message: Linter.LintMessage) {
if (message.ruleId === "eol-last" && message.messageId === "unexpected") {
// Ignore this report as it is not possible to remove the EOF of a block.
return true
}
return false
}
}

/** Get indent */
Expand Down
16 changes: 12 additions & 4 deletions src/utils/transform/lines-and-columns.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export class LinesAndColumns {
private readonly lineStartIndices: number[]

private readonly code: string

public constructor(code: string) {
const len = code.length
const lineStartIndices = [0]
Expand All @@ -16,6 +18,7 @@ export class LinesAndColumns {
lineStartIndices.push(index + 1)
}
}
this.code = code
this.lineStartIndices = lineStartIndices
}

Expand All @@ -28,10 +31,15 @@ export class LinesAndColumns {
}

public getIndexFromLoc(loc: { line: number; column: number }): number {
const lineStartIndex = this.lineStartIndices[loc.line - 1]
const positionIndex = lineStartIndex + loc.column

return positionIndex
const lineIndex = loc.line - 1
if (this.lineStartIndices.length > lineIndex) {
const lineStartIndex = this.lineStartIndices[lineIndex]
const positionIndex = lineStartIndex + loc.column
return positionIndex
} else if (this.lineStartIndices.length === lineIndex) {
return this.code.length + loc.column
}
return this.code.length + loc.column
}
}

Expand Down
74 changes: 74 additions & 0 deletions tests/src/integration/eol-last.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { RuleTester, Linter } from "eslint"
import { processor } from "../../../src/processor"

describe("Integration test for eol-last", () => {
const eolLast = new Linter().getRules().get("eol-last")!
const tester = new RuleTester({
parser: require.resolve("./auto-parser"),
parserOptions: {
ecmaVersion: 2020,
sourceType: "module",
},
})
tester.run("eol-last", eolLast, {
valid: [
{
// @ts-expect-error -- fine name with processor
filename: {
filename: "foo.astro",
...processor,
},
code: `
<script define:vars={{ foo: 42 }}>
console.log(foo)
</script>\n`,
},
{
// @ts-expect-error -- fine name with processor
filename: {
filename: "foo.astro",
...processor,
},
code: `
<script define:vars={{ foo: 42 }}>
console.log(foo)
</script>`,
options: ["never"],
},
{
// @ts-expect-error -- fine name with processor
filename: {
filename: "foo.astro",
...processor,
},
code: `
<script define:vars={{ foo: 42 }}>
console.log(foo)</script>`,
options: ["never"],
},
],
invalid: [
{
// @ts-expect-error -- fine name with processor
filename: {
filename: "foo.astro",
...processor,
},
code: `
<script define:vars={{ foo: 42 }}>
console.log(foo)</script>\n`,
output: `
<script define:vars={{ foo: 42 }}>
console.log(foo)
</script>\n`,
errors: [
{
message: "Newline required at end of file but not found.",
line: 3,
column: 27,
},
],
},
],
})
})

0 comments on commit 8fb33ff

Please sign in to comment.