eslint-plugin-crisp 1.4.19 → 1.4.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -226,6 +226,7 @@ Each item has emojis denoting:
226
226
  | [crisp/vue-header-check](https://github.com/crisp-oss/eslint-plugin-crisp/blob/master/rules/vue-header-check.js) | Ensures `script`, `template` and `style` tags start with corresponding comment block | | 🟢 |
227
227
  | [crisp/vue-html-indent](https://github.com/crisp-oss/eslint-plugin-crisp/blob/master/rules/vue-html-indent.js) | Enforces consistent indentation in `template` (supports for Pug) | | 🟢 |
228
228
  | [crisp/vue-html-quotes](https://github.com/crisp-oss/eslint-plugin-crisp/blob/master/rules/vue-html-quotes.js) | Enforces HTML attributes to be enclosed with double quotes | | 🟢 |
229
+ | [crisp/vue-no-name-option](https://github.com/crisp-oss/eslint-plugin-crisp/blob/master/rules/vue-no-name-option.js) | Disallows explicit component names in Vue single-file components | | 🟢 |
229
230
  | [crisp/vue-no-regex-data](https://github.com/crisp-oss/eslint-plugin-crisp/blob/master/rules/vue-no-regex-data.js) | Disallows regular expressions to be declared in Vue data object | | 🟢 |
230
231
  | [crisp/vue-props-declaration-line-break](https://github.com/crisp-oss/eslint-plugin-crisp/blob/master/rules/vue-props-declaration-line-break.js) | Enforces line break between type and default function in prop definition | | 🟢 |
231
232
  | [crisp/vue-props-declaration-multiline](https://github.com/crisp-oss/eslint-plugin-crisp/blob/master/rules/vue-props-declaration-multiline.js) | Enforces props declarations to be multiline | | 🟢 |
package/index.js CHANGED
@@ -52,6 +52,7 @@ import ruleVueHtmlIndent from "./rules/vue-html-indent.js";
52
52
  import ruleVueHtmlQuotes from "./rules/vue-html-quotes.js";
53
53
  import ruleVueMethodsSeparator from "./rules/vue-methods-separator.js";
54
54
  import ruleVueNameProp from "./rules/vue-name-prop.js";
55
+ import ruleVueNoNameOption from "./rules/vue-no-name-option.js";
55
56
  import ruleVueNoRegexData from "./rules/vue-no-regex-data.js";
56
57
  import ruleVuePropsDeclarationLineBreak from "./rules/vue-props-declaration-line-break.js";
57
58
  import ruleVuePropsDeclarationMultiline from "./rules/vue-props-declaration-multiline.js";
@@ -122,6 +123,7 @@ const plugin = {
122
123
  "vue-html-quotes": ruleVueHtmlQuotes,
123
124
  "vue-methods-separator": ruleVueMethodsSeparator,
124
125
  "vue-name-prop": ruleVueNameProp,
126
+ "vue-no-name-option": ruleVueNoNameOption,
125
127
  "vue-no-regex-data": ruleVueNoRegexData,
126
128
  "vue-props-declaration-line-break": ruleVuePropsDeclarationLineBreak,
127
129
  "vue-props-declaration-multiline": ruleVuePropsDeclarationMultiline,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-crisp",
3
- "version": "1.4.19",
3
+ "version": "1.4.20",
4
4
  "description": "Custom ESLint Rules for Crisp",
5
5
  "author": "Crisp IM SAS",
6
6
  "main": "index.js",
@@ -391,6 +391,7 @@ export default function configRecommendedVue(pluginCrisp) {
391
391
  "crisp/vue-html-quotes": "error",
392
392
  "crisp/vue-methods-separator": "error",
393
393
  "crisp/vue-name-prop": "error",
394
+ "crisp/vue-no-name-option": "error",
394
395
  "crisp/vue-no-regex-data": "error",
395
396
  "crisp/vue-props-declaration-line-break": "error",
396
397
  "crisp/vue-props-declaration-multiline": "error",
@@ -0,0 +1,108 @@
1
+ export default {
2
+ meta: {
3
+ type: "suggestion",
4
+ docs: {
5
+ description: "disallow explicit names in Vue single-file components",
6
+ category: "Best Practices",
7
+ recommended: false
8
+ },
9
+ fixable: "code",
10
+ schema: []
11
+ },
12
+
13
+ create(context) {
14
+ const fileName = (context.filename || context.getFilename()).replace(/\\/g, "/");
15
+
16
+ if (!fileName.endsWith(".vue")) {
17
+ return {};
18
+ }
19
+
20
+ return {
21
+ ExportDefaultDeclaration(node) {
22
+ const componentOptions = getComponentOptions(node.declaration);
23
+
24
+ if (!componentOptions) {
25
+ return;
26
+ }
27
+
28
+ componentOptions.properties.forEach((property) => {
29
+ if (!isNameProperty(property)) {
30
+ return;
31
+ }
32
+
33
+ context.report({
34
+ node: property,
35
+ message: "Vue single-file components must rely on their inferred filename.",
36
+
37
+ fix(fixer) {
38
+ return removeProperty(fixer, context, componentOptions, property);
39
+ }
40
+ });
41
+ });
42
+ }
43
+ };
44
+ }
45
+ };
46
+
47
+ // Returns the component options passed to defineComponent()
48
+ function getComponentOptions(node) {
49
+ if (!isDefineComponentCall(node)) {
50
+ return null;
51
+ }
52
+
53
+ const options = node.arguments[0];
54
+
55
+ return options?.type === "ObjectExpression" ? options : null;
56
+ }
57
+
58
+ // Returns whether the node is a defineComponent() call
59
+ function isDefineComponentCall(node) {
60
+ if (!node || node.type !== "CallExpression") {
61
+ return false;
62
+ }
63
+
64
+ if (node.callee.type === "Identifier") {
65
+ return node.callee.name === "defineComponent";
66
+ }
67
+
68
+ return (
69
+ node.callee.type === "MemberExpression" &&
70
+ node.callee.property.type === "Identifier" &&
71
+ node.callee.property.name === "defineComponent"
72
+ );
73
+ }
74
+
75
+ // Returns whether the property is the component name option
76
+ function isNameProperty(property) {
77
+ if (property.type !== "Property") {
78
+ return false;
79
+ }
80
+
81
+ if (property.key.type === "Identifier") {
82
+ return property.key.name === "name";
83
+ }
84
+
85
+ return property.key.type === "Literal" && property.key.value === "name";
86
+ }
87
+
88
+ // Removes a property and its adjacent comma
89
+ function removeProperty(fixer, context, options, property) {
90
+ const sourceCode = context.sourceCode || context.getSourceCode();
91
+ const nextToken = sourceCode.getTokenAfter(property);
92
+
93
+ if (nextToken?.value === ",") {
94
+ return fixer.removeRange([property.range[0], nextToken.range[1]]);
95
+ }
96
+
97
+ const propertyIndex = options.properties.indexOf(property);
98
+
99
+ if (propertyIndex > 0) {
100
+ const previousToken = sourceCode.getTokenBefore(property);
101
+
102
+ if (previousToken?.value === ",") {
103
+ return fixer.removeRange([previousToken.range[0], property.range[1]]);
104
+ }
105
+ }
106
+
107
+ return fixer.remove(property);
108
+ }