eslint-plugin-html
Version:
A ESLint plugin to lint and fix inline scripts contained in HTML files.
128 lines (114 loc) • 3.12 kB
JavaScript
"use strict"
const lineEndingsRe = /\r\n|\r|\n/g
function lineStarts(str) {
const result = [0]
lineEndingsRe.lastIndex = 0
while (true) {
const match = lineEndingsRe.exec(str)
if (!match) break
result.push(lineEndingsRe.lastIndex)
}
return result
}
function locationToIndex(location, lineStarts) {
if (
!location.line ||
location.line < 0 ||
!location.column ||
location.column < 0
) {
throw new Error("Invalid location")
}
return lineStarts[location.line - 1] + location.column - 1
}
function indexToLocation(index, lineStarts) {
if (index < 0) throw new Error("Invalid index")
let line = 0
while (line + 1 < lineStarts.length && lineStarts[line + 1] <= index) {
line += 1
}
return {
line: line + 1,
column: index - lineStarts[line] + 1,
}
}
module.exports = class TransformableString {
constructor(original) {
this._original = original
this._blocks = []
this._lineStarts = lineStarts(original)
this._cache = null
}
_compute() {
if (!this._cache) {
let result = ""
let index = 0
for (const block of this._blocks) {
result += this._original.slice(index, block.from) + block.str
index = block.to
}
result += this._original.slice(index)
this._cache = {
lineStarts: lineStarts(result),
result,
}
}
return this._cache
}
getOriginalLine(n) {
if (n < 1 || n > this._lineStarts.length) {
throw new Error("Invalid line number")
}
return this._original
.slice(this._lineStarts[n - 1], this._lineStarts[n])
.replace(lineEndingsRe, "")
}
toString() {
return this._compute().result
}
replace(from, to, str) {
this._cache = null
if (from > to || from < 0 || to > this._original.length) {
throw new Error("Invalid slice indexes")
}
const newBlock = { from, to, str }
if (
!this._blocks.length ||
this._blocks[this._blocks.length - 1].to <= from
) {
this._blocks.push(newBlock)
} else {
const index = this._blocks.findIndex((other) => other.to > from)
if (this._blocks[index].from < to) throw new Error("Can't replace slice")
this._blocks.splice(index, 0, newBlock)
}
}
originalIndex(index) {
let block
for (block of this._blocks) {
if (index < block.from) break
if (index < block.from + block.str.length) {
return
} else {
index += block.to - block.from - block.str.length
}
}
if (index < 0 || index > this._original.length) {
throw new Error("Invalid index")
}
if (index == this._original.length) {
if (block.to && block.to === this._original.length) {
return block.from + block.str.length
}
return this._original.length
}
return index
}
originalLocation(location) {
const index = locationToIndex(location, this._compute().lineStarts)
const originalIndex = this.originalIndex(index)
if (originalIndex !== undefined) {
return indexToLocation(originalIndex, this._lineStarts)
}
}
}