eslint-plugin-mpx 0.0.21 → 0.2.0

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.
Files changed (180) hide show
  1. package/README.md +3 -0
  2. package/lib/.DS_Store +0 -0
  3. package/lib/configs/base.js +10 -5
  4. package/lib/configs/mpx-essential.js +0 -30
  5. package/lib/index.js +1 -150
  6. package/lib/rules/comment-directive.js +2 -2
  7. package/lib/rules/component-tags-order.js +2 -2
  8. package/lib/rules/eqeqeq.js +4 -2
  9. package/lib/rules/html-end-tags.js +1 -1
  10. package/lib/rules/no-arrow-functions-in-watch.js +2 -2
  11. package/lib/rules/no-async-in-computed-properties.js +5 -5
  12. package/lib/rules/no-dupe-keys.js +3 -3
  13. package/lib/rules/no-dupe-wx-elif.js +8 -3
  14. package/lib/rules/no-duplicate-attributes.js +6 -16
  15. package/lib/rules/no-parsing-error.js +2 -2
  16. package/lib/rules/no-reserved-keys.js +3 -3
  17. package/lib/rules/no-side-effects-in-computed-properties.js +8 -9
  18. package/lib/rules/return-in-computed-property.js +3 -3
  19. package/lib/rules/syntaxes/dynamic-directive-arguments.js +2 -1
  20. package/lib/rules/syntaxes/scope-attribute.js +2 -1
  21. package/lib/rules/syntaxes/slot-attribute.js +2 -1
  22. package/lib/rules/syntaxes/v-bind-prop-modifier-shorthand.js +2 -1
  23. package/lib/rules/valid-wx-elif.js +1 -1
  24. package/lib/rules/valid-wx-else.js +1 -1
  25. package/lib/rules/valid-wx-for.js +2 -2
  26. package/lib/rules/valid-wx-if.js +1 -1
  27. package/lib/rules/valid-wx-model.js +2 -2
  28. package/lib/utils/index.js +504 -490
  29. package/lib/utils/keycode-to-key.js +60 -60
  30. package/lib/utils/{vue-reserved.json → mpx-reserved.json} +2 -2
  31. package/package.json +18 -15
  32. package/lib/configs/essential.js +0 -51
  33. package/lib/configs/no-layout-rules.js +0 -47
  34. package/lib/configs/recommended.js +0 -17
  35. package/lib/configs/strongly-recommended.js +0 -32
  36. package/lib/configs/vue3-essential.js +0 -71
  37. package/lib/configs/vue3-recommended.js +0 -17
  38. package/lib/configs/vue3-strongly-recommended.js +0 -33
  39. package/lib/rules/array-bracket-spacing.js +0 -12
  40. package/lib/rules/arrow-spacing.js +0 -9
  41. package/lib/rules/attribute-hyphenation.js +0 -121
  42. package/lib/rules/attributes-order.js +0 -281
  43. package/lib/rules/block-spacing.js +0 -11
  44. package/lib/rules/brace-style.js +0 -11
  45. package/lib/rules/camelcase.js +0 -9
  46. package/lib/rules/comma-dangle.js +0 -9
  47. package/lib/rules/comma-spacing.js +0 -12
  48. package/lib/rules/comma-style.js +0 -20
  49. package/lib/rules/component-definition-name-casing.js +0 -108
  50. package/lib/rules/component-name-in-template-casing.js +0 -164
  51. package/lib/rules/custom-event-name-casing.js +0 -214
  52. package/lib/rules/dot-location.js +0 -9
  53. package/lib/rules/dot-notation.js +0 -9
  54. package/lib/rules/func-call-spacing.js +0 -11
  55. package/lib/rules/html-closing-bracket-newline.js +0 -115
  56. package/lib/rules/html-closing-bracket-spacing.js +0 -137
  57. package/lib/rules/html-comment-content-newline.js +0 -215
  58. package/lib/rules/html-comment-content-spacing.js +0 -179
  59. package/lib/rules/html-comment-indent.js +0 -258
  60. package/lib/rules/html-indent.js +0 -81
  61. package/lib/rules/html-quotes.js +0 -107
  62. package/lib/rules/html-self-closing.js +0 -222
  63. package/lib/rules/jsx-uses-vars.js +0 -73
  64. package/lib/rules/key-spacing.js +0 -11
  65. package/lib/rules/keyword-spacing.js +0 -11
  66. package/lib/rules/match-component-file-name.js +0 -151
  67. package/lib/rules/max-attributes-per-line.js +0 -194
  68. package/lib/rules/max-len.js +0 -561
  69. package/lib/rules/multiline-html-element-content-newline.js +0 -246
  70. package/lib/rules/mustache-interpolation-spacing.js +0 -107
  71. package/lib/rules/name-property-casing.js +0 -71
  72. package/lib/rules/no-bare-strings-in-template.js +0 -275
  73. package/lib/rules/no-boolean-default.js +0 -114
  74. package/lib/rules/no-confusing-v-for-v-if.js +0 -69
  75. package/lib/rules/no-custom-modifiers-on-v-model.js +0 -59
  76. package/lib/rules/no-deprecated-data-object-declaration.js +0 -95
  77. package/lib/rules/no-deprecated-destroyed-lifecycle.js +0 -101
  78. package/lib/rules/no-deprecated-dollar-listeners-api.js +0 -72
  79. package/lib/rules/no-deprecated-dollar-scopedslots-api.js +0 -79
  80. package/lib/rules/no-deprecated-events-api.js +0 -69
  81. package/lib/rules/no-deprecated-filter.js +0 -44
  82. package/lib/rules/no-deprecated-functional-template.js +0 -56
  83. package/lib/rules/no-deprecated-html-element-is.js +0 -54
  84. package/lib/rules/no-deprecated-inline-template.js +0 -47
  85. package/lib/rules/no-deprecated-scope-attribute.js +0 -31
  86. package/lib/rules/no-deprecated-slot-attribute.js +0 -29
  87. package/lib/rules/no-deprecated-slot-scope-attribute.js +0 -34
  88. package/lib/rules/no-deprecated-v-bind-sync.js +0 -62
  89. package/lib/rules/no-deprecated-v-on-native-modifier.js +0 -50
  90. package/lib/rules/no-deprecated-v-on-number-modifiers.js +0 -61
  91. package/lib/rules/no-deprecated-vue-config-keycodes.js +0 -53
  92. package/lib/rules/no-duplicate-attr-inheritance.js +0 -67
  93. package/lib/rules/no-empty-component-block.js +0 -109
  94. package/lib/rules/no-empty-pattern.js +0 -9
  95. package/lib/rules/no-extra-parens.js +0 -182
  96. package/lib/rules/no-irregular-whitespace.js +0 -251
  97. package/lib/rules/no-lifecycle-after-await.js +0 -133
  98. package/lib/rules/no-lone-template.js +0 -129
  99. package/lib/rules/no-multi-spaces.js +0 -107
  100. package/lib/rules/no-multiple-objects-in-class.js +0 -59
  101. package/lib/rules/no-multiple-slot-args.js +0 -118
  102. package/lib/rules/no-multiple-template-root.js +0 -101
  103. package/lib/rules/no-mutating-props.js +0 -323
  104. package/lib/rules/no-potential-component-option-typo.js +0 -125
  105. package/lib/rules/no-ref-as-operand.js +0 -189
  106. package/lib/rules/no-reserved-component-names.js +0 -187
  107. package/lib/rules/no-restricted-component-options.js +0 -215
  108. package/lib/rules/no-restricted-static-attribute.js +0 -164
  109. package/lib/rules/no-restricted-syntax.js +0 -9
  110. package/lib/rules/no-restricted-v-bind.js +0 -184
  111. package/lib/rules/no-setup-props-destructure.js +0 -149
  112. package/lib/rules/no-spaces-around-equal-signs-in-attribute.js +0 -57
  113. package/lib/rules/no-sparse-arrays.js +0 -9
  114. package/lib/rules/no-static-inline-styles.js +0 -141
  115. package/lib/rules/no-template-key.js +0 -48
  116. package/lib/rules/no-template-shadow.js +0 -101
  117. package/lib/rules/no-template-target-blank.js +0 -138
  118. package/lib/rules/no-textarea-mustache.js +0 -46
  119. package/lib/rules/no-unregistered-components.js +0 -187
  120. package/lib/rules/no-unsupported-features.js +0 -157
  121. package/lib/rules/no-unused-components.js +0 -143
  122. package/lib/rules/no-unused-properties.js +0 -742
  123. package/lib/rules/no-unused-vars.js +0 -147
  124. package/lib/rules/no-use-v-if-with-v-for.js +0 -119
  125. package/lib/rules/no-useless-concat.js +0 -9
  126. package/lib/rules/no-useless-mustaches.js +0 -154
  127. package/lib/rules/no-useless-v-bind.js +0 -150
  128. package/lib/rules/no-v-html.js +0 -36
  129. package/lib/rules/no-v-model-argument.js +0 -49
  130. package/lib/rules/no-watch-after-await.js +0 -142
  131. package/lib/rules/object-curly-newline.js +0 -12
  132. package/lib/rules/object-curly-spacing.js +0 -12
  133. package/lib/rules/object-property-newline.js +0 -12
  134. package/lib/rules/one-component-per-file.js +0 -50
  135. package/lib/rules/operator-linebreak.js +0 -9
  136. package/lib/rules/order-in-components.js +0 -341
  137. package/lib/rules/padding-line-between-blocks.js +0 -220
  138. package/lib/rules/prefer-template.js +0 -9
  139. package/lib/rules/prop-name-casing.js +0 -66
  140. package/lib/rules/require-component-is.js +0 -45
  141. package/lib/rules/require-default-prop.js +0 -190
  142. package/lib/rules/require-direct-export.js +0 -128
  143. package/lib/rules/require-explicit-emits.js +0 -511
  144. package/lib/rules/require-name-property.js +0 -43
  145. package/lib/rules/require-prop-type-constructor.js +0 -99
  146. package/lib/rules/require-prop-types.js +0 -103
  147. package/lib/rules/require-render-return.js +0 -50
  148. package/lib/rules/require-slots-as-functions.js +0 -120
  149. package/lib/rules/require-toggle-inside-transition.js +0 -89
  150. package/lib/rules/require-v-for-key.js +0 -62
  151. package/lib/rules/require-valid-default-prop.js +0 -338
  152. package/lib/rules/return-in-emits-validator.js +0 -141
  153. package/lib/rules/script-indent.js +0 -56
  154. package/lib/rules/singleline-html-element-content-newline.js +0 -215
  155. package/lib/rules/sort-keys.js +0 -282
  156. package/lib/rules/space-in-parens.js +0 -12
  157. package/lib/rules/space-infix-ops.js +0 -11
  158. package/lib/rules/space-unary-ops.js +0 -11
  159. package/lib/rules/static-class-names-order.js +0 -61
  160. package/lib/rules/template-curly-spacing.js +0 -12
  161. package/lib/rules/this-in-template.js +0 -128
  162. package/lib/rules/use-v-on-exact.js +0 -228
  163. package/lib/rules/v-bind-style.js +0 -76
  164. package/lib/rules/v-for-delimiter-style.js +0 -69
  165. package/lib/rules/v-on-function-call.js +0 -172
  166. package/lib/rules/v-on-style.js +0 -58
  167. package/lib/rules/v-slot-style.js +0 -155
  168. package/lib/rules/valid-template-root.js +0 -69
  169. package/lib/rules/valid-v-bind-sync.js +0 -179
  170. package/lib/rules/valid-v-bind.js +0 -62
  171. package/lib/rules/valid-v-cloak.js +0 -58
  172. package/lib/rules/valid-v-html.js +0 -58
  173. package/lib/rules/valid-v-is.js +0 -95
  174. package/lib/rules/valid-v-on.js +0 -153
  175. package/lib/rules/valid-v-once.js +0 -58
  176. package/lib/rules/valid-v-pre.js +0 -58
  177. package/lib/rules/valid-v-show.js +0 -58
  178. package/lib/rules/valid-v-slot.js +0 -290
  179. package/lib/rules/valid-v-text.js +0 -58
  180. package/lib/utils/indent-common.js +0 -2085
