Skip to content

Commit a90c6b5

Browse files
authored
Add vue-scoped-css/require-v-slotted-argument rule (#42)
1 parent b1463a3 commit a90c6b5

File tree

9 files changed

+183
-5
lines changed

9 files changed

+183
-5
lines changed

.github/workflows/NpmPublish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010
steps:
1111
- name: checkout
12-
uses: actions/checkout@v1
12+
uses: actions/checkout@v2
1313
- name: setup Node
1414
uses: actions/setup-node@v1
1515
with:

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,13 @@ Enforce all the rules in this category with:
9898

9999
| Rule ID | Description | |
100100
|:--------|:------------|:---|
101-
| [vue-scoped-css/no-deprecated-deep-combinator](https://future-architect.github.io/eslint-plugin-vue-scoped-css/rules/no-deprecated-deep-combinator.html) | disallow using deprecated deep combinators | |
101+
| [vue-scoped-css/no-deprecated-deep-combinator](https://future-architect.github.io/eslint-plugin-vue-scoped-css/rules/no-deprecated-deep-combinator.html) | disallow using deprecated deep combinators | :wrench: |
102102
| [vue-scoped-css/no-parsing-error](https://future-architect.github.io/eslint-plugin-vue-scoped-css/rules/no-parsing-error.html) | Disallow parsing errors in `<style>` | |
103103
| [vue-scoped-css/no-unused-keyframes](https://future-architect.github.io/eslint-plugin-vue-scoped-css/rules/no-unused-keyframes.html) | Reports the `@keyframes` is not used in Scoped CSS. | |
104104
| [vue-scoped-css/no-unused-selector](https://future-architect.github.io/eslint-plugin-vue-scoped-css/rules/no-unused-selector.html) | Reports selectors defined in Scoped CSS not used in `<template>`. | |
105105
| [vue-scoped-css/require-scoped](https://future-architect.github.io/eslint-plugin-vue-scoped-css/rules/require-scoped.html) | Enforce the `<style>` tags to has the `scoped` attribute. | |
106106
| [vue-scoped-css/require-v-deep-argument](https://future-architect.github.io/eslint-plugin-vue-scoped-css/rules/require-v-deep-argument.html) | require selector argument to be passed to `::v-deep()`. | :wrench: |
107+
| [vue-scoped-css/require-v-slotted-argument](https://future-architect.github.io/eslint-plugin-vue-scoped-css/rules/require-v-slotted-argument.html) | require selector argument to be passed to `::v-slotted()`. | |
107108

108109
## Recommended for Vue.js 2.x
109110

docs/rules/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ Enforce all the rules in this category with:
1818

1919
| Rule ID | Description | |
2020
|:--------|:------------|:---|
21-
| [vue-scoped-css/no-deprecated-deep-combinator](./no-deprecated-deep-combinator.md) | disallow using deprecated deep combinators | |
21+
| [vue-scoped-css/no-deprecated-deep-combinator](./no-deprecated-deep-combinator.md) | disallow using deprecated deep combinators | :wrench: |
2222
| [vue-scoped-css/no-parsing-error](./no-parsing-error.md) | Disallow parsing errors in `<style>` | |
2323
| [vue-scoped-css/no-unused-keyframes](./no-unused-keyframes.md) | Reports the `@keyframes` is not used in Scoped CSS. | |
2424
| [vue-scoped-css/no-unused-selector](./no-unused-selector.md) | Reports selectors defined in Scoped CSS not used in `<template>`. | |
2525
| [vue-scoped-css/require-scoped](./require-scoped.md) | Enforce the `<style>` tags to has the `scoped` attribute. | |
2626
| [vue-scoped-css/require-v-deep-argument](./require-v-deep-argument.md) | require selector argument to be passed to `::v-deep()`. | :wrench: |
27+
| [vue-scoped-css/require-v-slotted-argument](./require-v-slotted-argument.md) | require selector argument to be passed to `::v-slotted()`. | |
2728

2829
## Recommended for Vue.js 2.x
2930

docs/rules/no-deprecated-deep-combinator.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ description: "disallow using deprecated deep combinators"
99
> disallow using deprecated deep combinators
1010
1111
- :gear: This rule is included in `"plugin:vue-scoped-css/vue3-recommended"` and `"plugin:vue-scoped-css/all"`.
12+
- :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule.
1213

1314
## :book: Rule Details
1415

1516
This rule reports the use of deprecated deep combinators as errors.
1617

17-
<eslint-code-block :rules="{'vue-scoped-css/no-deprecated-deep-combinator': ['error']}">
18+
<eslint-code-block fix :rules="{'vue-scoped-css/no-deprecated-deep-combinator': ['error']}">
1819

1920
```vue
2021
<style scoped>

docs/rules/require-v-deep-argument.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ This rule reports `::v-deep` pseudo-element with no selector argument passed.
2121
<style scoped>
2222
/* ✗ BAD */
2323
.baz .qux ::v-deep .foo .bar {}
24-
.baz .qux ::v-deep() .foo .bar {}
24+
.baz .qux ::v-deep() {}
2525
2626
/* ✓ GOOD */
2727
.baz .qux ::v-deep(.foo .bar) {}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
pageClass: "rule-details"
3+
sidebarDepth: 0
4+
title: "vue-scoped-css/require-v-slotted-argument"
5+
description: "require selector argument to be passed to `::v-slotted()`."
6+
---
7+
# vue-scoped-css/require-v-slotted-argument
8+
9+
> require selector argument to be passed to `::v-slotted()`.
10+
11+
- :gear: This rule is included in `"plugin:vue-scoped-css/vue3-recommended"` and `"plugin:vue-scoped-css/all"`.
12+
13+
## :book: Rule Details
14+
15+
This rule reports `::v-slotted` pseudo-element with no selector argument passed.
16+
17+
<eslint-code-block :rules="{'vue-scoped-css/require-v-slotted-argument': ['error']}">
18+
19+
```vue
20+
<style scoped>
21+
/* ✗ BAD */
22+
.baz .qux ::v-slotted() {}
23+
.baz .qux ::v-slotted {}
24+
25+
/* ✓ GOOD */
26+
.baz .qux ::v-slotted(.foo .bar) {}
27+
</style>
28+
```
29+
30+
</eslint-code-block>
31+
32+
## :wrench: Options
33+
34+
Nothing.
35+
36+
## Implementation
37+
38+
- [Rule source](https://github.com/future-architect/eslint-plugin-vue-scoped-css/blob/master/lib/rules/require-v-slotted-argument.ts)
39+
- [Test source](https://github.com/future-architect/eslint-plugin-vue-scoped-css/blob/master/tests/lib/rules/require-v-slotted-argument.js)
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import {
2+
getStyleContexts,
3+
getCommentDirectivesReporter,
4+
StyleContext,
5+
ValidStyleContext,
6+
} from "../styles/context"
7+
import type { RuleContext, Rule } from "../types"
8+
import {
9+
isPseudoEmptyArguments,
10+
isVSlottedPseudo,
11+
VSlottedPseudo,
12+
} from "../styles/utils/selectors"
13+
14+
declare const module: {
15+
exports: Rule
16+
}
17+
18+
module.exports = {
19+
meta: {
20+
docs: {
21+
description:
22+
"require selector argument to be passed to `::v-slotted()`.",
23+
categories: ["vue3-recommended"],
24+
default: "warn",
25+
url:
26+
"https://future-architect.github.io/eslint-plugin-vue-scoped-css/rules/require-v-slotted-argument.html",
27+
},
28+
fixable: null,
29+
messages: {
30+
missingArguments:
31+
"Need to pass argument to the `::v-slotted` pseudo-element.",
32+
},
33+
schema: [],
34+
type: "suggestion", // "problem",
35+
},
36+
create(context: RuleContext) {
37+
const styles = getStyleContexts(context)
38+
.filter(StyleContext.isValid)
39+
.filter((style) => style.scoped)
40+
if (!styles.length) {
41+
return {}
42+
}
43+
const reporter = getCommentDirectivesReporter(context)
44+
45+
/**
46+
* Reports the given node
47+
* @param {ASTNode} node node to report
48+
*/
49+
function report(node: VSlottedPseudo) {
50+
reporter.report({
51+
node,
52+
loc: node.loc,
53+
messageId: "missingArguments",
54+
})
55+
}
56+
57+
/**
58+
* Verify the style
59+
*/
60+
function verify(style: ValidStyleContext) {
61+
style.traverseSelectorNodes({
62+
enterNode(node) {
63+
if (
64+
isVSlottedPseudo(node) &&
65+
isPseudoEmptyArguments(node)
66+
) {
67+
report(node)
68+
}
69+
},
70+
})
71+
}
72+
73+
return {
74+
"Program:exit"() {
75+
for (const style of styles) {
76+
verify(style)
77+
}
78+
},
79+
}
80+
},
81+
}

lib/utils/rules.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ const baseRules = [
3636
ruleName: "require-v-deep-argument",
3737
ruleId: "vue-scoped-css/require-v-deep-argument",
3838
},
39+
{
40+
rule: require("../rules/require-v-slotted-argument"),
41+
ruleName: "require-v-slotted-argument",
42+
ruleId: "vue-scoped-css/require-v-slotted-argument",
43+
},
3944
]
4045

4146
export const rules = baseRules.map((obj) => {
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { RuleTester } from "eslint"
2+
const rule = require("../../../lib/rules/require-v-slotted-argument")
3+
4+
const tester = new RuleTester({
5+
parser: require.resolve("vue-eslint-parser"),
6+
parserOptions: {
7+
ecmaVersion: 2019,
8+
sourceType: "module",
9+
},
10+
})
11+
12+
tester.run("require-v-slotted-argument", rule, {
13+
valid: [
14+
`
15+
<template><div class="item">sample</div></template>
16+
<style scoped>
17+
.baz .qux ::v-slotted(.foo .bar) {}
18+
</style>
19+
`,
20+
],
21+
invalid: [
22+
{
23+
code: `
24+
<template><div class="item">sample</div></template>
25+
<style scoped>
26+
.baz .qux ::v-slotted .foo .bar {}
27+
.baz .qux ::v-slotted() {}
28+
</style>
29+
`,
30+
errors: [
31+
{
32+
message:
33+
"Need to pass argument to the `::v-slotted` pseudo-element.",
34+
line: 4,
35+
column: 23,
36+
endLine: 4,
37+
endColumn: 34,
38+
},
39+
{
40+
message:
41+
"Need to pass argument to the `::v-slotted` pseudo-element.",
42+
line: 5,
43+
column: 23,
44+
endLine: 5,
45+
endColumn: 36,
46+
},
47+
],
48+
},
49+
],
50+
})

0 commit comments

Comments
 (0)