Skip to content

Commit f62d4de

Browse files
authored
no-parsing-error improve (#4)
* refactor * no-parsing-error improve
1 parent c3681a7 commit f62d4de

File tree

9 files changed

+367
-99
lines changed

9 files changed

+367
-99
lines changed

lib/styles/parser/css-parser.ts

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import postcss from "postcss"
2+
import postcssSafeParser from "postcss-safe-parser"
23
import { CSSSelectorParser } from "./selector/css-selector-parser"
34
import {
45
VCSSStyleSheet,
@@ -36,6 +37,7 @@ export class CSSParser {
3637
protected commentContainer: VCSSCommentNode[]
3738
private _selectorParser: CSSSelectorParser | null = null
3839
private readonly lang: string
40+
private anyErrors: any[] = []
3941
/**
4042
* constructor.
4143
* @param {SourceCode} sourceCode the SourceCode object that you can use to work with the source that was passed to ESLint.
@@ -57,6 +59,7 @@ export class CSSParser {
5759

5860
this.commentContainer = []
5961
this._selectorParser = this.createSelectorParser()
62+
this.anyErrors = []
6063

6164
try {
6265
const postcssRoot = this.parseInternal(css) as PostCSSRoot
@@ -66,28 +69,12 @@ export class CSSParser {
6669
postcssRoot,
6770
)
6871
rootNode.comments = this.commentContainer
69-
return rootNode
70-
} catch (e) {
71-
const errorLoc = getESLintLineAndColumnFromPostCSSPosition(
72-
offsetLocation,
73-
e,
74-
)
75-
const errorIndex = this.sourceCode.getIndexFromLoc(errorLoc)
76-
const message = e.reason || e.message
77-
const errorNode = new VCSSParsingError(
78-
null as any,
79-
{
80-
start: errorLoc,
81-
end: errorLoc,
82-
},
83-
errorIndex,
84-
errorIndex,
85-
{
86-
lang: this.lang,
87-
message,
88-
},
72+
rootNode.errors.push(
73+
...this.collectErrors(this.anyErrors, offsetLocation),
8974
)
9075

76+
return rootNode
77+
} catch (e) {
9178
const startIndex = sourceCode.getIndexFromLoc(offsetLocation)
9279
const endIndex = startIndex + css.length
9380
const styleLoc = {
@@ -100,13 +87,59 @@ export class CSSParser {
10087
startIndex,
10188
endIndex,
10289
{
103-
errors: [errorNode],
90+
errors: this.collectErrors(
91+
[...this.anyErrors, e],
92+
offsetLocation,
93+
),
10494
lang: this.lang,
10595
},
10696
)
10797
}
10898
}
10999

100+
private addError(error: any) {
101+
this.anyErrors.push(error)
102+
}
103+
104+
private collectErrors(
105+
errors: any[],
106+
offsetLocation: LineAndColumnData,
107+
): VCSSParsingError[] {
108+
const errorNodes = []
109+
const duplicate = new Set<string>()
110+
for (const error of errors) {
111+
const errorLoc =
112+
getESLintLineAndColumnFromPostCSSPosition(
113+
offsetLocation,
114+
error,
115+
) || offsetLocation
116+
const message = error.reason || error.message
117+
118+
const key = `[${errorLoc.line}:${errorLoc.column}]: ${message}`
119+
if (duplicate.has(key)) {
120+
continue
121+
}
122+
duplicate.add(key)
123+
const errorIndex = this.sourceCode.getIndexFromLoc(errorLoc)
124+
errorNodes.push(
125+
new VCSSParsingError(
126+
null as any,
127+
{
128+
start: errorLoc,
129+
end: errorLoc,
130+
},
131+
errorIndex,
132+
errorIndex,
133+
{
134+
lang: this.lang,
135+
message,
136+
},
137+
),
138+
)
139+
}
140+
return errorNodes
141+
}
142+
110143
protected get selectorParser(): CSSSelectorParser {
111144
return (
112145
this._selectorParser ||
@@ -150,7 +183,8 @@ export class CSSParser {
150183
) ||
151184
// for node type: `root`
152185
sourceCode.getLocFromIndex(
153-
start + (node as PostCSSRoot).source.input.css.length,
186+
sourceCode.getIndexFromLoc(offsetLocation) +
187+
(node as PostCSSRoot).source.input.css.length,
154188
)
155189
const end = sourceCode.getIndexFromLoc(endLoc)
156190
const loc: SourceLocation = {
@@ -179,12 +213,16 @@ export class CSSParser {
179213
return astNode
180214
}
181215

182-
/* eslint-disable class-methods-use-this */
183-
184216
protected parseInternal(css: string): postcss.Root {
185-
return postcss.parse(css)
217+
try {
218+
return postcss.parse(css)
219+
} catch (e) {
220+
this.addError(e)
221+
return postcssSafeParser(css)
222+
}
186223
}
187224

225+
/* eslint-disable class-methods-use-this */
188226
protected createSelectorParser(): CSSSelectorParser {
189227
return new CSSSelectorParser(this.sourceCode, this.commentContainer)
190228
}

lib/styles/parser/selector/scss-selector-parser.ts

Lines changed: 22 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,6 @@ function restoreInterpolationAndInlineComments<T extends PostCSSSPNode>(
300300
} = options
301301

302302
if (node.source) {
303-
let startIndex = null
304-
let endIndex = null
305303
if (node.source.start) {
306304
const cssLoc = node.source.start
307305
const index = cssSourceCode.getIndexFromLoc({
@@ -312,7 +310,6 @@ function restoreInterpolationAndInlineComments<T extends PostCSSSPNode>(
312310
const scssLoc = scssSourceCode.getLocFromIndex(scssIndex)
313311
scssLoc.column++
314312
node.source.start = scssLoc
315-
startIndex = scssIndex
316313
}
317314
if (node.source.end) {
318315
const cssLoc = node.source.end
@@ -322,11 +319,8 @@ function restoreInterpolationAndInlineComments<T extends PostCSSSPNode>(
322319
})
323320
const scssIndex = remapContext.remapIndex(index)
324321
node.source.end = scssSourceCode.getLocFromIndex(scssIndex)
325-
endIndex = scssIndex
326322
}
327-
while (
328-
restoreInterpolations(node, startIndex, endIndex, interpolations)
329-
) {
323+
while (restoreInterpolations(node, interpolations)) {
330324
// loop
331325
}
332326
while (restoreComments(node, inlineComments)) {
@@ -341,70 +335,38 @@ function restoreInterpolationAndInlineComments<T extends PostCSSSPNode>(
341335
return node
342336
}
343337

344-
/* eslint-disable complexity */
345338
/**
346339
* Restore interpolation for given node
347340
*/
348341
function restoreInterpolations(
349342
node: PostCSSSPNode,
350-
startIndex: number | null,
351-
endIndex: number | null,
352343
interpolations: ReplaceInfo[],
353344
): boolean {
354-
/* eslint-enable complexity */
355345
if (!interpolations.length) {
356346
return false
357347
}
358-
if (
359-
node.type === "root" ||
360-
node.type === "selector" ||
361-
node.type === "universal" || // *
362-
node.type === "nesting" || // &
363-
node.type === "comment"
364-
) {
365-
return false
366-
}
367-
if (node.type === "string") {
368-
for (let index = 0; index < interpolations.length; index++) {
369-
const inter = interpolations[index]
370-
if (restoreReplaceNodeProp(node, "value", inter)) {
371-
interpolations.splice(index, 1)
372-
return true
373-
}
374-
}
375-
return false
376-
}
377-
378-
const interpolationIndex = interpolations.findIndex(
379-
inter =>
380-
(startIndex == null || startIndex <= inter.start) &&
381-
(endIndex == null || inter.start < endIndex),
382-
)
383-
if (interpolationIndex < 0) {
384-
return false
385-
}
386-
387-
const inter = interpolations[interpolationIndex]
388-
348+
const targetProperties = []
389349
if (
390350
node.type === "tag" ||
391351
node.type === "class" ||
392352
node.type === "id" ||
393353
node.type === "combinator" ||
394-
node.type === "pseudo"
354+
node.type === "pseudo" ||
355+
node.type === "string"
395356
) {
396-
if (restoreReplaceNodeProp(node, "value", inter)) {
397-
interpolations.splice(interpolationIndex, 1)
398-
return true
399-
}
357+
targetProperties.push("value")
400358
} else if (node.type === "attribute") {
401-
if (restoreReplaceNodeProp(node, "attribute", inter)) {
402-
interpolations.splice(interpolationIndex, 1)
403-
return true
404-
}
405-
if (restoreReplaceNodeProp(node, "value", inter)) {
406-
interpolations.splice(interpolationIndex, 1)
407-
return true
359+
targetProperties.push("attribute")
360+
targetProperties.push("value")
361+
}
362+
363+
for (const prop of targetProperties) {
364+
for (let index = 0; index < interpolations.length; index++) {
365+
const interpolation = interpolations[index]
366+
if (restoreReplaceNodeProp(node, prop, interpolation)) {
367+
interpolations.splice(index, 1)
368+
return true
369+
}
408370
}
409371
}
410372

@@ -426,23 +388,14 @@ function restoreComments(node: PostCSSSPNode, inlineComments: ReplaceInfo[]) {
426388
targetProperties.push("raws.spaces.after")
427389
targetProperties.push("raws.spaces.before")
428390
}
429-
if (!targetProperties.length) {
430-
return false
431-
}
432391

433392
for (const prop of targetProperties) {
434-
const text = `${lodash.get(node, prop, "") || ""}`
435-
const commentIndex = inlineComments.findIndex(comment =>
436-
text.includes(comment.replace),
437-
)
438-
if (commentIndex < 0) {
439-
return false
440-
}
441-
442-
const comment = inlineComments[commentIndex]
443-
if (restoreReplaceNodeProp(node, prop, comment)) {
444-
inlineComments.splice(commentIndex, 1)
445-
return true
393+
for (let index = 0; index < inlineComments.length; index++) {
394+
const comment = inlineComments[index]
395+
if (restoreReplaceNodeProp(node, prop, comment)) {
396+
inlineComments.splice(index, 1)
397+
return true
398+
}
446399
}
447400
}
448401
return false

lib/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { AST } from "vue-eslint-parser"
1+
// eslint-disable-next-line @mysticatea/node/no-missing-import
2+
import AST from "vue-eslint-parser/ast"
23
import postcss from "postcss"
34
import selectorParser from "postcss-selector-parser"
45
// eslint-disable-next-line @mysticatea/node/no-extraneous-import

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"mocha": "^6.2.2",
6363
"nyc": "^14.1.1",
6464
"pack": "^2.2.0",
65+
"postcss-safe-parser": "^4.0.1",
6566
"raw-loader": "^3.1.0",
6667
"rimraf": "^3.0.0",
6768
"ts-node": "^8.4.1",

0 commit comments

Comments
 (0)