@@ -1,246 +0,0 @@
1
- /**
2
- * @author Yosuke Ota
3
- * See LICENSE file in root directory for full license.
4
- */
5
- 'use strict'
6
-
7
- // ------------------------------------------------------------------------------
8
- // Requirements
9
- // ------------------------------------------------------------------------------
10
-
11
- const utils = require('../utils')
12
- const casing = require('../utils/casing')
13
- const INLINE_ELEMENTS = require('../utils/inline-non-void-elements.json')
14
-
15
- // ------------------------------------------------------------------------------
16
- // Helpers
17
- // ------------------------------------------------------------------------------
18
-
19
- /**
20
- * @param {VElement & { endTag: VEndTag }} element
21
- */
22
- function isMultilineElement(element) {
23
- return element.loc.start.line < element.endTag.loc.start.line
24
- }
25
-
26
- /**
27
- * @param {any} options
28
- */
29
- function parseOptions(options) {
30
- return Object.assign(
31
- {
32
- ignores: ['pre', 'textarea'].concat(INLINE_ELEMENTS),
33
- ignoreWhenEmpty: true,
34
- allowEmptyLines: false
35
- },
36
- options
37
- )
38
- }
39
-
40
- /**
41
- * @param {number} lineBreaks
42
- */
43
- function getPhrase(lineBreaks) {
44
- switch (lineBreaks) {
45
- case 0:
46
- return 'no'
47
- default:
48
- return `${lineBreaks}`
49
- }
50
- }
51
- /**
52
- * Check whether the given element is empty or not.
53
- * This ignores whitespaces, doesn't ignore comments.
54
- * @param {VElement & { endTag: VEndTag }} node The element node to check.
55
- * @param {SourceCode} sourceCode The source code object of the current context.
56
- * @returns {boolean} `true` if the element is empty.
57
- */
58
- function isEmpty(node, sourceCode) {
59
- const start = node.startTag.range[1]
60
- const end = node.endTag.range[0]
61
- return sourceCode.text.slice(start, end).trim() === ''
62
- }
63
-
64
- // ------------------------------------------------------------------------------
65
- // Rule Definition
66
- // ------------------------------------------------------------------------------
67
-
68
- module.exports = {
69
- meta: {
70
- type: 'layout',
71
- docs: {
72
- description:
73
- 'require a line break before and after the contents of a multiline element',
74
- categories: ['vue3-strongly-recommended', 'strongly-recommended'],
75
- url:
76
- 'https://eslint.vuejs.org/rules/multiline-html-element-content-newline.html'
77
- },
78
- fixable: 'whitespace',
79
- schema: [
80
- {
81
- type: 'object',
82
- properties: {
83
- ignoreWhenEmpty: {
84
- type: 'boolean'
85
- },
86
- ignores: {
87
- type: 'array',
88
- items: { type: 'string' },
89
- uniqueItems: true,
90
- additionalItems: false
91
- },
92
- allowEmptyLines: {
93
- type: 'boolean'
94
- }
95
- },
96
- additionalProperties: false
97
- }
98
- ],
99
- messages: {
100
- unexpectedAfterClosingBracket:
101
- 'Expected 1 line break after opening tag (`<{{name}}>`), but {{actual}} line breaks found.',
102
- unexpectedBeforeOpeningBracket:
103
- 'Expected 1 line break before closing tag (`</{{name}}>`), but {{actual}} line breaks found.'
104
- }
105
- },
106
- /** @param {RuleContext} context */
107
- create(context) {
108
- const options = parseOptions(context.options[0])
109
- const ignores = options.ignores
110
- const ignoreWhenEmpty = options.ignoreWhenEmpty
111
- const allowEmptyLines = options.allowEmptyLines
112
- const template =
113
- context.parserServices.getTemplateBodyTokenStore &&
114
- context.parserServices.getTemplateBodyTokenStore()
115
- const sourceCode = context.getSourceCode()
116
-
117
- /** @type {VElement | null} */
118
- let inIgnoreElement = null
119
-
120
- /**
121
- * @param {VElement} node
122
- */
123
- function isIgnoredElement(node) {
124
- return (
125
- ignores.includes(node.name) ||
126
- ignores.includes(casing.pascalCase(node.rawName)) ||
127
- ignores.includes(casing.kebabCase(node.rawName))
128
- )
129
- }
130
-
131
- /**
132
- * @param {number} lineBreaks
133
- */
134
- function isInvalidLineBreaks(lineBreaks) {
135
- if (allowEmptyLines) {
136
- return lineBreaks === 0
137
- } else {
138
- return lineBreaks !== 1
139
- }
140
- }
141
-
142
- return utils.defineTemplateBodyVisitor(context, {
143
- VElement(node) {
144
- if (inIgnoreElement) {
145
- return
146
- }
147
- if (isIgnoredElement(node)) {
148
- // ignore element name
149
- inIgnoreElement = node
150
- return
151
- }
152
- if (node.startTag.selfClosing || !node.endTag) {
153
- // self closing
154
- return
155
- }
156
-
157
- const element = /** @type {VElement & { endTag: VEndTag }} */ (node)
158
-
159
- if (!isMultilineElement(element)) {
160
- return
161
- }
162
-
163
- /**
164
- * @type {SourceCode.CursorWithCountOptions}
165
- */
166
- const getTokenOption = {
167
- includeComments: true,
168
- filter: (token) => token.type !== 'HTMLWhitespace'
169
- }
170
- if (
171
- ignoreWhenEmpty &&
172
- element.children.length === 0 &&
173
- template.getFirstTokensBetween(
174
- element.startTag,
175
- element.endTag,
176
- getTokenOption
177
- ).length === 0
178
- ) {
179
- return
180
- }
181
-
182
- const contentFirst = /** @type {Token} */ (template.getTokenAfter(
183
- element.startTag,
184
- getTokenOption
185
- ))
186
- const contentLast = /** @type {Token} */ (template.getTokenBefore(
187
- element.endTag,
188
- getTokenOption
189
- ))
190
-
191
- const beforeLineBreaks =
192
- contentFirst.loc.start.line - element.startTag.loc.end.line
193
- const afterLineBreaks =
194
- element.endTag.loc.start.line - contentLast.loc.end.line
195
- if (isInvalidLineBreaks(beforeLineBreaks)) {
196
- context.report({
197
- node: template.getLastToken(element.startTag),
198
- loc: {
199
- start: element.startTag.loc.end,
200
- end: contentFirst.loc.start
201
- },
202
- messageId: 'unexpectedAfterClosingBracket',
203
- data: {
204
- name: element.rawName,
205
- actual: getPhrase(beforeLineBreaks)
206
- },
207
- fix(fixer) {
208
- /** @type {Range} */
209
- const range = [element.startTag.range[1], contentFirst.range[0]]
210
- return fixer.replaceTextRange(range, '\n')
211
- }
212
- })
213
- }
214
-
215
- if (isEmpty(element, sourceCode)) {
216
- return
217
- }
218
-
219
- if (isInvalidLineBreaks(afterLineBreaks)) {
220
- context.report({
221
- node: template.getFirstToken(element.endTag),
222
- loc: {
223
- start: contentLast.loc.end,
224
- end: element.endTag.loc.start
225
- },
226
- messageId: 'unexpectedBeforeOpeningBracket',
227
- data: {
228
- name: element.name,
229
- actual: getPhrase(afterLineBreaks)
230
- },
231
- fix(fixer) {
232
- /** @type {Range} */
233
- const range = [contentLast.range[1], element.endTag.range[0]]
234
- return fixer.replaceTextRange(range, '\n')
235
- }
236
- })
237
- }
238
- },
239
- 'VElement:exit'(node) {
240
- if (inIgnoreElement === node) {
241
- inIgnoreElement = null
242
- }
243
- }
244
- })
245
- }
246
- }
@@ -1,107 +0,0 @@
1
- /**
2
- * @fileoverview enforce unified spacing in mustache interpolations.
3
- * @author Armano
4
- */
5
- 'use strict'
6
-
7
- // ------------------------------------------------------------------------------
8
- // Requirements
9
- // ------------------------------------------------------------------------------
10
-
11
- const utils = require('../utils')
12
-
13
- // ------------------------------------------------------------------------------
14
- // Rule Definition
15
- // ------------------------------------------------------------------------------
16
-
17
- module.exports = {
18
- meta: {
19
- type: 'layout',
20
- docs: {
21
- description: 'enforce unified spacing in mustache interpolations',
22
- categories: ['vue3-strongly-recommended', 'strongly-recommended'],
23
- url: 'https://eslint.vuejs.org/rules/mustache-interpolation-spacing.html'
24
- },
25
- fixable: 'whitespace',
26
- schema: [
27
- {
28
- enum: ['always', 'never']
29
- }
30
- ]
31
- },
32
- /** @param {RuleContext} context */
33
- create(context) {
34
- const options = context.options[0] || 'always'
35
- const template =
36
- context.parserServices.getTemplateBodyTokenStore &&
37
- context.parserServices.getTemplateBodyTokenStore()
38
-
39
- // ----------------------------------------------------------------------
40
- // Public
41
- // ----------------------------------------------------------------------
42
-
43
- return utils.defineTemplateBodyVisitor(context, {
44
- /** @param {VExpressionContainer} node */
45
- 'VExpressionContainer[expression!=null]'(node) {
46
- const openBrace = template.getFirstToken(node)
47
- const closeBrace = template.getLastToken(node)
48
-
49
- if (
50
- !openBrace ||
51
- !closeBrace ||
52
- openBrace.type !== 'VExpressionStart' ||
53
- closeBrace.type !== 'VExpressionEnd'
54
- ) {
55
- return
56
- }
57
-
58
- const firstToken = template.getTokenAfter(openBrace, {
59
- includeComments: true
60
- })
61
- const lastToken = template.getTokenBefore(closeBrace, {
62
- includeComments: true
63
- })
64
-
65
- if (options === 'always') {
66
- if (openBrace.range[1] === firstToken.range[0]) {
67
- context.report({
68
- node: openBrace,
69
- message: "Expected 1 space after '{{', but not found.",
70
- fix: (fixer) => fixer.insertTextAfter(openBrace, ' ')
71
- })
72
- }
73
- if (closeBrace.range[0] === lastToken.range[1]) {
74
- context.report({
75
- node: closeBrace,
76
- message: "Expected 1 space before '}}', but not found.",
77
- fix: (fixer) => fixer.insertTextBefore(closeBrace, ' ')
78
- })
79
- }
80
- } else {
81
- if (openBrace.range[1] !== firstToken.range[0]) {
82
- context.report({
83
- loc: {
84
- start: openBrace.loc.start,
85
- end: firstToken.loc.start
86
- },
87
- message: "Expected no space after '{{', but found.",
88
- fix: (fixer) =>
89
- fixer.removeRange([openBrace.range[1], firstToken.range[0]])
90
- })
91
- }
92
- if (closeBrace.range[0] !== lastToken.range[1]) {
93
- context.report({
94
- loc: {
95
- start: lastToken.loc.end,
96
- end: closeBrace.loc.end
97
- },
98
- message: "Expected no space before '}}', but found.",
99
- fix: (fixer) =>
100
- fixer.removeRange([lastToken.range[1], closeBrace.range[0]])
101
- })
102
- }
103
- }
104
- }
105
- })
106
- }
107
- }
@@ -1,71 +0,0 @@
1
- /**
2
- * @fileoverview Requires specific casing for the name property in Vue components
3
- * @author Armano
4
- */
5
- 'use strict'
6
-
7
- const utils = require('../utils')
8
- const casing = require('../utils/casing')
9
- const allowedCaseOptions = ['PascalCase', 'kebab-case']
10
-
11
- // ------------------------------------------------------------------------------
12
- // Rule Definition
13
- // ------------------------------------------------------------------------------
14
-
15
- module.exports = {
16
- meta: {
17
- type: 'suggestion',
18
- docs: {
19
- description:
20
- 'enforce specific casing for the name property in Vue components',
21
- categories: ['vue3-strongly-recommended', 'strongly-recommended'],
22
- url: 'https://eslint.vuejs.org/rules/name-property-casing.html',
23
- replacedBy: ['component-definition-name-casing']
24
- },
25
- deprecated: true,
26
- fixable: 'code', // or "code" or "whitespace"
27
- schema: [
28
- {
29
- enum: allowedCaseOptions
30
- }
31
- ]
32
- },
33
- /** @param {RuleContext} context */
34
- create(context) {
35
- const options = context.options[0]
36
- const caseType =
37
- allowedCaseOptions.indexOf(options) !== -1 ? options : 'PascalCase'
38
-
39
- // ----------------------------------------------------------------------
40
- // Public
41
- // ----------------------------------------------------------------------
42
-
43
- return utils.executeOnVue(context, (obj) => {
44
- const node = utils.findProperty(obj, 'name')
45
-
46
- if (!node) return
47
- const valueNode = node.value
48
- if (valueNode.type !== 'Literal') return
49
-
50
- if (!casing.getChecker(caseType)(`${valueNode.value}`)) {
51
- const value = casing.getExactConverter(caseType)(`${valueNode.value}`)
52
- context.report({
53
- node: valueNode,
54
- message: 'Property name "{{value}}" is not {{caseType}}.',
55
- data: {
56
- value: `${valueNode.value}`,
57
- caseType
58
- },
59
- fix: (fixer) =>
60
- fixer.replaceText(
61
- valueNode,
62
- context
63
- .getSourceCode()
64
- .getText(valueNode)
65
- .replace(`${valueNode.value}`, value)
66
- )
67
- })
68
- }
69
- })
70
- }
71
- }
@@ -1,275 +0,0 @@
1
- /**
2
- * @author Yosuke Ota
3
- * See LICENSE file in root directory for full license.
4
- */
5
- 'use strict'
6
-
7
- // ------------------------------------------------------------------------------
8
- // Requirements
9
- // ------------------------------------------------------------------------------
10
-
11
- const utils = require('../utils')
12
- const regexp = require('../utils/regexp')
13
- const casing = require('../utils/casing')
14
-
15
- /**
16
- * @typedef { { names: { [tagName in string]: Set<string> }, regexps: { name: RegExp, attrs: Set<string> }[], cache: { [tagName in string]: Set<string> } } } TargetAttrs
17
- */
18
-
19
- // ------------------------------------------------------------------------------
20
- // Constants
21
- // ------------------------------------------------------------------------------
22
-
23
- // https://dev.w3.org/html5/html-author/charref
24
- const DEFAULT_ALLOWLIST = [
25
- '(',
26
- ')',
27
- ',',
28
- '.',
29
- '&',
30
- '+',
31
- '-',
32
- '=',
33
- '*',
34
- '/',
35
- '#',
36
- '%',
37
- '!',
38
- '?',
39
- ':',
40
- '[',
41
- ']',
42
- '{',
43
- '}',
44
- '<',
45
- '>',
46
- '\u00b7', // "·"
47
- '\u2022', // "•"
48
- '\u2010', // "‐"
49
- '\u2013', // "–"
50
- '\u2014', // "—"
51
- '\u2212', // "−"
52
- '|'
53
- ]
54
-
55
- const DEFAULT_ATTRIBUTES = {
56
- '/.+/': [
57
- 'title',
58
- 'aria-label',
59
- 'aria-placeholder',
60
- 'aria-roledescription',
61
- 'aria-valuetext'
62
- ],
63
- input: ['placeholder'],
64
- img: ['alt']
65
- }
66
-
67
- const DEFAULT_DIRECTIVES = ['v-text']
68
-
69
- // --------------------------------------------------------------------------
70
- // Helpers
71
- // --------------------------------------------------------------------------
72
-
73
- /**
74
- * Parse attributes option
75
- * @param {any} options
76
- * @returns {TargetAttrs}
77
- */
78
- function parseTargetAttrs(options) {
79
- /** @type {TargetAttrs} */
80
- const result = { names: {}, regexps: [], cache: {} }
81
- for (const tagName of Object.keys(options)) {
82
- /** @type { Set<string> } */
83
- const attrs = new Set(options[tagName])
84
- if (regexp.isRegExp(tagName)) {
85
- result.regexps.push({
86
- name: regexp.toRegExp(tagName),
87
- attrs
88
- })
89
- } else {
90
- result.names[tagName] = attrs
91
- }
92
- }
93
- return result
94
- }
95
-
96
- /**
97
- * Get a string from given expression container node
98
- * @param {VExpressionContainer} value
99
- * @returns { string | null }
100
- */
101
- function getStringValue(value) {
102
- const expression = value.expression
103
- if (!expression) {
104
- return null
105
- }
106
- if (expression.type !== 'Literal') {
107
- return null
108
- }
109
- if (typeof expression.value === 'string') {
110
- return expression.value
111
- }
112
- return null
113
- }
114
-
115
- // ------------------------------------------------------------------------------
116
- // Rule Definition
117
- // ------------------------------------------------------------------------------
118
-
119
- module.exports = {
120
- meta: {
121
- type: 'suggestion',
122
- docs: {
123
- description: 'disallow the use of bare strings in `<template>`',
124
- categories: undefined,
125
- url: 'https://eslint.vuejs.org/rules/no-bare-strings-in-template.html'
126
- },
127
- schema: [
128
- {
129
- type: 'object',
130
- properties: {
131
- allowlist: {
132
- type: 'array',
133
- items: { type: 'string' },
134
- uniqueItems: true
135
- },
136
- attributes: {
137
- type: 'object',
138
- patternProperties: {
139
- '^(?:\\S+|/.*/[a-z]*)$': {
140
- type: 'array',
141
- items: { type: 'string' },
142
- uniqueItems: true
143
- }
144
- },
145
- additionalProperties: false
146
- },
147
- directives: {
148
- type: 'array',
149
- items: { type: 'string', pattern: '^v-' },
150
- uniqueItems: true
151
- }
152
- }
153
- }
154
- ],
155
- messages: {
156
- unexpected: 'Unexpected non-translated string used.',
157
- unexpectedInAttr: 'Unexpected non-translated string used in `{{attr}}`.'
158
- }
159
- },
160
- /** @param {RuleContext} context */
161
- create(context) {
162
- /**
163
- * @typedef { { upper: ElementStack | null, name: string, attrs: Set<string> } } ElementStack
164
- */
165
- const opts = context.options[0] || {}
166
- /** @type {string[]} */
167
- const allowlist = opts.allowlist || DEFAULT_ALLOWLIST
168
- const attributes = parseTargetAttrs(opts.attributes || DEFAULT_ATTRIBUTES)
169
- const directives = opts.directives || DEFAULT_DIRECTIVES
170
-
171
- const allowlistRe = new RegExp(
172
- allowlist.map((w) => regexp.escape(w)).join('|'),
173
- 'gu'
174
- )
175
-
176
- /** @type {ElementStack | null} */
177
- let elementStack = null
178
- /**
179
- * Gets the bare string from given string
180
- * @param {string} str
181
- */
182
- function getBareString(str) {
183
- return str.trim().replace(allowlistRe, '').trim()
184
- }
185
-
186
- /**
187
- * Get the attribute to be verified from the element name.
188
- * @param {string} tagName
189
- * @returns {Set<string>}
190
- */
191
- function getTargetAttrs(tagName) {
192
- if (attributes.cache[tagName]) {
193
- return attributes.cache[tagName]
194
- }
195
- /** @type {string[]} */
196
- const result = []
197
- if (attributes.names[tagName]) {
198
- result.push(...attributes.names[tagName])
199
- }
200
- for (const { name, attrs } of attributes.regexps) {
201
- name.lastIndex = 0
202
- if (name.test(tagName)) {
203
- result.push(...attrs)
204
- }
205
- }
206
- if (casing.isKebabCase(tagName)) {
207
- result.push(...getTargetAttrs(casing.pascalCase(tagName)))
208
- }
209
-
210
- return (attributes.cache[tagName] = new Set(result))
211
- }
212
-
213
- return utils.defineTemplateBodyVisitor(context, {
214
- /** @param {VText} node */
215
- VText(node) {
216
- if (getBareString(node.value)) {
217
- context.report({
218
- node,
219
- messageId: 'unexpected'
220
- })
221
- }
222
- },
223
- /**
224
- * @param {VElement} node
225
- */
226
- VElement(node) {
227
- elementStack = {
228
- upper: elementStack,
229
- name: node.rawName,
230
- attrs: getTargetAttrs(node.rawName)
231
- }
232
- },
233
- 'VElement:exit'() {
234
- elementStack = elementStack && elementStack.upper
235
- },
236
- /** @param {VAttribute|VDirective} node */
237
- VAttribute(node) {
238
- if (!node.value || !elementStack) {
239
- return
240
- }
241
- if (node.directive === false) {
242
- const attrs = elementStack.attrs
243
- if (!attrs.has(node.key.rawName)) {
244
- return
245
- }
246
-
247
- if (getBareString(node.value.value)) {
248
- context.report({
249
- node: node.value,
250
- messageId: 'unexpectedInAttr',
251
- data: {
252
- attr: node.key.rawName
253
- }
254
- })
255
- }
256
- } else {
257
- const directive = `v-${node.key.name.name}`
258
- if (!directives.includes(directive)) {
259
- return
260
- }
261
- const str = getStringValue(node.value)
262
- if (str && getBareString(str)) {
263
- context.report({
264
- node: node.value,
265
- messageId: 'unexpectedInAttr',
266
- data: {
267
- attr: directive
268
- }
269
- })
270
- }
271
- }
272
- }
273
- })
274
- }
275
- }