-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
For example:
<p>Hello</p>
<style>
p {
color: green;
}
</style>The p {} rule when parsed with postcss-html has source locations that are offset relative to the entire html doc.
So p {} starts on line 4, not on line 1.
This is very useful when reporting errors (i.e. Stylelint) to developers in a code editors.
As the error will be reported on the line and column in the entire document.
However this unfortunately conflicts with the changes I introduced in #1980
Since those changes, we use node.source.input.css to infer positions.
But we assume the start of node.source.input.css corresponds with:
index == 0line == 1andcolumn == 1
Because postcss-html offsets the positions relative to the enclosing document this assumptions proves to be incorrect, making any position calculations incorrect.
The simplest way forward I could think of was to add an extra field on Input to keep track of both the source of the enclosing document and of the CSS block independently.
Lines 17 to 34 in 99da2f2
| class Input { | |
| constructor(css, opts = {}) { | |
| if ( | |
| css === null || | |
| typeof css === 'undefined' || | |
| (typeof css === 'object' && !css.toString) | |
| ) { | |
| throw new Error(`PostCSS received ${css} instead of CSS string`) | |
| } | |
| this.css = css.toString() | |
| if (this.css[0] === '\uFEFF' || this.css[0] === '\uFFFE') { | |
| this.hasBOM = true | |
| this.css = this.css.slice(1) | |
| } else { | |
| this.hasBOM = false | |
| } |
class Input {
constructor(css, opts = {}) {
if (
css === null ||
typeof css === 'undefined' ||
(typeof css === 'object' && !css.toString)
) {
throw new Error(`PostCSS received ${css} instead of CSS string`)
}
this.css = css.toString()
if (this.css[0] === '\uFEFF' || this.css[0] === '\uFFFE') {
this.hasBOM = true
this.css = this.css.slice(1)
} else {
this.hasBOM = false
}
this.document = this.css
if (opts.document) this.document = opts.document.toString()
// ...For almost all usage of PostCSS input.document would correspond to input.css as the document is the CSS stylesheet.
But for CSS-in-X syntaxes (like postcss-html) the syntax authors could set document to the enclosing source (e.g. the html document).
When inferring positions we would use node.source.input.document instead of node.source.input.css in PostCSS itself.
positionBy(opts) {
let pos = this.source.start
if (opts.index) {
pos = this.positionInside(opts.index)
} else if (opts.word) {
let stringRepresentation = this.source.input.document.slice(
sourceOffset(this.source.input.document, this.source.start),
sourceOffset(this.source.input.document, this.source.end)
)
let index = stringRepresentation.indexOf(opts.word)
if (index !== -1) pos = this.positionInside(index)
}
return pos
}