Skip to content

Commit a0ff678

Browse files
authored
Supports Stylus (#16)
1 parent 651ddc7 commit a0ff678

File tree

146 files changed

+16016
-1534
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

146 files changed

+16016
-1534
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ This ESLint plugin provides linting rules relate to better ways to help you avoi
2222
- Provides linting rules for Scoped CSS.
2323
- Supports CSS syntax including level 4 selectors.
2424
- Supports `<style lang="scss">`.
25+
- Supports `<style lang="stylus">`.
2526
- Parses `<style>`, `<template>` and `<script>` blocks.
2627

2728
You can check on the [Online DEMO](https://future-architect.github.io/eslint-plugin-vue-scoped-css/playground/).

docs/.vuepress/config.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
const { rules } = require("../../dist/utils/rules")
22
const categories = require("./categories")
3+
// eslint-disable-next-line @mysticatea/node/no-extraneous-require
4+
const webpack = require("webpack")
35

46
const uncategorizedRules = rules.filter(
57
rule => !rule.meta.docs.category && !rule.meta.deprecated
@@ -43,8 +45,18 @@ module.exports = {
4345
configureWebpack(_config, _isServer) {
4446
return {
4547
resolve: {
46-
alias: {},
48+
alias: {
49+
// eslint-disable-next-line @mysticatea/node/no-extraneous-require
50+
stylus: require.resolve("stylus/lib/stylus"),
51+
glob: require.resolve("./shim/glob"),
52+
"safer-buffer": require.resolve("./shim/safer-buffer"),
53+
},
4754
},
55+
plugins: [
56+
new webpack.DefinePlugin({
57+
"process.version": JSON.stringify("v12.13.0"),
58+
}),
59+
],
4860
}
4961
},
5062

docs/.vuepress/shim/glob.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = {}

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ This ESLint plugin provides linting rules relate to better ways to help you avoi
2222
- Provides linting rules for Scoped CSS.
2323
- Supports CSS syntax including level 4 selectors.
2424
- Supports `<style lang="scss">`.
25+
- Supports `<style lang="stylus">`.
2526
- Parses `<style>`, `<template>` and `<script>` blocks.
2627

2728
You can check on the [Online DEMO](./playground/).

lib/index.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
import { rules } from "./utils/rules"
1+
import { rules as ruleList } from "./utils/rules"
22
import { Rule } from "./types"
33

4-
const allRules = rules.reduce((obj, r) => {
4+
const configs = {
5+
base: require("./configs/base"),
6+
recommended: require("./configs/recommended"),
7+
all: require("./configs/all"),
8+
}
9+
10+
const rules = ruleList.reduce((obj, r) => {
511
obj[r.meta.docs.ruleName] = r
612
return obj
713
}, {} as { [key: string]: Rule })
814

915
export = {
10-
configs: {
11-
base: require("./configs/base"),
12-
recommended: require("./configs/recommended"),
13-
all: require("./configs/all"),
14-
},
15-
rules: allRules,
16+
configs,
17+
rules,
1618
}

lib/rules/no-unused-keyframes.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ module.exports = {
4040
function report(node: VCSSAtRule) {
4141
const paramsStartIndex =
4242
node.range[0] + // start index of at-rule
43-
1 + // `@`
43+
node.identifier.length + // `@`
4444
node.name.length + // `nest`
4545
(node.node.raws.afterName || "").length // comments and spaces
4646
const paramsEndIndex = paramsStartIndex + node.rawParamsText.length
@@ -71,7 +71,10 @@ module.exports = {
7171
style.traverseNodes({
7272
enterNode(node) {
7373
if (node.type === "VCSSAtRule") {
74-
if (/-?keyframes$/u.test(node.name)) {
74+
if (
75+
/-?keyframes$/u.test(node.name) &&
76+
node.identifier === "@"
77+
) {
7578
// register keyframes
7679
keyframes.push({
7780
params: Template.ofParams(node),

lib/styles/ast.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ export class VCSSStyleRule extends HasParentNode<
186186
props: {
187187
parent: VCSSContainerNode
188188
selectorText?: string
189-
rawSelectorText?: string
189+
rawSelectorText: string | null
190190
selectors?: VCSSSelectorNode[]
191191
nodes?: VCSSNode[]
192192
},
@@ -268,6 +268,7 @@ export class VCSSDeclarationProperty extends HasParentNode<
268268
export class VCSSAtRule extends HasParentNode<"VCSSAtRule", VCSSContainerNode> {
269269
public nodes: VCSSNode[]
270270
public readonly name: string
271+
public readonly identifier: string
271272
public readonly paramsText: string
272273
public readonly rawParamsText: string
273274
public rawSelectorText?: string
@@ -289,8 +290,9 @@ export class VCSSAtRule extends HasParentNode<"VCSSAtRule", VCSSContainerNode> {
289290
end: number,
290291
props: {
291292
parent: VCSSContainerNode
293+
identifier: string
292294
paramsText?: string
293-
rawParamsText?: string
295+
rawParamsText: string | null
294296
selectors?: VCSSSelectorNode[]
295297
nodes?: VCSSNode[]
296298
},
@@ -299,6 +301,7 @@ export class VCSSAtRule extends HasParentNode<"VCSSAtRule", VCSSContainerNode> {
299301
this.node = node
300302

301303
this.name = getProp(props, node, "name")
304+
this.identifier = props.identifier
302305
this.paramsText = props.paramsText ?? node.params
303306
if (props.rawParamsText != null) {
304307
this.rawParamsText = props.rawParamsText
@@ -1008,7 +1011,9 @@ export type VCSSSelectorNode =
10081011
| VCSSSelectorCombinator
10091012
| VCSSUnknownSelector
10101013
| VCSSSelectorContainerNode
1011-
export type VCSSSelectorContainerNode = VCSSSelector | VCSSSelectorPseudo
1014+
export type VCSSSelectorContainerNode = (VCSSSelector | VCSSSelectorPseudo) & {
1015+
nodes: VCSSSelectorValueNode[]
1016+
}
10121017
export type VCSSSelectorValueNode =
10131018
| VCSSTypeSelector
10141019
| VCSSIDSelector

lib/styles/context/style/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ function getInvalidEOFError(
1818
let errors = body?.errors
1919
let inDocumentFragment = false
2020
if (errors == null) {
21+
/* istanbul ignore if */
2122
if (!context.parserServices.getDocumentFragment) {
2223
return null
2324
}
2425
const df = context.parserServices.getDocumentFragment()
2526
inDocumentFragment = true
2627
errors = df?.errors
28+
/* istanbul ignore if */
2729
if (errors == null) {
2830
return null
2931
}
@@ -62,6 +64,7 @@ function getStyleElements(context: RuleContext): AST.VElement[] {
6264
const sourceCode = context.getSourceCode()
6365
const { ast } = sourceCode
6466
const templateBody = ast.templateBody as AST.ESLintProgram | undefined
67+
/* istanbul ignore if */
6568
if (templateBody) {
6669
document = templateBody.parent as AST.VDocumentFragment
6770
}

lib/styles/parser/css-parser.ts

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,12 @@ export class CSSParser {
109109
const duplicate = new Set<string>()
110110
for (const error of errors) {
111111
const errorLoc =
112-
getESLintLineAndColumnFromPostCSSPosition(
113-
offsetLocation,
114-
error,
115-
) || offsetLocation
112+
error.line != null && error.column != null
113+
? getESLintLineAndColumnFromPostCSSPosition(
114+
offsetLocation,
115+
error,
116+
)
117+
: offsetLocation
116118
const message = error.reason || error.message
117119

118120
const key = `[${errorLoc.line}:${errorLoc.column}]: ${message}`
@@ -241,7 +243,7 @@ export class CSSParser {
241243
loc: SourceLocation,
242244
start: number,
243245
end: number,
244-
) {
246+
): VCSSNode | null {
245247
return new VCSSStyleSheet(node, loc, start, end, { lang: this.lang })
246248
}
247249

@@ -260,24 +262,27 @@ export class CSSParser {
260262
start: number,
261263
end: number,
262264
parent: VCSSContainerNode,
263-
) {
264-
const astNode = new VCSSStyleRule(node, loc, start, end, { parent })
265+
): VCSSNode | null {
266+
const astNode = new VCSSStyleRule(node, loc, start, end, {
267+
parent,
268+
rawSelectorText: this.getRaw(node, "selector")?.raw ?? null,
269+
})
265270
astNode.selectors = this.selectorParser.parse(
266271
astNode.rawSelectorText,
267272
astNode.loc.start,
268273
astNode,
269274
)
270275

271-
if (node.raws.between?.trim()) {
276+
if (this.getRaw(node, "between")?.trim()) {
272277
this.parseRuleRawsBetween(node, astNode)
273278
}
274279

275280
return astNode
276281
}
277282

278283
protected parseRuleRawsBetween(node: PostCSSRule, astNode: VCSSNode) {
279-
const { between } = node.raws
280-
const rawSelector = node.raws.selector?.raw ?? node.selector
284+
const between = this.getRaw(node, "between")
285+
const rawSelector = this.getRaw(node, "selector")?.raw ?? node.selector
281286
const betweenStart = astNode.range[0] + rawSelector.length
282287
const postcssRoot = this.parseInternal(between || "") as PostCSSRoot
283288

@@ -302,15 +307,19 @@ export class CSSParser {
302307
start: number,
303308
end: number,
304309
parent: VCSSContainerNode,
305-
) {
306-
const astNode = new VCSSAtRule(node, loc, start, end, { parent })
310+
): VCSSNode | null {
311+
const astNode = new VCSSAtRule(node, loc, start, end, {
312+
parent,
313+
rawParamsText: this.getRaw(node, "params")?.raw ?? null,
314+
identifier: this.getRaw(node as any, "identifier") ?? "@",
315+
})
307316
if (node.name === "nest") {
308317
// The parameters following `@nest` are parsed as selectors.
309318
const paramsStartIndex =
310319
astNode.range[0] + // start index of at-rule
311-
1 + // `@`
320+
astNode.identifier.length + // `@`
312321
astNode.name.length + // `nest`
313-
(node.raws.afterName || "").length // comments and spaces
322+
(this.getRaw(node, "afterName") || "").length // comments and spaces
314323

315324
astNode.selectors = this.selectorParser.parse(
316325
astNode.rawParamsText,
@@ -319,22 +328,22 @@ export class CSSParser {
319328
)
320329
}
321330

322-
if (node.raws.afterName?.trim()) {
331+
if (this.getRaw(node, "afterName")?.trim()) {
323332
this.parseAtruleRawsAfterName(node, astNode)
324333
}
325-
if (node.raws.between?.trim()) {
334+
if (this.getRaw(node, "between")?.trim()) {
326335
this.parseAtruleRawsBetween(node, astNode)
327336
}
328337

329338
return astNode
330339
}
331340

332341
private parseAtruleRawsAfterName(node: PostCSSAtRule, astNode: VCSSAtRule) {
333-
const { afterName } = node.raws
342+
const afterName = this.getRaw(node, "afterName")
334343

335344
const afterNameStart =
336345
astNode.range[0] + // start index of at-rule
337-
1 + // `@`
346+
astNode.identifier.length + // `@`
338347
astNode.name.length // `nest`
339348
const postcssRoot = this.parseInternal(afterName || "") as PostCSSRoot
340349

@@ -345,14 +354,14 @@ export class CSSParser {
345354
}
346355

347356
private parseAtruleRawsBetween(node: PostCSSAtRule, astNode: VCSSAtRule) {
348-
const { between } = node.raws
357+
const between = this.getRaw(node, "between")
349358

350-
const rawParams = node.raws.params?.raw ?? node.params
359+
const rawParams = this.getRaw(node, "params")?.raw ?? node.params
351360
const betweenStart =
352361
astNode.range[0] + // start index of at-rule
353-
1 + // `@`
362+
astNode.identifier.length + // `@`
354363
astNode.name.length + // `nest`
355-
(node.raws.afterName || "").length + // comments and spaces
364+
(this.getRaw(node, "afterName") || "").length + // comments and spaces
356365
rawParams.length
357366

358367
const postcssRoot = this.parseInternal(between || "") as PostCSSRoot
@@ -377,7 +386,7 @@ export class CSSParser {
377386
start: number,
378387
end: number,
379388
parent: VCSSContainerNode,
380-
) {
389+
): VCSSNode | null {
381390
// adjust star hack
382391
// `*color: red`
383392
// ^
@@ -418,7 +427,7 @@ export class CSSParser {
418427
start: number,
419428
end: number,
420429
parent: VCSSContainerNode,
421-
): null {
430+
): VCSSNode | null {
422431
this.commentContainer.push(
423432
new VCSSComment(node, node.text, loc, start, end, { parent }),
424433
)
@@ -440,13 +449,20 @@ export class CSSParser {
440449
start: number,
441450
end: number,
442451
parent: VCSSContainerNode,
443-
) {
452+
): VCSSNode | null {
444453
return new VCSSUnknown(node, loc, start, end, {
445454
parent,
446455
unknownType: node.type,
447456
})
448457
}
449458

459+
protected getRaw<N extends PostCSSNode, K extends keyof N["raws"] & string>(
460+
node: N,
461+
keyName: K,
462+
): N["raws"][K] {
463+
return (node.raws as any)[keyName]
464+
}
465+
450466
/* eslint-enable class-methods-use-this */
451467
}
452468

0 commit comments

Comments
 (0)