first commit
This commit is contained in:
21
app_vue/node_modules/eslint-plugin-vue/LICENSE
generated
vendored
Normal file
21
app_vue/node_modules/eslint-plugin-vue/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Toru Nagashima
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
49
app_vue/node_modules/eslint-plugin-vue/README.md
generated
vendored
Normal file
49
app_vue/node_modules/eslint-plugin-vue/README.md
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
# eslint-plugin-vue
|
||||
|
||||
[](https://npmjs.org/package/eslint-plugin-vue)
|
||||
[](https://npmjs.org/package/eslint-plugin-vue)
|
||||
[](https://circleci.com/gh/vuejs/eslint-plugin-vue)
|
||||
[](https://github.com/vuejs/eslint-plugin-vue/blob/master/LICENSE)
|
||||
|
||||
> Official ESLint plugin for Vue.js
|
||||
|
||||
## :book: Documentation
|
||||
|
||||
Please refer to the [official website](https://eslint.vuejs.org).
|
||||
|
||||
## :anchor: Versioning Policy
|
||||
|
||||
This plugin follows [Semantic Versioning](https://semver.org) and [ESLint's Semantic Versioning Policy](https://github.com/eslint/eslint#semantic-versioning-policy).
|
||||
|
||||
## :newspaper: Releases
|
||||
|
||||
This project uses [GitHub Releases](https://github.com/vuejs/eslint-plugin-vue/releases).
|
||||
|
||||
## :beers: Contribution Guide
|
||||
|
||||
Contributing is welcome! See the [ESLint Vue Plugin Developer Guide](https://eslint.vuejs.org/developer-guide).
|
||||
|
||||
### Working With Rules
|
||||
|
||||
Be sure to read the [official ESLint guide](https://eslint.org/docs/developer-guide/working-with-rules) before you start writing a new rule.
|
||||
|
||||
To see what an abstract syntax tree (AST) of your code looks like, you may use [AST Explorer](https://astexplorer.net). After opening [AST Explorer](https://astexplorer.net), select `Vue` as the syntax and `vue-eslint-parser` as the parser.
|
||||
|
||||
The default JavaScript parser must be replaced because [Vue.js single file components](https://vuejs.org/guide/scaling-up/sfc.html) are not plain JavaScript, but a custom file format. [`vue-eslint-parser`](https://github.com/vuejs/vue-eslint-parser) is a replacement parser that generates an enhanced AST with nodes that represent specific parts of the template syntax, as well as the contents of the `<script>` tag.
|
||||
|
||||
To learn more about certain nodes in a produced AST, see the [ESTree project page](https://github.com/estree/estree) and the [vue-eslint-parser AST documentation](https://github.com/vuejs/vue-eslint-parser/blob/master/docs/ast.md).
|
||||
|
||||
`vue-eslint-parser` provides a few useful parser services to help traverse the produced AST and access template tokens:
|
||||
|
||||
- `context.parserServices.defineTemplateBodyVisitor(visitor, scriptVisitor)`
|
||||
- `context.parserServices.getTemplateBodyTokenStore()`
|
||||
|
||||
Check out an [example rule](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/mustache-interpolation-spacing.js) to see usage of these services.
|
||||
|
||||
Be aware that depending on the code samples you write in tests, the `RuleTester` parser property must be set accordingly (this can be done on a test by test basis). See an [example here](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/attribute-hyphenation.js#L19).
|
||||
|
||||
If you're stuck, remember there are many rules available for reference. If you can't find the right solution, don't hesitate to reach out in [issues](https://github.com/vuejs/eslint-plugin-vue/issues) – we're happy to help!
|
||||
|
||||
## :lock: License
|
||||
|
||||
See the [LICENSE](LICENSE) file for license rights and limitations (MIT).
|
22
app_vue/node_modules/eslint-plugin-vue/lib/configs/base.js
generated
vendored
Normal file
22
app_vue/node_modules/eslint-plugin-vue/lib/configs/base.js
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* IMPORTANT!
|
||||
* This file has been automatically generated,
|
||||
* in order to update its content execute "npm run update"
|
||||
*/
|
||||
module.exports = {
|
||||
parser: require.resolve('vue-eslint-parser'),
|
||||
parserOptions: {
|
||||
ecmaVersion: 2020,
|
||||
sourceType: 'module'
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true
|
||||
},
|
||||
plugins: ['vue'],
|
||||
rules: {
|
||||
'vue/comment-directive': 'error',
|
||||
'vue/jsx-uses-vars': 'error',
|
||||
'vue/script-setup-uses-vars': 'error'
|
||||
}
|
||||
}
|
62
app_vue/node_modules/eslint-plugin-vue/lib/configs/essential.js
generated
vendored
Normal file
62
app_vue/node_modules/eslint-plugin-vue/lib/configs/essential.js
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* IMPORTANT!
|
||||
* This file has been automatically generated,
|
||||
* in order to update its content execute "npm run update"
|
||||
*/
|
||||
module.exports = {
|
||||
extends: require.resolve('./base'),
|
||||
rules: {
|
||||
'vue/multi-word-component-names': 'error',
|
||||
'vue/no-arrow-functions-in-watch': 'error',
|
||||
'vue/no-async-in-computed-properties': 'error',
|
||||
'vue/no-computed-properties-in-data': 'error',
|
||||
'vue/no-custom-modifiers-on-v-model': 'error',
|
||||
'vue/no-dupe-keys': 'error',
|
||||
'vue/no-dupe-v-else-if': 'error',
|
||||
'vue/no-duplicate-attributes': 'error',
|
||||
'vue/no-multiple-template-root': 'error',
|
||||
'vue/no-mutating-props': 'error',
|
||||
'vue/no-parsing-error': 'error',
|
||||
'vue/no-reserved-keys': 'error',
|
||||
'vue/no-reserved-props': [
|
||||
'error',
|
||||
{
|
||||
vueVersion: 2
|
||||
}
|
||||
],
|
||||
'vue/no-shared-component-data': 'error',
|
||||
'vue/no-side-effects-in-computed-properties': 'error',
|
||||
'vue/no-template-key': 'error',
|
||||
'vue/no-textarea-mustache': 'error',
|
||||
'vue/no-unused-components': 'error',
|
||||
'vue/no-unused-vars': 'error',
|
||||
'vue/no-use-v-if-with-v-for': 'error',
|
||||
'vue/no-useless-template-attributes': 'error',
|
||||
'vue/no-v-for-template-key': 'error',
|
||||
'vue/no-v-model-argument': 'error',
|
||||
'vue/require-component-is': 'error',
|
||||
'vue/require-prop-type-constructor': 'error',
|
||||
'vue/require-render-return': 'error',
|
||||
'vue/require-v-for-key': 'error',
|
||||
'vue/require-valid-default-prop': 'error',
|
||||
'vue/return-in-computed-property': 'error',
|
||||
'vue/use-v-on-exact': 'error',
|
||||
'vue/valid-next-tick': 'error',
|
||||
'vue/valid-template-root': 'error',
|
||||
'vue/valid-v-bind-sync': 'error',
|
||||
'vue/valid-v-bind': 'error',
|
||||
'vue/valid-v-cloak': 'error',
|
||||
'vue/valid-v-else-if': 'error',
|
||||
'vue/valid-v-else': 'error',
|
||||
'vue/valid-v-for': 'error',
|
||||
'vue/valid-v-html': 'error',
|
||||
'vue/valid-v-if': 'error',
|
||||
'vue/valid-v-model': 'error',
|
||||
'vue/valid-v-on': 'error',
|
||||
'vue/valid-v-once': 'error',
|
||||
'vue/valid-v-pre': 'error',
|
||||
'vue/valid-v-show': 'error',
|
||||
'vue/valid-v-slot': 'error',
|
||||
'vue/valid-v-text': 'error'
|
||||
}
|
||||
}
|
52
app_vue/node_modules/eslint-plugin-vue/lib/configs/no-layout-rules.js
generated
vendored
Normal file
52
app_vue/node_modules/eslint-plugin-vue/lib/configs/no-layout-rules.js
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* IMPORTANT!
|
||||
* This file has been automatically generated,
|
||||
* in order to update its content execute "npm run update"
|
||||
*/
|
||||
module.exports = {
|
||||
rules: {
|
||||
'vue/array-bracket-newline': 'off',
|
||||
'vue/array-bracket-spacing': 'off',
|
||||
'vue/arrow-spacing': 'off',
|
||||
'vue/block-spacing': 'off',
|
||||
'vue/block-tag-newline': 'off',
|
||||
'vue/brace-style': 'off',
|
||||
'vue/comma-dangle': 'off',
|
||||
'vue/comma-spacing': 'off',
|
||||
'vue/comma-style': 'off',
|
||||
'vue/define-macros-order': 'off',
|
||||
'vue/dot-location': 'off',
|
||||
'vue/first-attribute-linebreak': 'off',
|
||||
'vue/func-call-spacing': 'off',
|
||||
'vue/html-closing-bracket-newline': 'off',
|
||||
'vue/html-closing-bracket-spacing': 'off',
|
||||
'vue/html-comment-content-newline': 'off',
|
||||
'vue/html-comment-content-spacing': 'off',
|
||||
'vue/html-comment-indent': 'off',
|
||||
'vue/html-indent': 'off',
|
||||
'vue/html-quotes': 'off',
|
||||
'vue/html-self-closing': 'off',
|
||||
'vue/key-spacing': 'off',
|
||||
'vue/keyword-spacing': 'off',
|
||||
'vue/max-attributes-per-line': 'off',
|
||||
'vue/max-len': 'off',
|
||||
'vue/multiline-html-element-content-newline': 'off',
|
||||
'vue/mustache-interpolation-spacing': 'off',
|
||||
'vue/new-line-between-multi-line-property': 'off',
|
||||
'vue/no-extra-parens': 'off',
|
||||
'vue/no-multi-spaces': 'off',
|
||||
'vue/no-spaces-around-equal-signs-in-attribute': 'off',
|
||||
'vue/object-curly-newline': 'off',
|
||||
'vue/object-curly-spacing': 'off',
|
||||
'vue/object-property-newline': 'off',
|
||||
'vue/operator-linebreak': 'off',
|
||||
'vue/padding-line-between-blocks': 'off',
|
||||
'vue/script-indent': 'off',
|
||||
'vue/singleline-html-element-content-newline': 'off',
|
||||
'vue/space-in-parens': 'off',
|
||||
'vue/space-infix-ops': 'off',
|
||||
'vue/space-unary-ops': 'off',
|
||||
'vue/template-curly-spacing': 'off',
|
||||
'vue/v-for-delimiter-style': 'off'
|
||||
}
|
||||
}
|
17
app_vue/node_modules/eslint-plugin-vue/lib/configs/recommended.js
generated
vendored
Normal file
17
app_vue/node_modules/eslint-plugin-vue/lib/configs/recommended.js
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* IMPORTANT!
|
||||
* This file has been automatically generated,
|
||||
* in order to update its content execute "npm run update"
|
||||
*/
|
||||
module.exports = {
|
||||
extends: require.resolve('./strongly-recommended'),
|
||||
rules: {
|
||||
'vue/attributes-order': 'warn',
|
||||
'vue/component-tags-order': 'warn',
|
||||
'vue/no-lone-template': 'warn',
|
||||
'vue/no-multiple-slot-args': 'warn',
|
||||
'vue/no-v-html': 'warn',
|
||||
'vue/order-in-components': 'warn',
|
||||
'vue/this-in-template': 'warn'
|
||||
}
|
||||
}
|
33
app_vue/node_modules/eslint-plugin-vue/lib/configs/strongly-recommended.js
generated
vendored
Normal file
33
app_vue/node_modules/eslint-plugin-vue/lib/configs/strongly-recommended.js
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* IMPORTANT!
|
||||
* This file has been automatically generated,
|
||||
* in order to update its content execute "npm run update"
|
||||
*/
|
||||
module.exports = {
|
||||
extends: require.resolve('./essential'),
|
||||
rules: {
|
||||
'vue/attribute-hyphenation': 'warn',
|
||||
'vue/component-definition-name-casing': 'warn',
|
||||
'vue/first-attribute-linebreak': 'warn',
|
||||
'vue/html-closing-bracket-newline': 'warn',
|
||||
'vue/html-closing-bracket-spacing': 'warn',
|
||||
'vue/html-end-tags': 'warn',
|
||||
'vue/html-indent': 'warn',
|
||||
'vue/html-quotes': 'warn',
|
||||
'vue/html-self-closing': 'warn',
|
||||
'vue/max-attributes-per-line': 'warn',
|
||||
'vue/multiline-html-element-content-newline': 'warn',
|
||||
'vue/mustache-interpolation-spacing': 'warn',
|
||||
'vue/no-multi-spaces': 'warn',
|
||||
'vue/no-spaces-around-equal-signs-in-attribute': 'warn',
|
||||
'vue/no-template-shadow': 'warn',
|
||||
'vue/one-component-per-file': 'warn',
|
||||
'vue/prop-name-casing': 'warn',
|
||||
'vue/require-default-prop': 'warn',
|
||||
'vue/require-prop-types': 'warn',
|
||||
'vue/singleline-html-element-content-newline': 'warn',
|
||||
'vue/v-bind-style': 'warn',
|
||||
'vue/v-on-style': 'warn',
|
||||
'vue/v-slot-style': 'warn'
|
||||
}
|
||||
}
|
84
app_vue/node_modules/eslint-plugin-vue/lib/configs/vue3-essential.js
generated
vendored
Normal file
84
app_vue/node_modules/eslint-plugin-vue/lib/configs/vue3-essential.js
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* IMPORTANT!
|
||||
* This file has been automatically generated,
|
||||
* in order to update its content execute "npm run update"
|
||||
*/
|
||||
module.exports = {
|
||||
extends: require.resolve('./base'),
|
||||
rules: {
|
||||
'vue/multi-word-component-names': 'error',
|
||||
'vue/no-arrow-functions-in-watch': 'error',
|
||||
'vue/no-async-in-computed-properties': 'error',
|
||||
'vue/no-computed-properties-in-data': 'error',
|
||||
'vue/no-deprecated-data-object-declaration': 'error',
|
||||
'vue/no-deprecated-destroyed-lifecycle': 'error',
|
||||
'vue/no-deprecated-dollar-listeners-api': 'error',
|
||||
'vue/no-deprecated-dollar-scopedslots-api': 'error',
|
||||
'vue/no-deprecated-events-api': 'error',
|
||||
'vue/no-deprecated-filter': 'error',
|
||||
'vue/no-deprecated-functional-template': 'error',
|
||||
'vue/no-deprecated-html-element-is': 'error',
|
||||
'vue/no-deprecated-inline-template': 'error',
|
||||
'vue/no-deprecated-props-default-this': 'error',
|
||||
'vue/no-deprecated-router-link-tag-prop': 'error',
|
||||
'vue/no-deprecated-scope-attribute': 'error',
|
||||
'vue/no-deprecated-slot-attribute': 'error',
|
||||
'vue/no-deprecated-slot-scope-attribute': 'error',
|
||||
'vue/no-deprecated-v-bind-sync': 'error',
|
||||
'vue/no-deprecated-v-is': 'error',
|
||||
'vue/no-deprecated-v-on-native-modifier': 'error',
|
||||
'vue/no-deprecated-v-on-number-modifiers': 'error',
|
||||
'vue/no-deprecated-vue-config-keycodes': 'error',
|
||||
'vue/no-dupe-keys': 'error',
|
||||
'vue/no-dupe-v-else-if': 'error',
|
||||
'vue/no-duplicate-attributes': 'error',
|
||||
'vue/no-export-in-script-setup': 'error',
|
||||
'vue/no-lifecycle-after-await': 'error',
|
||||
'vue/no-mutating-props': 'error',
|
||||
'vue/no-parsing-error': 'error',
|
||||
'vue/no-ref-as-operand': 'error',
|
||||
'vue/no-reserved-keys': 'error',
|
||||
'vue/no-reserved-props': 'error',
|
||||
'vue/no-setup-props-destructure': 'error',
|
||||
'vue/no-shared-component-data': 'error',
|
||||
'vue/no-side-effects-in-computed-properties': 'error',
|
||||
'vue/no-template-key': 'error',
|
||||
'vue/no-textarea-mustache': 'error',
|
||||
'vue/no-unused-components': 'error',
|
||||
'vue/no-unused-vars': 'error',
|
||||
'vue/no-use-v-if-with-v-for': 'error',
|
||||
'vue/no-useless-template-attributes': 'error',
|
||||
'vue/no-v-for-template-key-on-child': 'error',
|
||||
'vue/no-watch-after-await': 'error',
|
||||
'vue/require-component-is': 'error',
|
||||
'vue/require-prop-type-constructor': 'error',
|
||||
'vue/require-render-return': 'error',
|
||||
'vue/require-slots-as-functions': 'error',
|
||||
'vue/require-toggle-inside-transition': 'error',
|
||||
'vue/require-v-for-key': 'error',
|
||||
'vue/require-valid-default-prop': 'error',
|
||||
'vue/return-in-computed-property': 'error',
|
||||
'vue/return-in-emits-validator': 'error',
|
||||
'vue/use-v-on-exact': 'error',
|
||||
'vue/valid-define-emits': 'error',
|
||||
'vue/valid-define-props': 'error',
|
||||
'vue/valid-next-tick': 'error',
|
||||
'vue/valid-template-root': 'error',
|
||||
'vue/valid-v-bind': 'error',
|
||||
'vue/valid-v-cloak': 'error',
|
||||
'vue/valid-v-else-if': 'error',
|
||||
'vue/valid-v-else': 'error',
|
||||
'vue/valid-v-for': 'error',
|
||||
'vue/valid-v-html': 'error',
|
||||
'vue/valid-v-if': 'error',
|
||||
'vue/valid-v-is': 'error',
|
||||
'vue/valid-v-memo': 'error',
|
||||
'vue/valid-v-model': 'error',
|
||||
'vue/valid-v-on': 'error',
|
||||
'vue/valid-v-once': 'error',
|
||||
'vue/valid-v-pre': 'error',
|
||||
'vue/valid-v-show': 'error',
|
||||
'vue/valid-v-slot': 'error',
|
||||
'vue/valid-v-text': 'error'
|
||||
}
|
||||
}
|
17
app_vue/node_modules/eslint-plugin-vue/lib/configs/vue3-recommended.js
generated
vendored
Normal file
17
app_vue/node_modules/eslint-plugin-vue/lib/configs/vue3-recommended.js
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* IMPORTANT!
|
||||
* This file has been automatically generated,
|
||||
* in order to update its content execute "npm run update"
|
||||
*/
|
||||
module.exports = {
|
||||
extends: require.resolve('./vue3-strongly-recommended'),
|
||||
rules: {
|
||||
'vue/attributes-order': 'warn',
|
||||
'vue/component-tags-order': 'warn',
|
||||
'vue/no-lone-template': 'warn',
|
||||
'vue/no-multiple-slot-args': 'warn',
|
||||
'vue/no-v-html': 'warn',
|
||||
'vue/order-in-components': 'warn',
|
||||
'vue/this-in-template': 'warn'
|
||||
}
|
||||
}
|
35
app_vue/node_modules/eslint-plugin-vue/lib/configs/vue3-strongly-recommended.js
generated
vendored
Normal file
35
app_vue/node_modules/eslint-plugin-vue/lib/configs/vue3-strongly-recommended.js
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* IMPORTANT!
|
||||
* This file has been automatically generated,
|
||||
* in order to update its content execute "npm run update"
|
||||
*/
|
||||
module.exports = {
|
||||
extends: require.resolve('./vue3-essential'),
|
||||
rules: {
|
||||
'vue/attribute-hyphenation': 'warn',
|
||||
'vue/component-definition-name-casing': 'warn',
|
||||
'vue/first-attribute-linebreak': 'warn',
|
||||
'vue/html-closing-bracket-newline': 'warn',
|
||||
'vue/html-closing-bracket-spacing': 'warn',
|
||||
'vue/html-end-tags': 'warn',
|
||||
'vue/html-indent': 'warn',
|
||||
'vue/html-quotes': 'warn',
|
||||
'vue/html-self-closing': 'warn',
|
||||
'vue/max-attributes-per-line': 'warn',
|
||||
'vue/multiline-html-element-content-newline': 'warn',
|
||||
'vue/mustache-interpolation-spacing': 'warn',
|
||||
'vue/no-multi-spaces': 'warn',
|
||||
'vue/no-spaces-around-equal-signs-in-attribute': 'warn',
|
||||
'vue/no-template-shadow': 'warn',
|
||||
'vue/one-component-per-file': 'warn',
|
||||
'vue/prop-name-casing': 'warn',
|
||||
'vue/require-default-prop': 'warn',
|
||||
'vue/require-explicit-emits': 'warn',
|
||||
'vue/require-prop-types': 'warn',
|
||||
'vue/singleline-html-element-content-newline': 'warn',
|
||||
'vue/v-bind-style': 'warn',
|
||||
'vue/v-on-event-hyphenation': 'warn',
|
||||
'vue/v-on-style': 'warn',
|
||||
'vue/v-slot-style': 'warn'
|
||||
}
|
||||
}
|
248
app_vue/node_modules/eslint-plugin-vue/lib/index.js
generated
vendored
Normal file
248
app_vue/node_modules/eslint-plugin-vue/lib/index.js
generated
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* IMPORTANT!
|
||||
* This file has been automatically generated,
|
||||
* in order to update its content execute "npm run update"
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
rules: {
|
||||
'array-bracket-newline': require('./rules/array-bracket-newline'),
|
||||
'array-bracket-spacing': require('./rules/array-bracket-spacing'),
|
||||
'arrow-spacing': require('./rules/arrow-spacing'),
|
||||
'attribute-hyphenation': require('./rules/attribute-hyphenation'),
|
||||
'attributes-order': require('./rules/attributes-order'),
|
||||
'block-lang': require('./rules/block-lang'),
|
||||
'block-spacing': require('./rules/block-spacing'),
|
||||
'block-tag-newline': require('./rules/block-tag-newline'),
|
||||
'brace-style': require('./rules/brace-style'),
|
||||
camelcase: require('./rules/camelcase'),
|
||||
'comma-dangle': require('./rules/comma-dangle'),
|
||||
'comma-spacing': require('./rules/comma-spacing'),
|
||||
'comma-style': require('./rules/comma-style'),
|
||||
'comment-directive': require('./rules/comment-directive'),
|
||||
'component-api-style': require('./rules/component-api-style'),
|
||||
'component-definition-name-casing': require('./rules/component-definition-name-casing'),
|
||||
'component-name-in-template-casing': require('./rules/component-name-in-template-casing'),
|
||||
'component-options-name-casing': require('./rules/component-options-name-casing'),
|
||||
'component-tags-order': require('./rules/component-tags-order'),
|
||||
'custom-event-name-casing': require('./rules/custom-event-name-casing'),
|
||||
'define-macros-order': require('./rules/define-macros-order'),
|
||||
'dot-location': require('./rules/dot-location'),
|
||||
'dot-notation': require('./rules/dot-notation'),
|
||||
eqeqeq: require('./rules/eqeqeq'),
|
||||
'experimental-script-setup-vars': require('./rules/experimental-script-setup-vars'),
|
||||
'first-attribute-linebreak': require('./rules/first-attribute-linebreak'),
|
||||
'func-call-spacing': require('./rules/func-call-spacing'),
|
||||
'html-button-has-type': require('./rules/html-button-has-type'),
|
||||
'html-closing-bracket-newline': require('./rules/html-closing-bracket-newline'),
|
||||
'html-closing-bracket-spacing': require('./rules/html-closing-bracket-spacing'),
|
||||
'html-comment-content-newline': require('./rules/html-comment-content-newline'),
|
||||
'html-comment-content-spacing': require('./rules/html-comment-content-spacing'),
|
||||
'html-comment-indent': require('./rules/html-comment-indent'),
|
||||
'html-end-tags': require('./rules/html-end-tags'),
|
||||
'html-indent': require('./rules/html-indent'),
|
||||
'html-quotes': require('./rules/html-quotes'),
|
||||
'html-self-closing': require('./rules/html-self-closing'),
|
||||
'jsx-uses-vars': require('./rules/jsx-uses-vars'),
|
||||
'key-spacing': require('./rules/key-spacing'),
|
||||
'keyword-spacing': require('./rules/keyword-spacing'),
|
||||
'match-component-file-name': require('./rules/match-component-file-name'),
|
||||
'match-component-import-name': require('./rules/match-component-import-name'),
|
||||
'max-attributes-per-line': require('./rules/max-attributes-per-line'),
|
||||
'max-len': require('./rules/max-len'),
|
||||
'multi-word-component-names': require('./rules/multi-word-component-names'),
|
||||
'multiline-html-element-content-newline': require('./rules/multiline-html-element-content-newline'),
|
||||
'mustache-interpolation-spacing': require('./rules/mustache-interpolation-spacing'),
|
||||
'name-property-casing': require('./rules/name-property-casing'),
|
||||
'new-line-between-multi-line-property': require('./rules/new-line-between-multi-line-property'),
|
||||
'next-tick-style': require('./rules/next-tick-style'),
|
||||
'no-arrow-functions-in-watch': require('./rules/no-arrow-functions-in-watch'),
|
||||
'no-async-in-computed-properties': require('./rules/no-async-in-computed-properties'),
|
||||
'no-bare-strings-in-template': require('./rules/no-bare-strings-in-template'),
|
||||
'no-boolean-default': require('./rules/no-boolean-default'),
|
||||
'no-child-content': require('./rules/no-child-content'),
|
||||
'no-computed-properties-in-data': require('./rules/no-computed-properties-in-data'),
|
||||
'no-confusing-v-for-v-if': require('./rules/no-confusing-v-for-v-if'),
|
||||
'no-constant-condition': require('./rules/no-constant-condition'),
|
||||
'no-custom-modifiers-on-v-model': require('./rules/no-custom-modifiers-on-v-model'),
|
||||
'no-deprecated-data-object-declaration': require('./rules/no-deprecated-data-object-declaration'),
|
||||
'no-deprecated-destroyed-lifecycle': require('./rules/no-deprecated-destroyed-lifecycle'),
|
||||
'no-deprecated-dollar-listeners-api': require('./rules/no-deprecated-dollar-listeners-api'),
|
||||
'no-deprecated-dollar-scopedslots-api': require('./rules/no-deprecated-dollar-scopedslots-api'),
|
||||
'no-deprecated-events-api': require('./rules/no-deprecated-events-api'),
|
||||
'no-deprecated-filter': require('./rules/no-deprecated-filter'),
|
||||
'no-deprecated-functional-template': require('./rules/no-deprecated-functional-template'),
|
||||
'no-deprecated-html-element-is': require('./rules/no-deprecated-html-element-is'),
|
||||
'no-deprecated-inline-template': require('./rules/no-deprecated-inline-template'),
|
||||
'no-deprecated-props-default-this': require('./rules/no-deprecated-props-default-this'),
|
||||
'no-deprecated-router-link-tag-prop': require('./rules/no-deprecated-router-link-tag-prop'),
|
||||
'no-deprecated-scope-attribute': require('./rules/no-deprecated-scope-attribute'),
|
||||
'no-deprecated-slot-attribute': require('./rules/no-deprecated-slot-attribute'),
|
||||
'no-deprecated-slot-scope-attribute': require('./rules/no-deprecated-slot-scope-attribute'),
|
||||
'no-deprecated-v-bind-sync': require('./rules/no-deprecated-v-bind-sync'),
|
||||
'no-deprecated-v-is': require('./rules/no-deprecated-v-is'),
|
||||
'no-deprecated-v-on-native-modifier': require('./rules/no-deprecated-v-on-native-modifier'),
|
||||
'no-deprecated-v-on-number-modifiers': require('./rules/no-deprecated-v-on-number-modifiers'),
|
||||
'no-deprecated-vue-config-keycodes': require('./rules/no-deprecated-vue-config-keycodes'),
|
||||
'no-dupe-keys': require('./rules/no-dupe-keys'),
|
||||
'no-dupe-v-else-if': require('./rules/no-dupe-v-else-if'),
|
||||
'no-duplicate-attr-inheritance': require('./rules/no-duplicate-attr-inheritance'),
|
||||
'no-duplicate-attributes': require('./rules/no-duplicate-attributes'),
|
||||
'no-empty-component-block': require('./rules/no-empty-component-block'),
|
||||
'no-empty-pattern': require('./rules/no-empty-pattern'),
|
||||
'no-export-in-script-setup': require('./rules/no-export-in-script-setup'),
|
||||
'no-expose-after-await': require('./rules/no-expose-after-await'),
|
||||
'no-extra-parens': require('./rules/no-extra-parens'),
|
||||
'no-invalid-model-keys': require('./rules/no-invalid-model-keys'),
|
||||
'no-irregular-whitespace': require('./rules/no-irregular-whitespace'),
|
||||
'no-lifecycle-after-await': require('./rules/no-lifecycle-after-await'),
|
||||
'no-lone-template': require('./rules/no-lone-template'),
|
||||
'no-loss-of-precision': require('./rules/no-loss-of-precision'),
|
||||
'no-multi-spaces': require('./rules/no-multi-spaces'),
|
||||
'no-multiple-objects-in-class': require('./rules/no-multiple-objects-in-class'),
|
||||
'no-multiple-slot-args': require('./rules/no-multiple-slot-args'),
|
||||
'no-multiple-template-root': require('./rules/no-multiple-template-root'),
|
||||
'no-mutating-props': require('./rules/no-mutating-props'),
|
||||
'no-parsing-error': require('./rules/no-parsing-error'),
|
||||
'no-potential-component-option-typo': require('./rules/no-potential-component-option-typo'),
|
||||
'no-ref-as-operand': require('./rules/no-ref-as-operand'),
|
||||
'no-reserved-component-names': require('./rules/no-reserved-component-names'),
|
||||
'no-reserved-keys': require('./rules/no-reserved-keys'),
|
||||
'no-reserved-props': require('./rules/no-reserved-props'),
|
||||
'no-restricted-block': require('./rules/no-restricted-block'),
|
||||
'no-restricted-call-after-await': require('./rules/no-restricted-call-after-await'),
|
||||
'no-restricted-class': require('./rules/no-restricted-class'),
|
||||
'no-restricted-component-options': require('./rules/no-restricted-component-options'),
|
||||
'no-restricted-custom-event': require('./rules/no-restricted-custom-event'),
|
||||
'no-restricted-html-elements': require('./rules/no-restricted-html-elements'),
|
||||
'no-restricted-props': require('./rules/no-restricted-props'),
|
||||
'no-restricted-static-attribute': require('./rules/no-restricted-static-attribute'),
|
||||
'no-restricted-syntax': require('./rules/no-restricted-syntax'),
|
||||
'no-restricted-v-bind': require('./rules/no-restricted-v-bind'),
|
||||
'no-setup-props-destructure': require('./rules/no-setup-props-destructure'),
|
||||
'no-shared-component-data': require('./rules/no-shared-component-data'),
|
||||
'no-side-effects-in-computed-properties': require('./rules/no-side-effects-in-computed-properties'),
|
||||
'no-spaces-around-equal-signs-in-attribute': require('./rules/no-spaces-around-equal-signs-in-attribute'),
|
||||
'no-sparse-arrays': require('./rules/no-sparse-arrays'),
|
||||
'no-static-inline-styles': require('./rules/no-static-inline-styles'),
|
||||
'no-template-key': require('./rules/no-template-key'),
|
||||
'no-template-shadow': require('./rules/no-template-shadow'),
|
||||
'no-template-target-blank': require('./rules/no-template-target-blank'),
|
||||
'no-textarea-mustache': require('./rules/no-textarea-mustache'),
|
||||
'no-this-in-before-route-enter': require('./rules/no-this-in-before-route-enter'),
|
||||
'no-undef-components': require('./rules/no-undef-components'),
|
||||
'no-undef-properties': require('./rules/no-undef-properties'),
|
||||
'no-unregistered-components': require('./rules/no-unregistered-components'),
|
||||
'no-unsupported-features': require('./rules/no-unsupported-features'),
|
||||
'no-unused-components': require('./rules/no-unused-components'),
|
||||
'no-unused-properties': require('./rules/no-unused-properties'),
|
||||
'no-unused-refs': require('./rules/no-unused-refs'),
|
||||
'no-unused-vars': require('./rules/no-unused-vars'),
|
||||
'no-use-computed-property-like-method': require('./rules/no-use-computed-property-like-method'),
|
||||
'no-use-v-if-with-v-for': require('./rules/no-use-v-if-with-v-for'),
|
||||
'no-useless-concat': require('./rules/no-useless-concat'),
|
||||
'no-useless-mustaches': require('./rules/no-useless-mustaches'),
|
||||
'no-useless-template-attributes': require('./rules/no-useless-template-attributes'),
|
||||
'no-useless-v-bind': require('./rules/no-useless-v-bind'),
|
||||
'no-v-for-template-key-on-child': require('./rules/no-v-for-template-key-on-child'),
|
||||
'no-v-for-template-key': require('./rules/no-v-for-template-key'),
|
||||
'no-v-html': require('./rules/no-v-html'),
|
||||
'no-v-model-argument': require('./rules/no-v-model-argument'),
|
||||
'no-v-text-v-html-on-component': require('./rules/no-v-text-v-html-on-component'),
|
||||
'no-v-text': require('./rules/no-v-text'),
|
||||
'no-watch-after-await': require('./rules/no-watch-after-await'),
|
||||
'object-curly-newline': require('./rules/object-curly-newline'),
|
||||
'object-curly-spacing': require('./rules/object-curly-spacing'),
|
||||
'object-property-newline': require('./rules/object-property-newline'),
|
||||
'object-shorthand': require('./rules/object-shorthand'),
|
||||
'one-component-per-file': require('./rules/one-component-per-file'),
|
||||
'operator-linebreak': require('./rules/operator-linebreak'),
|
||||
'order-in-components': require('./rules/order-in-components'),
|
||||
'padding-line-between-blocks': require('./rules/padding-line-between-blocks'),
|
||||
'prefer-import-from-vue': require('./rules/prefer-import-from-vue'),
|
||||
'prefer-prop-type-boolean-first': require('./rules/prefer-prop-type-boolean-first'),
|
||||
'prefer-separate-static-class': require('./rules/prefer-separate-static-class'),
|
||||
'prefer-template': require('./rules/prefer-template'),
|
||||
'prefer-true-attribute-shorthand': require('./rules/prefer-true-attribute-shorthand'),
|
||||
'prop-name-casing': require('./rules/prop-name-casing'),
|
||||
'quote-props': require('./rules/quote-props'),
|
||||
'require-component-is': require('./rules/require-component-is'),
|
||||
'require-default-prop': require('./rules/require-default-prop'),
|
||||
'require-direct-export': require('./rules/require-direct-export'),
|
||||
'require-emit-validator': require('./rules/require-emit-validator'),
|
||||
'require-explicit-emits': require('./rules/require-explicit-emits'),
|
||||
'require-expose': require('./rules/require-expose'),
|
||||
'require-name-property': require('./rules/require-name-property'),
|
||||
'require-prop-type-constructor': require('./rules/require-prop-type-constructor'),
|
||||
'require-prop-types': require('./rules/require-prop-types'),
|
||||
'require-render-return': require('./rules/require-render-return'),
|
||||
'require-slots-as-functions': require('./rules/require-slots-as-functions'),
|
||||
'require-toggle-inside-transition': require('./rules/require-toggle-inside-transition'),
|
||||
'require-v-for-key': require('./rules/require-v-for-key'),
|
||||
'require-valid-default-prop': require('./rules/require-valid-default-prop'),
|
||||
'return-in-computed-property': require('./rules/return-in-computed-property'),
|
||||
'return-in-emits-validator': require('./rules/return-in-emits-validator'),
|
||||
'script-indent': require('./rules/script-indent'),
|
||||
'script-setup-uses-vars': require('./rules/script-setup-uses-vars'),
|
||||
'singleline-html-element-content-newline': require('./rules/singleline-html-element-content-newline'),
|
||||
'sort-keys': require('./rules/sort-keys'),
|
||||
'space-in-parens': require('./rules/space-in-parens'),
|
||||
'space-infix-ops': require('./rules/space-infix-ops'),
|
||||
'space-unary-ops': require('./rules/space-unary-ops'),
|
||||
'static-class-names-order': require('./rules/static-class-names-order'),
|
||||
'template-curly-spacing': require('./rules/template-curly-spacing'),
|
||||
'this-in-template': require('./rules/this-in-template'),
|
||||
'use-v-on-exact': require('./rules/use-v-on-exact'),
|
||||
'v-bind-style': require('./rules/v-bind-style'),
|
||||
'v-for-delimiter-style': require('./rules/v-for-delimiter-style'),
|
||||
'v-on-event-hyphenation': require('./rules/v-on-event-hyphenation'),
|
||||
'v-on-function-call': require('./rules/v-on-function-call'),
|
||||
'v-on-style': require('./rules/v-on-style'),
|
||||
'v-slot-style': require('./rules/v-slot-style'),
|
||||
'valid-define-emits': require('./rules/valid-define-emits'),
|
||||
'valid-define-props': require('./rules/valid-define-props'),
|
||||
'valid-next-tick': require('./rules/valid-next-tick'),
|
||||
'valid-template-root': require('./rules/valid-template-root'),
|
||||
'valid-v-bind-sync': require('./rules/valid-v-bind-sync'),
|
||||
'valid-v-bind': require('./rules/valid-v-bind'),
|
||||
'valid-v-cloak': require('./rules/valid-v-cloak'),
|
||||
'valid-v-else-if': require('./rules/valid-v-else-if'),
|
||||
'valid-v-else': require('./rules/valid-v-else'),
|
||||
'valid-v-for': require('./rules/valid-v-for'),
|
||||
'valid-v-html': require('./rules/valid-v-html'),
|
||||
'valid-v-if': require('./rules/valid-v-if'),
|
||||
'valid-v-is': require('./rules/valid-v-is'),
|
||||
'valid-v-memo': require('./rules/valid-v-memo'),
|
||||
'valid-v-model': require('./rules/valid-v-model'),
|
||||
'valid-v-on': require('./rules/valid-v-on'),
|
||||
'valid-v-once': require('./rules/valid-v-once'),
|
||||
'valid-v-pre': require('./rules/valid-v-pre'),
|
||||
'valid-v-show': require('./rules/valid-v-show'),
|
||||
'valid-v-slot': require('./rules/valid-v-slot'),
|
||||
'valid-v-text': require('./rules/valid-v-text')
|
||||
},
|
||||
configs: {
|
||||
base: require('./configs/base'),
|
||||
essential: require('./configs/essential'),
|
||||
'no-layout-rules': require('./configs/no-layout-rules'),
|
||||
recommended: require('./configs/recommended'),
|
||||
'strongly-recommended': require('./configs/strongly-recommended'),
|
||||
'vue3-essential': require('./configs/vue3-essential'),
|
||||
'vue3-recommended': require('./configs/vue3-recommended'),
|
||||
'vue3-strongly-recommended': require('./configs/vue3-strongly-recommended')
|
||||
},
|
||||
processors: {
|
||||
'.vue': require('./processor')
|
||||
},
|
||||
environments: {
|
||||
'setup-compiler-macros': {
|
||||
globals: {
|
||||
defineProps: 'readonly',
|
||||
defineEmits: 'readonly',
|
||||
defineExpose: 'readonly',
|
||||
withDefaults: 'readonly'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
165
app_vue/node_modules/eslint-plugin-vue/lib/processor.js
generated
vendored
Normal file
165
app_vue/node_modules/eslint-plugin-vue/lib/processor.js
generated
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
/**
|
||||
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* @typedef {import('eslint').Linter.LintMessage} LintMessage
|
||||
*/
|
||||
/**
|
||||
* @typedef {object} GroupState
|
||||
* @property {Set<string>} GroupState.disableAllKeys
|
||||
* @property {Map<string, string[]>} GroupState.disableRuleKeys
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
/** @param {string} code */
|
||||
preprocess(code) {
|
||||
return [code]
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {LintMessage[][]} messages
|
||||
* @returns {LintMessage[]}
|
||||
*/
|
||||
postprocess(messages) {
|
||||
const state = {
|
||||
/** @type {GroupState} */
|
||||
block: {
|
||||
disableAllKeys: new Set(),
|
||||
disableRuleKeys: new Map()
|
||||
},
|
||||
/** @type {GroupState} */
|
||||
line: {
|
||||
disableAllKeys: new Set(),
|
||||
disableRuleKeys: new Map()
|
||||
}
|
||||
}
|
||||
/** @type {string[]} */
|
||||
const usedDisableDirectiveKeys = []
|
||||
/** @type {Map<string,LintMessage>} */
|
||||
const unusedDisableDirectiveReports = new Map()
|
||||
|
||||
// Filter messages which are in disabled area.
|
||||
const filteredMessages = messages[0].filter((message) => {
|
||||
if (message.ruleId === 'vue/comment-directive') {
|
||||
const directiveType = message.messageId
|
||||
const data = message.message.split(' ')
|
||||
switch (directiveType) {
|
||||
case 'disableBlock':
|
||||
state.block.disableAllKeys.add(data[1])
|
||||
break
|
||||
case 'disableLine':
|
||||
state.line.disableAllKeys.add(data[1])
|
||||
break
|
||||
case 'enableBlock':
|
||||
state.block.disableAllKeys.clear()
|
||||
break
|
||||
case 'enableLine':
|
||||
state.line.disableAllKeys.clear()
|
||||
break
|
||||
case 'disableBlockRule':
|
||||
addDisableRule(state.block.disableRuleKeys, data[1], data[2])
|
||||
break
|
||||
case 'disableLineRule':
|
||||
addDisableRule(state.line.disableRuleKeys, data[1], data[2])
|
||||
break
|
||||
case 'enableBlockRule':
|
||||
state.block.disableRuleKeys.delete(data[1])
|
||||
break
|
||||
case 'enableLineRule':
|
||||
state.line.disableRuleKeys.delete(data[1])
|
||||
break
|
||||
case 'clear':
|
||||
state.block.disableAllKeys.clear()
|
||||
state.block.disableRuleKeys.clear()
|
||||
state.line.disableAllKeys.clear()
|
||||
state.line.disableRuleKeys.clear()
|
||||
break
|
||||
default:
|
||||
// unused eslint-disable comments report
|
||||
unusedDisableDirectiveReports.set(messageToKey(message), message)
|
||||
break
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
const disableDirectiveKeys = []
|
||||
if (state.block.disableAllKeys.size) {
|
||||
disableDirectiveKeys.push(...state.block.disableAllKeys)
|
||||
}
|
||||
if (state.line.disableAllKeys.size) {
|
||||
disableDirectiveKeys.push(...state.line.disableAllKeys)
|
||||
}
|
||||
if (message.ruleId) {
|
||||
const block = state.block.disableRuleKeys.get(message.ruleId)
|
||||
if (block) {
|
||||
disableDirectiveKeys.push(...block)
|
||||
}
|
||||
const line = state.line.disableRuleKeys.get(message.ruleId)
|
||||
if (line) {
|
||||
disableDirectiveKeys.push(...line)
|
||||
}
|
||||
}
|
||||
|
||||
if (disableDirectiveKeys.length) {
|
||||
// Store used eslint-disable comment key
|
||||
usedDisableDirectiveKeys.push(...disableDirectiveKeys)
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (unusedDisableDirectiveReports.size) {
|
||||
for (const key of usedDisableDirectiveKeys) {
|
||||
// Remove used eslint-disable comments
|
||||
unusedDisableDirectiveReports.delete(key)
|
||||
}
|
||||
// Reports unused eslint-disable comments
|
||||
filteredMessages.push(...unusedDisableDirectiveReports.values())
|
||||
filteredMessages.sort(compareLocations)
|
||||
}
|
||||
|
||||
return filteredMessages
|
||||
},
|
||||
|
||||
supportsAutofix: true
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Map<string, string[]>} disableRuleKeys
|
||||
* @param {string} rule
|
||||
* @param {string} key
|
||||
*/
|
||||
function addDisableRule(disableRuleKeys, rule, key) {
|
||||
let keys = disableRuleKeys.get(rule)
|
||||
if (keys) {
|
||||
keys.push(key)
|
||||
} else {
|
||||
keys = [key]
|
||||
disableRuleKeys.set(rule, keys)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {LintMessage} message
|
||||
* @returns {string} message key
|
||||
*/
|
||||
function messageToKey(message) {
|
||||
return `line:${message.line},column${
|
||||
// -1 because +1 by ESLint's `report-translator`.
|
||||
message.column - 1
|
||||
}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the locations of two objects in a source file
|
||||
* @param {Position} itemA The first object
|
||||
* @param {Position} itemB The second object
|
||||
* @returns {number} A value less than 1 if itemA appears before itemB in the source file, greater than 1 if
|
||||
* itemA appears after itemB in the source file, or 0 if itemA and itemB have the same location.
|
||||
*/
|
||||
function compareLocations(itemA, itemB) {
|
||||
return itemA.line - itemB.line || itemA.column - itemB.column
|
||||
}
|
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/array-bracket-newline.js
generated
vendored
Normal file
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/array-bracket-newline.js
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('array-bracket-newline', {
|
||||
skipDynamicArguments: true
|
||||
})
|
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/array-bracket-spacing.js
generated
vendored
Normal file
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/array-bracket-spacing.js
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('array-bracket-spacing', {
|
||||
skipDynamicArguments: true
|
||||
})
|
9
app_vue/node_modules/eslint-plugin-vue/lib/rules/arrow-spacing.js
generated
vendored
Normal file
9
app_vue/node_modules/eslint-plugin-vue/lib/rules/arrow-spacing.js
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('arrow-spacing')
|
128
app_vue/node_modules/eslint-plugin-vue/lib/rules/attribute-hyphenation.js
generated
vendored
Normal file
128
app_vue/node_modules/eslint-plugin-vue/lib/rules/attribute-hyphenation.js
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
/**
|
||||
* @fileoverview Define a style for the props casing in templates.
|
||||
* @author Armano
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
const casing = require('../utils/casing')
|
||||
const svgAttributes = require('../utils/svg-attributes-weird-case.json')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description:
|
||||
'enforce attribute naming style on custom components in template',
|
||||
categories: ['vue3-strongly-recommended', 'strongly-recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/attribute-hyphenation.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [
|
||||
{
|
||||
enum: ['always', 'never']
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
ignore: {
|
||||
type: 'array',
|
||||
items: {
|
||||
allOf: [
|
||||
{ type: 'string' },
|
||||
{ not: { type: 'string', pattern: ':exit$' } },
|
||||
{ not: { type: 'string', pattern: '^\\s*$' } }
|
||||
]
|
||||
},
|
||||
uniqueItems: true,
|
||||
additionalItems: false
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const sourceCode = context.getSourceCode()
|
||||
const option = context.options[0]
|
||||
const optionsPayload = context.options[1]
|
||||
const useHyphenated = option !== 'never'
|
||||
let ignoredAttributes = ['data-', 'aria-', 'slot-scope'].concat(
|
||||
svgAttributes
|
||||
)
|
||||
|
||||
if (optionsPayload && optionsPayload.ignore) {
|
||||
ignoredAttributes = ignoredAttributes.concat(optionsPayload.ignore)
|
||||
}
|
||||
|
||||
const caseConverter = casing.getExactConverter(
|
||||
useHyphenated ? 'kebab-case' : 'camelCase'
|
||||
)
|
||||
|
||||
/**
|
||||
* @param {VDirective | VAttribute} node
|
||||
* @param {string} name
|
||||
*/
|
||||
function reportIssue(node, name) {
|
||||
const text = sourceCode.getText(node.key)
|
||||
|
||||
context.report({
|
||||
node: node.key,
|
||||
loc: node.loc,
|
||||
message: useHyphenated
|
||||
? "Attribute '{{text}}' must be hyphenated."
|
||||
: "Attribute '{{text}}' can't be hyphenated.",
|
||||
data: {
|
||||
text
|
||||
},
|
||||
fix: (fixer) =>
|
||||
fixer.replaceText(node.key, text.replace(name, caseConverter(name)))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
*/
|
||||
function isIgnoredAttribute(value) {
|
||||
const isIgnored = ignoredAttributes.some((attr) => {
|
||||
return value.includes(attr)
|
||||
})
|
||||
|
||||
if (isIgnored) {
|
||||
return true
|
||||
}
|
||||
|
||||
return useHyphenated ? value.toLowerCase() === value : !/-/.test(value)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
VAttribute(node) {
|
||||
if (
|
||||
!utils.isCustomComponent(node.parent.parent) &&
|
||||
node.parent.parent.name !== 'slot'
|
||||
)
|
||||
return
|
||||
|
||||
const name = !node.directive
|
||||
? node.key.rawName
|
||||
: node.key.name.name === 'bind'
|
||||
? node.key.argument &&
|
||||
node.key.argument.type === 'VIdentifier' &&
|
||||
node.key.argument.rawName
|
||||
: /* otherwise */ false
|
||||
if (!name || isIgnoredAttribute(name)) return
|
||||
|
||||
reportIssue(node, name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
399
app_vue/node_modules/eslint-plugin-vue/lib/rules/attributes-order.js
generated
vendored
Normal file
399
app_vue/node_modules/eslint-plugin-vue/lib/rules/attributes-order.js
generated
vendored
Normal file
@ -0,0 +1,399 @@
|
||||
/**
|
||||
* @fileoverview enforce ordering of attributes
|
||||
* @author Erin Depew
|
||||
*/
|
||||
'use strict'
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @typedef { VDirective & { key: VDirectiveKey & { name: VIdentifier & { name: 'bind' } } } } VBindDirective
|
||||
*/
|
||||
|
||||
const ATTRS = {
|
||||
DEFINITION: 'DEFINITION',
|
||||
LIST_RENDERING: 'LIST_RENDERING',
|
||||
CONDITIONALS: 'CONDITIONALS',
|
||||
RENDER_MODIFIERS: 'RENDER_MODIFIERS',
|
||||
GLOBAL: 'GLOBAL',
|
||||
UNIQUE: 'UNIQUE',
|
||||
SLOT: 'SLOT',
|
||||
TWO_WAY_BINDING: 'TWO_WAY_BINDING',
|
||||
OTHER_DIRECTIVES: 'OTHER_DIRECTIVES',
|
||||
OTHER_ATTR: 'OTHER_ATTR',
|
||||
EVENTS: 'EVENTS',
|
||||
CONTENT: 'CONTENT'
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given attribute is `v-bind` directive.
|
||||
* @param {VAttribute | VDirective | undefined | null} node
|
||||
* @returns { node is VBindDirective }
|
||||
*/
|
||||
function isVBind(node) {
|
||||
return Boolean(node && node.directive && node.key.name.name === 'bind')
|
||||
}
|
||||
/**
|
||||
* Check whether the given attribute is `v-model` directive.
|
||||
* @param {VAttribute | VDirective | undefined | null} node
|
||||
* @returns { node is VDirective }
|
||||
*/
|
||||
function isVModel(node) {
|
||||
return Boolean(node && node.directive && node.key.name.name === 'model')
|
||||
}
|
||||
/**
|
||||
* Check whether the given attribute is plain attribute.
|
||||
* @param {VAttribute | VDirective | undefined | null} node
|
||||
* @returns { node is VAttribute }
|
||||
*/
|
||||
function isVAttribute(node) {
|
||||
return Boolean(node && !node.directive)
|
||||
}
|
||||
/**
|
||||
* Check whether the given attribute is plain attribute, `v-bind` directive or `v-model` directive.
|
||||
* @param {VAttribute | VDirective | undefined | null} node
|
||||
* @returns { node is VAttribute }
|
||||
*/
|
||||
function isVAttributeOrVBindOrVModel(node) {
|
||||
return isVAttribute(node) || isVBind(node) || isVModel(node)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given attribute is `v-bind="..."` directive.
|
||||
* @param {VAttribute | VDirective | undefined | null} node
|
||||
* @returns { node is VBindDirective }
|
||||
*/
|
||||
function isVBindObject(node) {
|
||||
return isVBind(node) && node.key.argument == null
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VAttribute | VDirective} attribute
|
||||
* @param {SourceCode} sourceCode
|
||||
*/
|
||||
function getAttributeName(attribute, sourceCode) {
|
||||
if (attribute.directive) {
|
||||
if (isVBind(attribute)) {
|
||||
return attribute.key.argument
|
||||
? sourceCode.getText(attribute.key.argument)
|
||||
: ''
|
||||
} else {
|
||||
return getDirectiveKeyName(attribute.key, sourceCode)
|
||||
}
|
||||
} else {
|
||||
return attribute.key.name
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VDirectiveKey} directiveKey
|
||||
* @param {SourceCode} sourceCode
|
||||
*/
|
||||
function getDirectiveKeyName(directiveKey, sourceCode) {
|
||||
let text = `v-${directiveKey.name.name}`
|
||||
if (directiveKey.argument) {
|
||||
text += `:${sourceCode.getText(directiveKey.argument)}`
|
||||
}
|
||||
for (const modifier of directiveKey.modifiers) {
|
||||
text += `.${modifier.name}`
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VAttribute | VDirective} attribute
|
||||
*/
|
||||
function getAttributeType(attribute) {
|
||||
let propName
|
||||
if (attribute.directive) {
|
||||
if (!isVBind(attribute)) {
|
||||
const name = attribute.key.name.name
|
||||
if (name === 'for') {
|
||||
return ATTRS.LIST_RENDERING
|
||||
} else if (
|
||||
name === 'if' ||
|
||||
name === 'else-if' ||
|
||||
name === 'else' ||
|
||||
name === 'show' ||
|
||||
name === 'cloak'
|
||||
) {
|
||||
return ATTRS.CONDITIONALS
|
||||
} else if (name === 'pre' || name === 'once') {
|
||||
return ATTRS.RENDER_MODIFIERS
|
||||
} else if (name === 'model') {
|
||||
return ATTRS.TWO_WAY_BINDING
|
||||
} else if (name === 'on') {
|
||||
return ATTRS.EVENTS
|
||||
} else if (name === 'html' || name === 'text') {
|
||||
return ATTRS.CONTENT
|
||||
} else if (name === 'slot') {
|
||||
return ATTRS.SLOT
|
||||
} else if (name === 'is') {
|
||||
return ATTRS.DEFINITION
|
||||
} else {
|
||||
return ATTRS.OTHER_DIRECTIVES
|
||||
}
|
||||
}
|
||||
propName =
|
||||
attribute.key.argument && attribute.key.argument.type === 'VIdentifier'
|
||||
? attribute.key.argument.rawName
|
||||
: ''
|
||||
} else {
|
||||
propName = attribute.key.name
|
||||
}
|
||||
if (propName === 'is') {
|
||||
return ATTRS.DEFINITION
|
||||
} else if (propName === 'id') {
|
||||
return ATTRS.GLOBAL
|
||||
} else if (propName === 'ref' || propName === 'key') {
|
||||
return ATTRS.UNIQUE
|
||||
} else if (propName === 'slot' || propName === 'slot-scope') {
|
||||
return ATTRS.SLOT
|
||||
} else {
|
||||
return ATTRS.OTHER_ATTR
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VAttribute | VDirective} attribute
|
||||
* @param { { [key: string]: number } } attributePosition
|
||||
* @returns {number | null} If the value is null, the order is omitted. Do not force the order.
|
||||
*/
|
||||
function getPosition(attribute, attributePosition) {
|
||||
const attributeType = getAttributeType(attribute)
|
||||
return attributePosition[attributeType] != null
|
||||
? attributePosition[attributeType]
|
||||
: null
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VAttribute | VDirective} prevNode
|
||||
* @param {VAttribute | VDirective} currNode
|
||||
* @param {SourceCode} sourceCode
|
||||
*/
|
||||
function isAlphabetical(prevNode, currNode, sourceCode) {
|
||||
const prevName = getAttributeName(prevNode, sourceCode)
|
||||
const currName = getAttributeName(currNode, sourceCode)
|
||||
if (prevName === currName) {
|
||||
const prevIsBind = isVBind(prevNode)
|
||||
const currIsBind = isVBind(currNode)
|
||||
return prevIsBind <= currIsBind
|
||||
}
|
||||
return prevName < currName
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {RuleContext} context - The rule context.
|
||||
* @returns {RuleListener} AST event handlers.
|
||||
*/
|
||||
function create(context) {
|
||||
const sourceCode = context.getSourceCode()
|
||||
let attributeOrder = [
|
||||
ATTRS.DEFINITION,
|
||||
ATTRS.LIST_RENDERING,
|
||||
ATTRS.CONDITIONALS,
|
||||
ATTRS.RENDER_MODIFIERS,
|
||||
ATTRS.GLOBAL,
|
||||
[ATTRS.UNIQUE, ATTRS.SLOT],
|
||||
ATTRS.TWO_WAY_BINDING,
|
||||
ATTRS.OTHER_DIRECTIVES,
|
||||
ATTRS.OTHER_ATTR,
|
||||
ATTRS.EVENTS,
|
||||
ATTRS.CONTENT
|
||||
]
|
||||
if (context.options[0] && context.options[0].order) {
|
||||
attributeOrder = context.options[0].order
|
||||
}
|
||||
const alphabetical = Boolean(
|
||||
context.options[0] && context.options[0].alphabetical
|
||||
)
|
||||
|
||||
/** @type { { [key: string]: number } } */
|
||||
const attributePosition = {}
|
||||
attributeOrder.forEach((item, i) => {
|
||||
if (Array.isArray(item)) {
|
||||
for (const attr of item) {
|
||||
attributePosition[attr] = i
|
||||
}
|
||||
} else attributePosition[item] = i
|
||||
})
|
||||
|
||||
/**
|
||||
* @param {VAttribute | VDirective} node
|
||||
* @param {VAttribute | VDirective} previousNode
|
||||
*/
|
||||
function reportIssue(node, previousNode) {
|
||||
const currentNode = sourceCode.getText(node.key)
|
||||
const prevNode = sourceCode.getText(previousNode.key)
|
||||
context.report({
|
||||
node,
|
||||
message: `Attribute "${currentNode}" should go before "${prevNode}".`,
|
||||
data: {
|
||||
currentNode
|
||||
},
|
||||
|
||||
fix(fixer) {
|
||||
const attributes = node.parent.attributes
|
||||
|
||||
/** @type { (node: VAttribute | VDirective | undefined) => boolean } */
|
||||
let isMoveUp
|
||||
|
||||
if (isVBindObject(node)) {
|
||||
// prev, v-bind:foo, v-bind -> v-bind:foo, v-bind, prev
|
||||
isMoveUp = isVAttributeOrVBindOrVModel
|
||||
} else if (isVAttributeOrVBindOrVModel(node)) {
|
||||
// prev, v-bind, v-bind:foo -> v-bind, v-bind:foo, prev
|
||||
isMoveUp = isVBindObject
|
||||
} else {
|
||||
isMoveUp = () => false
|
||||
}
|
||||
|
||||
const previousNodes = attributes.slice(
|
||||
attributes.indexOf(previousNode),
|
||||
attributes.indexOf(node)
|
||||
)
|
||||
const moveNodes = [node]
|
||||
for (const node of previousNodes) {
|
||||
if (isMoveUp(node)) {
|
||||
moveNodes.unshift(node)
|
||||
} else {
|
||||
moveNodes.push(node)
|
||||
}
|
||||
}
|
||||
|
||||
return moveNodes.map((moveNode, index) => {
|
||||
const text = sourceCode.getText(moveNode)
|
||||
return fixer.replaceText(previousNodes[index] || node, text)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
VStartTag(node) {
|
||||
const attributeAndPositions = getAttributeAndPositionList(node)
|
||||
if (attributeAndPositions.length <= 1) {
|
||||
return
|
||||
}
|
||||
|
||||
let { attr: previousNode, position: previousPosition } =
|
||||
attributeAndPositions[0]
|
||||
for (let index = 1; index < attributeAndPositions.length; index++) {
|
||||
const { attr, position } = attributeAndPositions[index]
|
||||
|
||||
let valid = previousPosition <= position
|
||||
if (valid && alphabetical && previousPosition === position) {
|
||||
valid = isAlphabetical(previousNode, attr, sourceCode)
|
||||
}
|
||||
if (valid) {
|
||||
previousNode = attr
|
||||
previousPosition = position
|
||||
} else {
|
||||
reportIssue(attr, previousNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* @param {VStartTag} node
|
||||
* @returns { { attr: ( VAttribute | VDirective ), position: number }[] }
|
||||
*/
|
||||
function getAttributeAndPositionList(node) {
|
||||
const attributes = node.attributes.filter((node, index, attributes) => {
|
||||
if (
|
||||
isVBindObject(node) &&
|
||||
(isVAttributeOrVBindOrVModel(attributes[index - 1]) ||
|
||||
isVAttributeOrVBindOrVModel(attributes[index + 1]))
|
||||
) {
|
||||
// In Vue 3, ignore `v-bind="object"`, which is
|
||||
// a pair of `v-bind:foo="..."` and `v-bind="object"` and
|
||||
// a pair of `v-model="..."` and `v-bind="object"`,
|
||||
// because changing the order behaves differently.
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
const results = []
|
||||
for (let index = 0; index < attributes.length; index++) {
|
||||
const attr = attributes[index]
|
||||
const position = getPositionFromAttrIndex(index)
|
||||
if (position == null) {
|
||||
// The omitted order is skipped.
|
||||
continue
|
||||
}
|
||||
results.push({ attr, position })
|
||||
}
|
||||
|
||||
return results
|
||||
|
||||
/**
|
||||
* @param {number} index
|
||||
* @returns {number | null}
|
||||
*/
|
||||
function getPositionFromAttrIndex(index) {
|
||||
const node = attributes[index]
|
||||
if (isVBindObject(node)) {
|
||||
// node is `v-bind ="object"` syntax
|
||||
|
||||
// In Vue 3, if change the order of `v-bind:foo="..."`, `v-model="..."` and `v-bind="object"`,
|
||||
// the behavior will be different, so adjust so that there is no change in behavior.
|
||||
|
||||
const len = attributes.length
|
||||
for (let nextIndex = index + 1; nextIndex < len; nextIndex++) {
|
||||
const next = attributes[nextIndex]
|
||||
|
||||
if (isVAttributeOrVBindOrVModel(next) && !isVBindObject(next)) {
|
||||
// It is considered to be in the same order as the next bind prop node.
|
||||
return getPositionFromAttrIndex(nextIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
return getPosition(node, attributePosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'enforce order of attributes',
|
||||
categories: ['vue3-recommended', 'recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/attributes-order.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
order: {
|
||||
type: 'array',
|
||||
items: {
|
||||
anyOf: [
|
||||
{ enum: Object.values(ATTRS) },
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
enum: Object.values(ATTRS),
|
||||
uniqueItems: true,
|
||||
additionalItems: false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
uniqueItems: true,
|
||||
additionalItems: false
|
||||
},
|
||||
alphabetical: { type: 'boolean' }
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
},
|
||||
create
|
||||
}
|
224
app_vue/node_modules/eslint-plugin-vue/lib/rules/block-lang.js
generated
vendored
Normal file
224
app_vue/node_modules/eslint-plugin-vue/lib/rules/block-lang.js
generated
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
/**
|
||||
* @fileoverview Disallow use other than available `lang`
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
const utils = require('../utils')
|
||||
|
||||
/**
|
||||
* @typedef {object} BlockOptions
|
||||
* @property {Set<string>} lang
|
||||
* @property {boolean} allowNoLang
|
||||
*/
|
||||
/**
|
||||
* @typedef { { [element: string]: BlockOptions | undefined } } Options
|
||||
*/
|
||||
/**
|
||||
* @typedef {object} UserBlockOptions
|
||||
* @property {string[] | string} [lang]
|
||||
* @property {boolean} [allowNoLang]
|
||||
*/
|
||||
/**
|
||||
* @typedef { { [element: string]: UserBlockOptions | undefined } } UserOptions
|
||||
*/
|
||||
|
||||
/**
|
||||
* https://vuejs.github.io/vetur/guide/highlighting.html
|
||||
* <template lang="html"></template>
|
||||
* <style lang="css"></style>
|
||||
* <script lang="js"></script>
|
||||
* <script lang="javascript"></script>
|
||||
* @type {Record<string, string[] | undefined>}
|
||||
*/
|
||||
const DEFAULT_LANGUAGES = {
|
||||
template: ['html'],
|
||||
style: ['css'],
|
||||
script: ['js', 'javascript']
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {NonNullable<BlockOptions['lang']>} lang
|
||||
*/
|
||||
function getAllowsLangPhrase(lang) {
|
||||
const langs = [...lang].map((s) => `"${s}"`)
|
||||
switch (langs.length) {
|
||||
case 1:
|
||||
return langs[0]
|
||||
default:
|
||||
return `${langs.slice(0, -1).join(', ')}, and ${langs[langs.length - 1]}`
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a given option.
|
||||
* @param {string} blockName The block name.
|
||||
* @param { UserBlockOptions } option An option to parse.
|
||||
* @returns {BlockOptions} Normalized option.
|
||||
*/
|
||||
function normalizeOption(blockName, option) {
|
||||
const lang = new Set(
|
||||
Array.isArray(option.lang) ? option.lang : option.lang ? [option.lang] : []
|
||||
)
|
||||
let hasDefault = false
|
||||
for (const def of DEFAULT_LANGUAGES[blockName] || []) {
|
||||
if (lang.has(def)) {
|
||||
lang.delete(def)
|
||||
hasDefault = true
|
||||
}
|
||||
}
|
||||
if (lang.size === 0) {
|
||||
return {
|
||||
lang,
|
||||
allowNoLang: true
|
||||
}
|
||||
}
|
||||
return {
|
||||
lang,
|
||||
allowNoLang: hasDefault || Boolean(option.allowNoLang)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Normalizes a given options.
|
||||
* @param { UserOptions } options An option to parse.
|
||||
* @returns {Options} Normalized option.
|
||||
*/
|
||||
function normalizeOptions(options) {
|
||||
if (!options) {
|
||||
return {}
|
||||
}
|
||||
|
||||
/** @type {Options} */
|
||||
const normalized = {}
|
||||
|
||||
for (const blockName of Object.keys(options)) {
|
||||
const value = options[blockName]
|
||||
if (value) {
|
||||
normalized[blockName] = normalizeOption(blockName, value)
|
||||
}
|
||||
}
|
||||
|
||||
return normalized
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'disallow use other than available `lang`',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/block-lang.html'
|
||||
},
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
patternProperties: {
|
||||
'^(?:\\S+)$': {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
lang: {
|
||||
anyOf: [
|
||||
{ type: 'string' },
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
},
|
||||
uniqueItems: true,
|
||||
additionalItems: false
|
||||
}
|
||||
]
|
||||
},
|
||||
allowNoLang: { type: 'boolean' }
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
minProperties: 1,
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
expected:
|
||||
"Only {{allows}} can be used for the 'lang' attribute of '<{{tag}}>'.",
|
||||
missing: "The 'lang' attribute of '<{{tag}}>' is missing.",
|
||||
unexpected: "Do not specify the 'lang' attribute of '<{{tag}}>'.",
|
||||
useOrNot:
|
||||
"Only {{allows}} can be used for the 'lang' attribute of '<{{tag}}>'. Or, not specifying the `lang` attribute is allowed.",
|
||||
unexpectedDefault:
|
||||
"Do not explicitly specify the default language for the 'lang' attribute of '<{{tag}}>'."
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const options = normalizeOptions(
|
||||
context.options[0] || {
|
||||
script: { allowNoLang: true },
|
||||
template: { allowNoLang: true },
|
||||
style: { allowNoLang: true }
|
||||
}
|
||||
)
|
||||
if (!Object.keys(options).length) {
|
||||
// empty
|
||||
return {}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VElement} element
|
||||
* @returns {void}
|
||||
*/
|
||||
function verify(element) {
|
||||
const tag = element.name
|
||||
const option = options[tag]
|
||||
if (!option) {
|
||||
return
|
||||
}
|
||||
const lang = utils.getAttribute(element, 'lang')
|
||||
if (lang == null || lang.value == null) {
|
||||
if (!option.allowNoLang) {
|
||||
context.report({
|
||||
node: element.startTag,
|
||||
messageId: 'missing',
|
||||
data: {
|
||||
tag
|
||||
}
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
if (!option.lang.has(lang.value.value)) {
|
||||
let messageId
|
||||
if (!option.allowNoLang) {
|
||||
messageId = 'expected'
|
||||
} else if (option.lang.size === 0) {
|
||||
if ((DEFAULT_LANGUAGES[tag] || []).includes(lang.value.value)) {
|
||||
messageId = 'unexpectedDefault'
|
||||
} else {
|
||||
messageId = 'unexpected'
|
||||
}
|
||||
} else {
|
||||
messageId = 'useOrNot'
|
||||
}
|
||||
context.report({
|
||||
node: lang,
|
||||
messageId,
|
||||
data: {
|
||||
tag,
|
||||
allows: getAllowsLangPhrase(option.lang)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return utils.defineDocumentVisitor(context, {
|
||||
'VDocumentFragment > VElement': verify
|
||||
})
|
||||
}
|
||||
}
|
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/block-spacing.js
generated
vendored
Normal file
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/block-spacing.js
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('block-spacing', {
|
||||
skipDynamicArguments: true
|
||||
})
|
375
app_vue/node_modules/eslint-plugin-vue/lib/rules/block-tag-newline.js
generated
vendored
Normal file
375
app_vue/node_modules/eslint-plugin-vue/lib/rules/block-tag-newline.js
generated
vendored
Normal file
@ -0,0 +1,375 @@
|
||||
/**
|
||||
* @fileoverview Enforce line breaks style after opening and before closing block-level tags.
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
const utils = require('../utils')
|
||||
|
||||
/**
|
||||
* @typedef { 'always' | 'never' | 'consistent' | 'ignore' } OptionType
|
||||
* @typedef { { singleline?: OptionType, multiline?: OptionType, maxEmptyLines?: number } } ContentsOptions
|
||||
* @typedef { ContentsOptions & { blocks?: { [element: string]: ContentsOptions } } } Options
|
||||
* @typedef { Required<ContentsOptions> } ArgsOptions
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} text Source code as a string.
|
||||
* @returns {number}
|
||||
*/
|
||||
function getLinebreakCount(text) {
|
||||
return text.split(/\r\n|[\r\n\u2028\u2029]/gu).length - 1
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} lineBreaks
|
||||
*/
|
||||
function getPhrase(lineBreaks) {
|
||||
switch (lineBreaks) {
|
||||
case 1:
|
||||
return '1 line break'
|
||||
default:
|
||||
return `${lineBreaks} line breaks`
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const ENUM_OPTIONS = { enum: ['always', 'never', 'consistent', 'ignore'] }
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
docs: {
|
||||
description:
|
||||
'enforce line breaks after opening and before closing block-level tags',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/block-tag-newline.html'
|
||||
},
|
||||
fixable: 'whitespace',
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
singleline: ENUM_OPTIONS,
|
||||
multiline: ENUM_OPTIONS,
|
||||
maxEmptyLines: { type: 'number', minimum: 0 },
|
||||
blocks: {
|
||||
type: 'object',
|
||||
patternProperties: {
|
||||
'^(?:\\S+)$': {
|
||||
type: 'object',
|
||||
properties: {
|
||||
singleline: ENUM_OPTIONS,
|
||||
multiline: ENUM_OPTIONS,
|
||||
maxEmptyLines: { type: 'number', minimum: 0 }
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
unexpectedOpeningLinebreak:
|
||||
"There should be no line break after '<{{tag}}>'.",
|
||||
unexpectedClosingLinebreak:
|
||||
"There should be no line break before '</{{tag}}>'.",
|
||||
expectedOpeningLinebreak:
|
||||
"Expected {{expected}} after '<{{tag}}>', but {{actual}} found.",
|
||||
expectedClosingLinebreak:
|
||||
"Expected {{expected}} before '</{{tag}}>', but {{actual}} found.",
|
||||
missingOpeningLinebreak: "A line break is required after '<{{tag}}>'.",
|
||||
missingClosingLinebreak: "A line break is required before '</{{tag}}>'."
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const df =
|
||||
context.parserServices.getDocumentFragment &&
|
||||
context.parserServices.getDocumentFragment()
|
||||
if (!df) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const sourceCode = context.getSourceCode()
|
||||
|
||||
/**
|
||||
* @param {VStartTag} startTag
|
||||
* @param {string} beforeText
|
||||
* @param {number} beforeLinebreakCount
|
||||
* @param {'always' | 'never'} beforeOption
|
||||
* @param {number} maxEmptyLines
|
||||
* @returns {void}
|
||||
*/
|
||||
function verifyBeforeSpaces(
|
||||
startTag,
|
||||
beforeText,
|
||||
beforeLinebreakCount,
|
||||
beforeOption,
|
||||
maxEmptyLines
|
||||
) {
|
||||
if (beforeOption === 'always') {
|
||||
if (beforeLinebreakCount === 0) {
|
||||
context.report({
|
||||
loc: {
|
||||
start: startTag.loc.end,
|
||||
end: startTag.loc.end
|
||||
},
|
||||
messageId: 'missingOpeningLinebreak',
|
||||
data: { tag: startTag.parent.name },
|
||||
fix(fixer) {
|
||||
return fixer.insertTextAfter(startTag, '\n')
|
||||
}
|
||||
})
|
||||
} else if (maxEmptyLines < beforeLinebreakCount - 1) {
|
||||
context.report({
|
||||
loc: {
|
||||
start: startTag.loc.end,
|
||||
end: sourceCode.getLocFromIndex(
|
||||
startTag.range[1] + beforeText.length
|
||||
)
|
||||
},
|
||||
messageId: 'expectedOpeningLinebreak',
|
||||
data: {
|
||||
tag: startTag.parent.name,
|
||||
expected: getPhrase(maxEmptyLines + 1),
|
||||
actual: getPhrase(beforeLinebreakCount)
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.replaceTextRange(
|
||||
[startTag.range[1], startTag.range[1] + beforeText.length],
|
||||
'\n'.repeat(maxEmptyLines + 1)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (beforeLinebreakCount > 0) {
|
||||
context.report({
|
||||
loc: {
|
||||
start: startTag.loc.end,
|
||||
end: sourceCode.getLocFromIndex(
|
||||
startTag.range[1] + beforeText.length
|
||||
)
|
||||
},
|
||||
messageId: 'unexpectedOpeningLinebreak',
|
||||
data: { tag: startTag.parent.name },
|
||||
fix(fixer) {
|
||||
return fixer.removeRange([
|
||||
startTag.range[1],
|
||||
startTag.range[1] + beforeText.length
|
||||
])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {VEndTag} endTag
|
||||
* @param {string} afterText
|
||||
* @param {number} afterLinebreakCount
|
||||
* @param {'always' | 'never'} afterOption
|
||||
* @param {number} maxEmptyLines
|
||||
* @returns {void}
|
||||
*/
|
||||
function verifyAfterSpaces(
|
||||
endTag,
|
||||
afterText,
|
||||
afterLinebreakCount,
|
||||
afterOption,
|
||||
maxEmptyLines
|
||||
) {
|
||||
if (afterOption === 'always') {
|
||||
if (afterLinebreakCount === 0) {
|
||||
context.report({
|
||||
loc: {
|
||||
start: endTag.loc.start,
|
||||
end: endTag.loc.start
|
||||
},
|
||||
messageId: 'missingClosingLinebreak',
|
||||
data: { tag: endTag.parent.name },
|
||||
fix(fixer) {
|
||||
return fixer.insertTextBefore(endTag, '\n')
|
||||
}
|
||||
})
|
||||
} else if (maxEmptyLines < afterLinebreakCount - 1) {
|
||||
context.report({
|
||||
loc: {
|
||||
start: sourceCode.getLocFromIndex(
|
||||
endTag.range[0] - afterText.length
|
||||
),
|
||||
end: endTag.loc.start
|
||||
},
|
||||
messageId: 'expectedClosingLinebreak',
|
||||
data: {
|
||||
tag: endTag.parent.name,
|
||||
expected: getPhrase(maxEmptyLines + 1),
|
||||
actual: getPhrase(afterLinebreakCount)
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.replaceTextRange(
|
||||
[endTag.range[0] - afterText.length, endTag.range[0]],
|
||||
'\n'.repeat(maxEmptyLines + 1)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (afterLinebreakCount > 0) {
|
||||
context.report({
|
||||
loc: {
|
||||
start: sourceCode.getLocFromIndex(
|
||||
endTag.range[0] - afterText.length
|
||||
),
|
||||
end: endTag.loc.start
|
||||
},
|
||||
messageId: 'unexpectedOpeningLinebreak',
|
||||
data: { tag: endTag.parent.name },
|
||||
fix(fixer) {
|
||||
return fixer.removeRange([
|
||||
endTag.range[0] - afterText.length,
|
||||
endTag.range[0]
|
||||
])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {VElement} element
|
||||
* @param {ArgsOptions} options
|
||||
* @returns {void}
|
||||
*/
|
||||
function verifyElement(element, options) {
|
||||
const { startTag, endTag } = element
|
||||
if (startTag.selfClosing || endTag == null) {
|
||||
return
|
||||
}
|
||||
const text = sourceCode.text.slice(startTag.range[1], endTag.range[0])
|
||||
|
||||
const trimText = text.trim()
|
||||
if (!trimText) {
|
||||
return
|
||||
}
|
||||
|
||||
const option =
|
||||
options.multiline === options.singleline
|
||||
? options.singleline
|
||||
: /[\n\r\u2028\u2029]/u.test(text.trim())
|
||||
? options.multiline
|
||||
: options.singleline
|
||||
if (option === 'ignore') {
|
||||
return
|
||||
}
|
||||
const beforeText = /** @type {RegExpExecArray} */ (/^\s*/u.exec(text))[0]
|
||||
const afterText = /** @type {RegExpExecArray} */ (/\s*$/u.exec(text))[0]
|
||||
const beforeLinebreakCount = getLinebreakCount(beforeText)
|
||||
const afterLinebreakCount = getLinebreakCount(afterText)
|
||||
|
||||
/** @type {'always' | 'never'} */
|
||||
let beforeOption
|
||||
/** @type {'always' | 'never'} */
|
||||
let afterOption
|
||||
if (option === 'always' || option === 'never') {
|
||||
beforeOption = option
|
||||
afterOption = option
|
||||
} else {
|
||||
// consistent
|
||||
if (beforeLinebreakCount > 0 === afterLinebreakCount > 0) {
|
||||
return
|
||||
}
|
||||
beforeOption = 'always'
|
||||
afterOption = 'always'
|
||||
}
|
||||
|
||||
verifyBeforeSpaces(
|
||||
startTag,
|
||||
beforeText,
|
||||
beforeLinebreakCount,
|
||||
beforeOption,
|
||||
options.maxEmptyLines
|
||||
)
|
||||
|
||||
verifyAfterSpaces(
|
||||
endTag,
|
||||
afterText,
|
||||
afterLinebreakCount,
|
||||
afterOption,
|
||||
options.maxEmptyLines
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a given option value.
|
||||
* @param { Options | undefined } option An option value to parse.
|
||||
* @returns { (element: VElement) => void } Verify function.
|
||||
*/
|
||||
function normalizeOptionValue(option) {
|
||||
if (!option) {
|
||||
return normalizeOptionValue({})
|
||||
}
|
||||
|
||||
/** @type {ContentsOptions} */
|
||||
const contentsOptions = option
|
||||
/** @type {ArgsOptions} */
|
||||
const options = {
|
||||
singleline: contentsOptions.singleline || 'consistent',
|
||||
multiline: contentsOptions.multiline || 'always',
|
||||
maxEmptyLines: contentsOptions.maxEmptyLines || 0
|
||||
}
|
||||
const { blocks } = option
|
||||
if (!blocks) {
|
||||
return (element) => verifyElement(element, options)
|
||||
}
|
||||
|
||||
return (element) => {
|
||||
const { name } = element
|
||||
const elementsOptions = blocks[name]
|
||||
if (!elementsOptions) {
|
||||
verifyElement(element, options)
|
||||
} else {
|
||||
normalizeOptionValue({
|
||||
singleline: elementsOptions.singleline || options.singleline,
|
||||
multiline: elementsOptions.multiline || options.multiline,
|
||||
maxEmptyLines:
|
||||
elementsOptions.maxEmptyLines != null
|
||||
? elementsOptions.maxEmptyLines
|
||||
: options.maxEmptyLines
|
||||
})(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const documentFragment = df
|
||||
|
||||
const verify = normalizeOptionValue(context.options[0])
|
||||
|
||||
/**
|
||||
* @returns {VElement[]}
|
||||
*/
|
||||
function getTopLevelHTMLElements() {
|
||||
return documentFragment.children.filter(utils.isVElement)
|
||||
}
|
||||
|
||||
return utils.defineTemplateBodyVisitor(
|
||||
context,
|
||||
{},
|
||||
{
|
||||
/** @param {Program} node */
|
||||
Program(node) {
|
||||
if (utils.hasInvalidEOF(node)) {
|
||||
return
|
||||
}
|
||||
|
||||
for (const element of getTopLevelHTMLElements()) {
|
||||
verify(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/brace-style.js
generated
vendored
Normal file
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/brace-style.js
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('brace-style', {
|
||||
skipDynamicArguments: true
|
||||
})
|
9
app_vue/node_modules/eslint-plugin-vue/lib/rules/camelcase.js
generated
vendored
Normal file
9
app_vue/node_modules/eslint-plugin-vue/lib/rules/camelcase.js
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('camelcase')
|
9
app_vue/node_modules/eslint-plugin-vue/lib/rules/comma-dangle.js
generated
vendored
Normal file
9
app_vue/node_modules/eslint-plugin-vue/lib/rules/comma-dangle.js
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('comma-dangle')
|
13
app_vue/node_modules/eslint-plugin-vue/lib/rules/comma-spacing.js
generated
vendored
Normal file
13
app_vue/node_modules/eslint-plugin-vue/lib/rules/comma-spacing.js
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('comma-spacing', {
|
||||
skipDynamicArguments: true,
|
||||
skipDynamicArgumentsReport: true,
|
||||
applyDocument: true
|
||||
})
|
20
app_vue/node_modules/eslint-plugin-vue/lib/rules/comma-style.js
generated
vendored
Normal file
20
app_vue/node_modules/eslint-plugin-vue/lib/rules/comma-style.js
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('comma-style', {
|
||||
create(_context, { coreHandlers }) {
|
||||
return {
|
||||
VSlotScopeExpression(node) {
|
||||
if (coreHandlers.FunctionExpression) {
|
||||
// @ts-expect-error -- Process params of VSlotScopeExpression as FunctionExpression.
|
||||
coreHandlers.FunctionExpression(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
366
app_vue/node_modules/eslint-plugin-vue/lib/rules/comment-directive.js
generated
vendored
Normal file
366
app_vue/node_modules/eslint-plugin-vue/lib/rules/comment-directive.js
generated
vendored
Normal file
@ -0,0 +1,366 @@
|
||||
/**
|
||||
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||
*/
|
||||
/* eslint-disable eslint-plugin/report-message-format */
|
||||
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
/**
|
||||
* @typedef {object} RuleAndLocation
|
||||
* @property {string} RuleAndLocation.ruleId
|
||||
* @property {number} RuleAndLocation.index
|
||||
* @property {string} [RuleAndLocation.key]
|
||||
*/
|
||||
// -----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const COMMENT_DIRECTIVE_B = /^\s*(eslint-(?:en|dis)able)(?:\s+|$)/
|
||||
const COMMENT_DIRECTIVE_L = /^\s*(eslint-disable(?:-next)?-line)(?:\s+|$)/
|
||||
|
||||
/**
|
||||
* Remove the ignored part from a given directive comment and trim it.
|
||||
* @param {string} value The comment text to strip.
|
||||
* @returns {string} The stripped text.
|
||||
*/
|
||||
function stripDirectiveComment(value) {
|
||||
return value.split(/\s-{2,}\s/u)[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a given comment.
|
||||
* @param {RegExp} pattern The RegExp pattern to parse.
|
||||
* @param {string} comment The comment value to parse.
|
||||
* @returns {({type:string,rules:RuleAndLocation[]})|null} The parsing result.
|
||||
*/
|
||||
function parse(pattern, comment) {
|
||||
const text = stripDirectiveComment(comment)
|
||||
const match = pattern.exec(text)
|
||||
if (match == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
const type = match[1]
|
||||
|
||||
/** @type {RuleAndLocation[]} */
|
||||
const rules = []
|
||||
|
||||
const rulesRe = /([^,\s]+)[,\s]*/g
|
||||
let startIndex = match[0].length
|
||||
rulesRe.lastIndex = startIndex
|
||||
|
||||
let res
|
||||
while ((res = rulesRe.exec(text))) {
|
||||
const ruleId = res[1].trim()
|
||||
rules.push({
|
||||
ruleId,
|
||||
index: startIndex
|
||||
})
|
||||
startIndex = rulesRe.lastIndex
|
||||
}
|
||||
|
||||
return { type, rules }
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable rules.
|
||||
* @param {RuleContext} context The rule context.
|
||||
* @param {{line:number,column:number}} loc The location information to enable.
|
||||
* @param { 'block' | 'line' } group The group to enable.
|
||||
* @param {string | null} rule The rule ID to enable.
|
||||
* @returns {void}
|
||||
*/
|
||||
function enable(context, loc, group, rule) {
|
||||
if (!rule) {
|
||||
context.report({
|
||||
loc,
|
||||
messageId: group === 'block' ? 'enableBlock' : 'enableLine'
|
||||
})
|
||||
} else {
|
||||
context.report({
|
||||
loc,
|
||||
messageId: group === 'block' ? 'enableBlockRule' : 'enableLineRule',
|
||||
data: { rule }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable rules.
|
||||
* @param {RuleContext} context The rule context.
|
||||
* @param {{line:number,column:number}} loc The location information to disable.
|
||||
* @param { 'block' | 'line' } group The group to disable.
|
||||
* @param {string | null} rule The rule ID to disable.
|
||||
* @param {string} key The disable directive key.
|
||||
* @returns {void}
|
||||
*/
|
||||
function disable(context, loc, group, rule, key) {
|
||||
if (!rule) {
|
||||
context.report({
|
||||
loc,
|
||||
messageId: group === 'block' ? 'disableBlock' : 'disableLine',
|
||||
data: { key }
|
||||
})
|
||||
} else {
|
||||
context.report({
|
||||
loc,
|
||||
messageId: group === 'block' ? 'disableBlockRule' : 'disableLineRule',
|
||||
data: { rule, key }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a given comment token.
|
||||
* If the comment is `eslint-disable` or `eslint-enable` then it reports the comment.
|
||||
* @param {RuleContext} context The rule context.
|
||||
* @param {Token} comment The comment token to process.
|
||||
* @param {boolean} reportUnusedDisableDirectives To report unused eslint-disable comments.
|
||||
* @returns {void}
|
||||
*/
|
||||
function processBlock(context, comment, reportUnusedDisableDirectives) {
|
||||
const parsed = parse(COMMENT_DIRECTIVE_B, comment.value)
|
||||
if (parsed != null) {
|
||||
if (parsed.type === 'eslint-disable') {
|
||||
if (parsed.rules.length) {
|
||||
const rules = reportUnusedDisableDirectives
|
||||
? reportUnusedRules(context, comment, parsed.type, parsed.rules)
|
||||
: parsed.rules
|
||||
for (const rule of rules) {
|
||||
disable(
|
||||
context,
|
||||
comment.loc.start,
|
||||
'block',
|
||||
rule.ruleId,
|
||||
rule.key || '*'
|
||||
)
|
||||
}
|
||||
} else {
|
||||
const key = reportUnusedDisableDirectives
|
||||
? reportUnused(context, comment, parsed.type)
|
||||
: ''
|
||||
disable(context, comment.loc.start, 'block', null, key)
|
||||
}
|
||||
} else {
|
||||
if (parsed.rules.length) {
|
||||
for (const rule of parsed.rules) {
|
||||
enable(context, comment.loc.start, 'block', rule.ruleId)
|
||||
}
|
||||
} else {
|
||||
enable(context, comment.loc.start, 'block', null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a given comment token.
|
||||
* If the comment is `eslint-disable-line` or `eslint-disable-next-line` then it reports the comment.
|
||||
* @param {RuleContext} context The rule context.
|
||||
* @param {Token} comment The comment token to process.
|
||||
* @param {boolean} reportUnusedDisableDirectives To report unused eslint-disable comments.
|
||||
* @returns {void}
|
||||
*/
|
||||
function processLine(context, comment, reportUnusedDisableDirectives) {
|
||||
const parsed = parse(COMMENT_DIRECTIVE_L, comment.value)
|
||||
if (parsed != null && comment.loc.start.line === comment.loc.end.line) {
|
||||
const line =
|
||||
comment.loc.start.line + (parsed.type === 'eslint-disable-line' ? 0 : 1)
|
||||
const column = -1
|
||||
if (parsed.rules.length) {
|
||||
const rules = reportUnusedDisableDirectives
|
||||
? reportUnusedRules(context, comment, parsed.type, parsed.rules)
|
||||
: parsed.rules
|
||||
for (const rule of rules) {
|
||||
disable(context, { line, column }, 'line', rule.ruleId, rule.key || '')
|
||||
enable(context, { line: line + 1, column }, 'line', rule.ruleId)
|
||||
}
|
||||
} else {
|
||||
const key = reportUnusedDisableDirectives
|
||||
? reportUnused(context, comment, parsed.type)
|
||||
: ''
|
||||
disable(context, { line, column }, 'line', null, key)
|
||||
enable(context, { line: line + 1, column }, 'line', null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports unused disable directive.
|
||||
* Do not check the use of directives here. Filter the directives used with postprocess.
|
||||
* @param {RuleContext} context The rule context.
|
||||
* @param {Token} comment The comment token to report.
|
||||
* @param {string} kind The comment directive kind.
|
||||
* @returns {string} The report key
|
||||
*/
|
||||
function reportUnused(context, comment, kind) {
|
||||
const loc = comment.loc
|
||||
|
||||
context.report({
|
||||
loc,
|
||||
messageId: 'unused',
|
||||
data: { kind }
|
||||
})
|
||||
|
||||
return locToKey(loc.start)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports unused disable directive rules.
|
||||
* Do not check the use of directives here. Filter the directives used with postprocess.
|
||||
* @param {RuleContext} context The rule context.
|
||||
* @param {Token} comment The comment token to report.
|
||||
* @param {string} kind The comment directive kind.
|
||||
* @param {RuleAndLocation[]} rules To report rule.
|
||||
* @returns { { ruleId: string, key: string }[] }
|
||||
*/
|
||||
function reportUnusedRules(context, comment, kind, rules) {
|
||||
const sourceCode = context.getSourceCode()
|
||||
const commentStart = comment.range[0] + 4 /* <!-- */
|
||||
|
||||
return rules.map((rule) => {
|
||||
const start = sourceCode.getLocFromIndex(commentStart + rule.index)
|
||||
const end = sourceCode.getLocFromIndex(
|
||||
commentStart + rule.index + rule.ruleId.length
|
||||
)
|
||||
|
||||
context.report({
|
||||
loc: { start, end },
|
||||
messageId: 'unusedRule',
|
||||
data: { rule: rule.ruleId, kind }
|
||||
})
|
||||
|
||||
return {
|
||||
ruleId: rule.ruleId,
|
||||
key: locToKey(start)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key of location
|
||||
* @param {Position} location The location
|
||||
* @returns {string} The key
|
||||
*/
|
||||
function locToKey(location) {
|
||||
return `line:${location.line},column${location.column}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the top-level elements in document fragment.
|
||||
* @param {VDocumentFragment} documentFragment The document fragment.
|
||||
* @returns {VElement[]} The top-level elements
|
||||
*/
|
||||
function extractTopLevelHTMLElements(documentFragment) {
|
||||
return documentFragment.children.filter(utils.isVElement)
|
||||
}
|
||||
/**
|
||||
* Extracts the top-level comments in document fragment.
|
||||
* @param {VDocumentFragment} documentFragment The document fragment.
|
||||
* @returns {Token[]} The top-level comments
|
||||
*/
|
||||
function extractTopLevelDocumentFragmentComments(documentFragment) {
|
||||
const elements = extractTopLevelHTMLElements(documentFragment)
|
||||
|
||||
return documentFragment.comments.filter((comment) =>
|
||||
elements.every(
|
||||
(element) =>
|
||||
comment.range[1] <= element.range[0] ||
|
||||
element.range[1] <= comment.range[0]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'support comment-directives in `<template>`', // eslint-disable-line eslint-plugin/require-meta-docs-description
|
||||
categories: ['base'],
|
||||
url: 'https://eslint.vuejs.org/rules/comment-directive.html'
|
||||
},
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
reportUnusedDisableDirectives: {
|
||||
type: 'boolean'
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
disableBlock: '--block {{key}}',
|
||||
enableBlock: '++block',
|
||||
disableLine: '--line {{key}}',
|
||||
enableLine: '++line',
|
||||
disableBlockRule: '-block {{rule}} {{key}}',
|
||||
enableBlockRule: '+block {{rule}}',
|
||||
disableLineRule: '-line {{rule}} {{key}}',
|
||||
enableLineRule: '+line {{rule}}',
|
||||
clear: 'clear',
|
||||
|
||||
unused: 'Unused {{kind}} directive (no problems were reported).',
|
||||
unusedRule:
|
||||
"Unused {{kind}} directive (no problems were reported from '{{rule}}')."
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {RuleContext} context - The rule context.
|
||||
* @returns {RuleListener} AST event handlers.
|
||||
*/
|
||||
create(context) {
|
||||
const options = context.options[0] || {}
|
||||
/** @type {boolean} */
|
||||
const reportUnusedDisableDirectives = options.reportUnusedDisableDirectives
|
||||
const documentFragment =
|
||||
context.parserServices.getDocumentFragment &&
|
||||
context.parserServices.getDocumentFragment()
|
||||
|
||||
return {
|
||||
Program(node) {
|
||||
if (node.templateBody) {
|
||||
// Send directives to the post-process.
|
||||
for (const comment of node.templateBody.comments) {
|
||||
processBlock(context, comment, reportUnusedDisableDirectives)
|
||||
processLine(context, comment, reportUnusedDisableDirectives)
|
||||
}
|
||||
|
||||
// Send a clear mark to the post-process.
|
||||
context.report({
|
||||
loc: node.templateBody.loc.end,
|
||||
messageId: 'clear'
|
||||
})
|
||||
}
|
||||
if (documentFragment) {
|
||||
// Send directives to the post-process.
|
||||
for (const comment of extractTopLevelDocumentFragmentComments(
|
||||
documentFragment
|
||||
)) {
|
||||
processBlock(context, comment, reportUnusedDisableDirectives)
|
||||
processLine(context, comment, reportUnusedDisableDirectives)
|
||||
}
|
||||
|
||||
// Send a clear mark to the post-process.
|
||||
for (const element of extractTopLevelHTMLElements(documentFragment)) {
|
||||
context.report({
|
||||
loc: element.loc.end,
|
||||
messageId: 'clear'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
299
app_vue/node_modules/eslint-plugin-vue/lib/rules/component-api-style.js
generated
vendored
Normal file
299
app_vue/node_modules/eslint-plugin-vue/lib/rules/component-api-style.js
generated
vendored
Normal file
@ -0,0 +1,299 @@
|
||||
/**
|
||||
* @author Yosuke Ota <https://github.com/ota-meshi>
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
/**
|
||||
* @typedef { 'script-setup' | 'composition' | 'composition-vue2' | 'options' } PreferOption
|
||||
*
|
||||
* @typedef {PreferOption[]} UserPreferOption
|
||||
*
|
||||
* @typedef {object} NormalizeOptions
|
||||
* @property {object} allowsSFC
|
||||
* @property {boolean} [allowsSFC.scriptSetup]
|
||||
* @property {boolean} [allowsSFC.composition]
|
||||
* @property {boolean} [allowsSFC.compositionVue2]
|
||||
* @property {boolean} [allowsSFC.options]
|
||||
* @property {object} allowsOther
|
||||
* @property {boolean} [allowsOther.composition]
|
||||
* @property {boolean} [allowsOther.compositionVue2]
|
||||
* @property {boolean} [allowsOther.options]
|
||||
*/
|
||||
|
||||
/** @type {PreferOption[]} */
|
||||
const STYLE_OPTIONS = [
|
||||
'script-setup',
|
||||
'composition',
|
||||
'composition-vue2',
|
||||
'options'
|
||||
]
|
||||
|
||||
/**
|
||||
* Normalize options.
|
||||
* @param {any[]} options The options user configured.
|
||||
* @returns {NormalizeOptions} The normalized options.
|
||||
*/
|
||||
function parseOptions(options) {
|
||||
/** @type {NormalizeOptions} */
|
||||
const opts = { allowsSFC: {}, allowsOther: {} }
|
||||
|
||||
/** @type {UserPreferOption} */
|
||||
const preferOptions = options[0] || ['script-setup', 'composition']
|
||||
for (const prefer of preferOptions) {
|
||||
if (prefer === 'script-setup') {
|
||||
opts.allowsSFC.scriptSetup = true
|
||||
} else if (prefer === 'composition') {
|
||||
opts.allowsSFC.composition = true
|
||||
opts.allowsOther.composition = true
|
||||
} else if (prefer === 'composition-vue2') {
|
||||
opts.allowsSFC.compositionVue2 = true
|
||||
opts.allowsOther.compositionVue2 = true
|
||||
} else if (prefer === 'options') {
|
||||
opts.allowsSFC.options = true
|
||||
opts.allowsOther.options = true
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!opts.allowsOther.composition &&
|
||||
!opts.allowsOther.compositionVue2 &&
|
||||
!opts.allowsOther.options
|
||||
) {
|
||||
opts.allowsOther.composition = true
|
||||
opts.allowsOther.compositionVue2 = true
|
||||
opts.allowsOther.options = true
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
const OPTIONS_API_OPTIONS = new Set([
|
||||
'mixins',
|
||||
'extends',
|
||||
// state
|
||||
'data',
|
||||
'computed',
|
||||
'methods',
|
||||
'watch',
|
||||
'provide',
|
||||
'inject',
|
||||
// lifecycle
|
||||
'beforeCreate',
|
||||
'created',
|
||||
'beforeMount',
|
||||
'mounted',
|
||||
'beforeUpdate',
|
||||
'updated',
|
||||
'activated',
|
||||
'deactivated',
|
||||
'beforeDestroy',
|
||||
'beforeUnmount',
|
||||
'destroyed',
|
||||
'unmounted',
|
||||
'render',
|
||||
'renderTracked',
|
||||
'renderTriggered',
|
||||
'errorCaptured',
|
||||
// public API
|
||||
'expose'
|
||||
])
|
||||
const COMPOSITION_API_OPTIONS = new Set(['setup'])
|
||||
|
||||
const COMPOSITION_API_VUE2_OPTIONS = new Set([
|
||||
'setup',
|
||||
'render', // https://github.com/vuejs/composition-api#template-refs
|
||||
'renderTracked', // https://github.com/vuejs/composition-api#missing-apis
|
||||
'renderTriggered' // https://github.com/vuejs/composition-api#missing-apis
|
||||
])
|
||||
|
||||
const LIFECYCLE_HOOK_OPTIONS = new Set([
|
||||
'beforeCreate',
|
||||
'created',
|
||||
'beforeMount',
|
||||
'mounted',
|
||||
'beforeUpdate',
|
||||
'updated',
|
||||
'activated',
|
||||
'deactivated',
|
||||
'beforeDestroy',
|
||||
'beforeUnmount',
|
||||
'destroyed',
|
||||
'unmounted',
|
||||
'renderTracked',
|
||||
'renderTriggered',
|
||||
'errorCaptured'
|
||||
])
|
||||
|
||||
/**
|
||||
* @typedef { 'script-setup' | 'composition' | 'options' } ApiStyle
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {object} allowsOpt
|
||||
* @param {boolean} [allowsOpt.scriptSetup]
|
||||
* @param {boolean} [allowsOpt.composition]
|
||||
* @param {boolean} [allowsOpt.compositionVue2]
|
||||
* @param {boolean} [allowsOpt.options]
|
||||
*/
|
||||
function buildAllowedPhrase(allowsOpt) {
|
||||
const phrases = []
|
||||
if (allowsOpt.scriptSetup) {
|
||||
phrases.push('`<script setup>`')
|
||||
}
|
||||
if (allowsOpt.composition) {
|
||||
phrases.push('Composition API')
|
||||
}
|
||||
if (allowsOpt.compositionVue2) {
|
||||
phrases.push('Composition API (Vue 2)')
|
||||
}
|
||||
if (allowsOpt.options) {
|
||||
phrases.push('Options API')
|
||||
}
|
||||
return phrases.length > 2
|
||||
? `${phrases.slice(0, -1).join(',')} or ${phrases.slice(-1)[0]}`
|
||||
: phrases.join(' or ')
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} allowsOpt
|
||||
* @param {boolean} [allowsOpt.scriptSetup]
|
||||
* @param {boolean} [allowsOpt.composition]
|
||||
* @param {boolean} [allowsOpt.compositionVue2]
|
||||
* @param {boolean} [allowsOpt.options]
|
||||
*/
|
||||
function isPreferScriptSetup(allowsOpt) {
|
||||
if (
|
||||
!allowsOpt.scriptSetup ||
|
||||
allowsOpt.composition ||
|
||||
allowsOpt.compositionVue2 ||
|
||||
allowsOpt.options
|
||||
) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
function buildOptionPhrase(name) {
|
||||
return LIFECYCLE_HOOK_OPTIONS.has(name)
|
||||
? `\`${name}\` lifecycle hook`
|
||||
: name === 'setup' || name === 'render'
|
||||
? `\`${name}\` function`
|
||||
: `\`${name}\` option`
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'enforce component API style',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/component-api-style.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
enum: STYLE_OPTIONS,
|
||||
uniqueItems: true,
|
||||
additionalItems: false
|
||||
},
|
||||
minItems: 1
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
disallowScriptSetup:
|
||||
'`<script setup>` is not allowed in your project. Use {{allowedApis}} instead.',
|
||||
disallowComponentOption:
|
||||
'{{disallowedApi}} is not allowed in your project. {{optionPhrase}} is part of the {{disallowedApi}}. Use {{allowedApis}} instead.',
|
||||
disallowComponentOptionPreferScriptSetup:
|
||||
'{{disallowedApi}} is not allowed in your project. Use `<script setup>` instead.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const options = parseOptions(context.options)
|
||||
|
||||
return utils.compositingVisitors(
|
||||
{
|
||||
Program() {
|
||||
if (options.allowsSFC.scriptSetup) {
|
||||
return
|
||||
}
|
||||
const scriptSetup = utils.getScriptSetupElement(context)
|
||||
if (scriptSetup) {
|
||||
context.report({
|
||||
node: scriptSetup.startTag,
|
||||
messageId: 'disallowScriptSetup',
|
||||
data: {
|
||||
allowedApis: buildAllowedPhrase(options.allowsSFC)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
utils.defineVueVisitor(context, {
|
||||
onVueObjectEnter(node) {
|
||||
const allows = utils.isSFCObject(context, node)
|
||||
? options.allowsSFC
|
||||
: options.allowsOther
|
||||
if (
|
||||
(allows.composition || allows.compositionVue2) &&
|
||||
allows.options
|
||||
) {
|
||||
return
|
||||
}
|
||||
const apis = [
|
||||
{
|
||||
allow: allows.composition,
|
||||
options: COMPOSITION_API_OPTIONS,
|
||||
apiName: 'Composition API'
|
||||
},
|
||||
{
|
||||
allow: allows.options,
|
||||
options: OPTIONS_API_OPTIONS,
|
||||
apiName: 'Options API'
|
||||
},
|
||||
{
|
||||
allow: allows.compositionVue2,
|
||||
options: COMPOSITION_API_VUE2_OPTIONS,
|
||||
apiName: 'Composition API (Vue 2)'
|
||||
}
|
||||
]
|
||||
for (const prop of node.properties) {
|
||||
if (prop.type !== 'Property') {
|
||||
continue
|
||||
}
|
||||
const name = utils.getStaticPropertyName(prop)
|
||||
if (!name) {
|
||||
continue
|
||||
}
|
||||
const disallowApi =
|
||||
!apis.some((api) => api.allow && api.options.has(name)) &&
|
||||
apis.find((api) => !api.allow && api.options.has(name))
|
||||
|
||||
if (disallowApi) {
|
||||
context.report({
|
||||
node: prop.key,
|
||||
messageId: isPreferScriptSetup(allows)
|
||||
? 'disallowComponentOptionPreferScriptSetup'
|
||||
: 'disallowComponentOption',
|
||||
data: {
|
||||
disallowedApi: disallowApi.apiName,
|
||||
optionPhrase: buildOptionPhrase(name),
|
||||
allowedApis: buildAllowedPhrase(allows)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
107
app_vue/node_modules/eslint-plugin-vue/lib/rules/component-definition-name-casing.js
generated
vendored
Normal file
107
app_vue/node_modules/eslint-plugin-vue/lib/rules/component-definition-name-casing.js
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @fileoverview enforce specific casing for component definition name
|
||||
* @author Armano
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
const casing = require('../utils/casing')
|
||||
const allowedCaseOptions = ['PascalCase', 'kebab-case']
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'enforce specific casing for component definition name',
|
||||
categories: ['vue3-strongly-recommended', 'strongly-recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/component-definition-name-casing.html'
|
||||
},
|
||||
fixable: 'code', // or "code" or "whitespace"
|
||||
schema: [
|
||||
{
|
||||
enum: allowedCaseOptions
|
||||
}
|
||||
]
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const options = context.options[0]
|
||||
const caseType =
|
||||
allowedCaseOptions.indexOf(options) !== -1 ? options : 'PascalCase'
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {Literal | TemplateLiteral} node
|
||||
*/
|
||||
function convertName(node) {
|
||||
/** @type {string} */
|
||||
let nodeValue
|
||||
/** @type {Range} */
|
||||
let range
|
||||
if (node.type === 'TemplateLiteral') {
|
||||
const quasis = node.quasis[0]
|
||||
nodeValue = quasis.value.cooked
|
||||
range = quasis.range
|
||||
} else {
|
||||
nodeValue = `${node.value}`
|
||||
range = node.range
|
||||
}
|
||||
|
||||
if (!casing.getChecker(caseType)(nodeValue)) {
|
||||
context.report({
|
||||
node,
|
||||
message: 'Property name "{{value}}" is not {{caseType}}.',
|
||||
data: {
|
||||
value: nodeValue,
|
||||
caseType
|
||||
},
|
||||
fix: (fixer) =>
|
||||
fixer.replaceTextRange(
|
||||
[range[0] + 1, range[1] - 1],
|
||||
casing.getExactConverter(caseType)(nodeValue)
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Expression | SpreadElement} node
|
||||
* @returns {node is (Literal | TemplateLiteral)}
|
||||
*/
|
||||
function canConvert(node) {
|
||||
return (
|
||||
node.type === 'Literal' ||
|
||||
(node.type === 'TemplateLiteral' &&
|
||||
node.expressions.length === 0 &&
|
||||
node.quasis.length === 1)
|
||||
)
|
||||
}
|
||||
|
||||
return Object.assign(
|
||||
{},
|
||||
utils.executeOnCallVueComponent(context, (node) => {
|
||||
if (node.arguments.length === 2) {
|
||||
const argument = node.arguments[0]
|
||||
|
||||
if (canConvert(argument)) {
|
||||
convertName(argument)
|
||||
}
|
||||
}
|
||||
}),
|
||||
utils.executeOnVue(context, (obj) => {
|
||||
const node = utils.findProperty(obj, 'name')
|
||||
|
||||
if (!node) return
|
||||
if (!canConvert(node.value)) return
|
||||
convertName(node.value)
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
163
app_vue/node_modules/eslint-plugin-vue/lib/rules/component-name-in-template-casing.js
generated
vendored
Normal file
163
app_vue/node_modules/eslint-plugin-vue/lib/rules/component-name-in-template-casing.js
generated
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* issue https://github.com/vuejs/eslint-plugin-vue/issues/250
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
const casing = require('../utils/casing')
|
||||
const { toRegExp } = require('../utils/regexp')
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const allowedCaseOptions = ['PascalCase', 'kebab-case']
|
||||
const defaultCase = 'PascalCase'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description:
|
||||
'enforce specific casing for the component naming style in template',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/component-name-in-template-casing.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [
|
||||
{
|
||||
enum: allowedCaseOptions
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
ignores: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
uniqueItems: true,
|
||||
additionalItems: false
|
||||
},
|
||||
registeredComponentsOnly: {
|
||||
type: 'boolean'
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const caseOption = context.options[0]
|
||||
const options = context.options[1] || {}
|
||||
const caseType =
|
||||
allowedCaseOptions.indexOf(caseOption) !== -1 ? caseOption : defaultCase
|
||||
/** @type {RegExp[]} */
|
||||
const ignores = (options.ignores || []).map(toRegExp)
|
||||
const registeredComponentsOnly = options.registeredComponentsOnly !== false
|
||||
const tokens =
|
||||
context.parserServices.getTemplateBodyTokenStore &&
|
||||
context.parserServices.getTemplateBodyTokenStore()
|
||||
|
||||
/** @type { string[] } */
|
||||
const registeredComponents = []
|
||||
|
||||
/**
|
||||
* Checks whether the given node is the verification target node.
|
||||
* @param {VElement} node element node
|
||||
* @returns {boolean} `true` if the given node is the verification target node.
|
||||
*/
|
||||
function isVerifyTarget(node) {
|
||||
if (ignores.some((re) => re.test(node.rawName))) {
|
||||
// ignore
|
||||
return false
|
||||
}
|
||||
|
||||
if (!registeredComponentsOnly) {
|
||||
// If the user specifies registeredComponentsOnly as false, it checks all component tags.
|
||||
if (
|
||||
(!utils.isHtmlElementNode(node) && !utils.isSvgElementNode(node)) ||
|
||||
utils.isHtmlWellKnownElementName(node.rawName) ||
|
||||
utils.isSvgWellKnownElementName(node.rawName)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
// We only verify the components registered in the component.
|
||||
if (
|
||||
registeredComponents
|
||||
.filter((name) => casing.isPascalCase(name)) // When defining a component with PascalCase, you can use either case
|
||||
.some(
|
||||
(name) =>
|
||||
node.rawName === name || casing.pascalCase(node.rawName) === name
|
||||
)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
let hasInvalidEOF = false
|
||||
|
||||
return utils.defineTemplateBodyVisitor(
|
||||
context,
|
||||
{
|
||||
VElement(node) {
|
||||
if (hasInvalidEOF) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isVerifyTarget(node)) {
|
||||
return
|
||||
}
|
||||
|
||||
const name = node.rawName
|
||||
if (!casing.getChecker(caseType)(name)) {
|
||||
const startTag = node.startTag
|
||||
const open = tokens.getFirstToken(startTag)
|
||||
const casingName = casing.getExactConverter(caseType)(name)
|
||||
context.report({
|
||||
node: open,
|
||||
loc: open.loc,
|
||||
message: 'Component name "{{name}}" is not {{caseType}}.',
|
||||
data: {
|
||||
name,
|
||||
caseType
|
||||
},
|
||||
*fix(fixer) {
|
||||
yield fixer.replaceText(open, `<${casingName}`)
|
||||
const endTag = node.endTag
|
||||
if (endTag) {
|
||||
const endTagOpen = tokens.getFirstToken(endTag)
|
||||
yield fixer.replaceText(endTagOpen, `</${casingName}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
Program(node) {
|
||||
hasInvalidEOF = utils.hasInvalidEOF(node)
|
||||
},
|
||||
...(registeredComponentsOnly
|
||||
? utils.executeOnVue(context, (obj) => {
|
||||
registeredComponents.push(
|
||||
...utils.getRegisteredComponents(obj).map((n) => n.name)
|
||||
)
|
||||
})
|
||||
: {})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
115
app_vue/node_modules/eslint-plugin-vue/lib/rules/component-options-name-casing.js
generated
vendored
Normal file
115
app_vue/node_modules/eslint-plugin-vue/lib/rules/component-options-name-casing.js
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @author Pig Fang
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
const casing = require('../utils/casing')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {import('../../typings/eslint-plugin-vue/util-types/ast').Expression} node
|
||||
* @returns {string | null}
|
||||
*/
|
||||
function getOptionsComponentName(node) {
|
||||
if (node.type === 'Identifier') {
|
||||
return node.name
|
||||
}
|
||||
if (node.type === 'Literal') {
|
||||
return typeof node.value === 'string' ? node.value : null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description:
|
||||
'enforce the casing of component name in `components` options',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/component-options-name-casing.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
hasSuggestions: true,
|
||||
schema: [{ enum: casing.allowedCaseOptions }],
|
||||
messages: {
|
||||
caseNotMatched: 'Component name "{{component}}" is not {{caseType}}.',
|
||||
possibleRenaming: 'Rename component name to be in {{caseType}}.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const caseType = context.options[0] || 'PascalCase'
|
||||
|
||||
const canAutoFix = caseType === 'PascalCase'
|
||||
const checkCase = casing.getChecker(caseType)
|
||||
const convert = casing.getConverter(caseType)
|
||||
|
||||
return utils.executeOnVue(context, (obj) => {
|
||||
const node = utils.findProperty(obj, 'components')
|
||||
if (!node || node.value.type !== 'ObjectExpression') {
|
||||
return
|
||||
}
|
||||
|
||||
node.value.properties.forEach((property) => {
|
||||
if (property.type !== 'Property') {
|
||||
return
|
||||
}
|
||||
|
||||
const name = getOptionsComponentName(property.key)
|
||||
if (!name || checkCase(name)) {
|
||||
return
|
||||
}
|
||||
|
||||
context.report({
|
||||
node: property.key,
|
||||
messageId: 'caseNotMatched',
|
||||
data: {
|
||||
component: name,
|
||||
caseType
|
||||
},
|
||||
fix: canAutoFix
|
||||
? (fixer) => {
|
||||
const converted = convert(name)
|
||||
return property.shorthand
|
||||
? fixer.replaceText(property, `${converted}: ${name}`)
|
||||
: fixer.replaceText(property.key, converted)
|
||||
}
|
||||
: undefined,
|
||||
suggest: canAutoFix
|
||||
? undefined
|
||||
: [
|
||||
{
|
||||
messageId: 'possibleRenaming',
|
||||
data: { caseType },
|
||||
fix: (fixer) => {
|
||||
const converted = convert(name)
|
||||
if (caseType === 'kebab-case') {
|
||||
return property.shorthand
|
||||
? fixer.replaceText(property, `'${converted}': ${name}`)
|
||||
: fixer.replaceText(property.key, `'${converted}'`)
|
||||
}
|
||||
return property.shorthand
|
||||
? fixer.replaceText(property, `${converted}: ${name}`)
|
||||
: fixer.replaceText(property.key, converted)
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
195
app_vue/node_modules/eslint-plugin-vue/lib/rules/component-tags-order.js
generated
vendored
Normal file
195
app_vue/node_modules/eslint-plugin-vue/lib/rules/component-tags-order.js
generated
vendored
Normal file
@ -0,0 +1,195 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* issue https://github.com/vuejs/eslint-plugin-vue/issues/140
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
const { parseSelector } = require('../utils/selector')
|
||||
|
||||
/**
|
||||
* @typedef {import('../utils/selector').VElementSelector} VElementSelector
|
||||
*/
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const DEFAULT_ORDER = Object.freeze([['script', 'template'], 'style'])
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'enforce order of component top-level elements',
|
||||
categories: ['vue3-recommended', 'recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/component-tags-order.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
order: {
|
||||
type: 'array',
|
||||
items: {
|
||||
anyOf: [
|
||||
{ type: 'string' },
|
||||
{ type: 'array', items: { type: 'string' }, uniqueItems: true }
|
||||
]
|
||||
},
|
||||
uniqueItems: true,
|
||||
additionalItems: false
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
unexpected:
|
||||
"'<{{elementName}}{{elementAttributes}}>' should be above '<{{firstUnorderedName}}{{firstUnorderedAttributes}}>' on line {{line}}."
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {RuleContext} context - The rule context.
|
||||
* @returns {RuleListener} AST event handlers.
|
||||
*/
|
||||
create(context) {
|
||||
/**
|
||||
* @typedef {object} OrderElement
|
||||
* @property {string} selectorText
|
||||
* @property {VElementSelector} selector
|
||||
* @property {number} index
|
||||
*/
|
||||
/** @type {OrderElement[]} */
|
||||
const orders = []
|
||||
/** @type {(string|string[])[]} */
|
||||
const orderOptions =
|
||||
(context.options[0] && context.options[0].order) || DEFAULT_ORDER
|
||||
orderOptions.forEach((selectorOrSelectors, index) => {
|
||||
if (Array.isArray(selectorOrSelectors)) {
|
||||
for (const selector of selectorOrSelectors) {
|
||||
orders.push({
|
||||
selectorText: selector,
|
||||
selector: parseSelector(selector, context),
|
||||
index
|
||||
})
|
||||
}
|
||||
} else {
|
||||
orders.push({
|
||||
selectorText: selectorOrSelectors,
|
||||
selector: parseSelector(selectorOrSelectors, context),
|
||||
index
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* @param {VElement} element
|
||||
* @return {string}
|
||||
*/
|
||||
function getAttributeString(element) {
|
||||
return element.startTag.attributes
|
||||
.map((attribute) => {
|
||||
if (attribute.value && attribute.value.type !== 'VLiteral') {
|
||||
return ''
|
||||
}
|
||||
|
||||
return `${attribute.key.name}${
|
||||
attribute.value && attribute.value.value
|
||||
? `=${attribute.value.value}`
|
||||
: ''
|
||||
}`
|
||||
})
|
||||
.join(' ')
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VElement} element
|
||||
*/
|
||||
function getOrderElement(element) {
|
||||
return orders.find((o) => o.selector.test(element))
|
||||
}
|
||||
const documentFragment =
|
||||
context.parserServices.getDocumentFragment &&
|
||||
context.parserServices.getDocumentFragment()
|
||||
|
||||
function getTopLevelHTMLElements() {
|
||||
if (documentFragment) {
|
||||
return documentFragment.children.filter(utils.isVElement)
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
return {
|
||||
Program(node) {
|
||||
if (utils.hasInvalidEOF(node)) {
|
||||
return
|
||||
}
|
||||
const elements = getTopLevelHTMLElements()
|
||||
|
||||
const elementWithOrders = elements.flatMap((element) => {
|
||||
const order = getOrderElement(element)
|
||||
return order ? [{ order, element }] : []
|
||||
})
|
||||
const sourceCode = context.getSourceCode()
|
||||
elementWithOrders.forEach(({ order: expected, element }, index) => {
|
||||
const firstUnordered = elementWithOrders
|
||||
.slice(0, index)
|
||||
.filter(({ order }) => expected.index < order.index)
|
||||
.sort((e1, e2) => e1.order.index - e2.order.index)[0]
|
||||
if (firstUnordered) {
|
||||
const firstUnorderedAttributes = getAttributeString(
|
||||
firstUnordered.element
|
||||
)
|
||||
const elementAttributes = getAttributeString(element)
|
||||
|
||||
context.report({
|
||||
node: element,
|
||||
loc: element.loc,
|
||||
messageId: 'unexpected',
|
||||
data: {
|
||||
elementName: element.name,
|
||||
elementAttributes: elementAttributes
|
||||
? ` ${elementAttributes}`
|
||||
: '',
|
||||
firstUnorderedName: firstUnordered.element.name,
|
||||
firstUnorderedAttributes: firstUnorderedAttributes
|
||||
? ` ${firstUnorderedAttributes}`
|
||||
: '',
|
||||
line: firstUnordered.element.loc.start.line
|
||||
},
|
||||
*fix(fixer) {
|
||||
// insert element before firstUnordered
|
||||
const fixedElements = elements.flatMap((it) => {
|
||||
if (it === firstUnordered.element) {
|
||||
return [element, it]
|
||||
} else if (it === element) {
|
||||
return []
|
||||
}
|
||||
return [it]
|
||||
})
|
||||
for (let i = elements.length - 1; i >= 0; i--) {
|
||||
if (elements[i] !== fixedElements[i]) {
|
||||
yield fixer.replaceTextRange(
|
||||
elements[i].range,
|
||||
sourceCode.text.slice(...fixedElements[i].range)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
307
app_vue/node_modules/eslint-plugin-vue/lib/rules/custom-event-name-casing.js
generated
vendored
Normal file
307
app_vue/node_modules/eslint-plugin-vue/lib/rules/custom-event-name-casing.js
generated
vendored
Normal file
@ -0,0 +1,307 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const { findVariable } = require('eslint-utils')
|
||||
const utils = require('../utils')
|
||||
const casing = require('../utils/casing')
|
||||
const { toRegExp } = require('../utils/regexp')
|
||||
|
||||
/**
|
||||
* @typedef {import('../utils').VueObjectData} VueObjectData
|
||||
*/
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const ALLOWED_CASE_OPTIONS = ['kebab-case', 'camelCase']
|
||||
const DEFAULT_CASE = 'kebab-case'
|
||||
|
||||
/**
|
||||
* Get the name param node from the given CallExpression
|
||||
* @param {CallExpression} node CallExpression
|
||||
* @returns { Literal & { value: string } | null }
|
||||
*/
|
||||
function getNameParamNode(node) {
|
||||
const nameLiteralNode = node.arguments[0]
|
||||
if (
|
||||
!nameLiteralNode ||
|
||||
nameLiteralNode.type !== 'Literal' ||
|
||||
typeof nameLiteralNode.value !== 'string'
|
||||
) {
|
||||
// cannot check
|
||||
return null
|
||||
}
|
||||
|
||||
return /** @type {Literal & { value: string }} */ (nameLiteralNode)
|
||||
}
|
||||
/**
|
||||
* Get the callee member node from the given CallExpression
|
||||
* @param {CallExpression} node CallExpression
|
||||
*/
|
||||
function getCalleeMemberNode(node) {
|
||||
const callee = utils.skipChainExpression(node.callee)
|
||||
|
||||
if (callee.type === 'MemberExpression') {
|
||||
const name = utils.getStaticPropertyName(callee)
|
||||
if (name) {
|
||||
return { name, member: callee }
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const OBJECT_OPTION_SCHEMA = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
ignores: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
uniqueItems: true,
|
||||
additionalItems: false
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'enforce specific casing for custom event name',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/custom-event-name-casing.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: {
|
||||
anyOf: [
|
||||
{
|
||||
type: 'array',
|
||||
items: [
|
||||
{
|
||||
enum: ALLOWED_CASE_OPTIONS
|
||||
},
|
||||
OBJECT_OPTION_SCHEMA
|
||||
]
|
||||
},
|
||||
// For backward compatibility
|
||||
{
|
||||
type: 'array',
|
||||
items: [OBJECT_OPTION_SCHEMA]
|
||||
}
|
||||
]
|
||||
},
|
||||
messages: {
|
||||
unexpected: "Custom event name '{{name}}' must be {{caseType}}."
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
/** @type {Map<ObjectExpression|Program, {contextReferenceIds:Set<Identifier>,emitReferenceIds:Set<Identifier>}>} */
|
||||
const setupContexts = new Map()
|
||||
const options =
|
||||
context.options.length === 1 && typeof context.options[0] !== 'string'
|
||||
? // For backward compatibility
|
||||
[undefined, context.options[0]]
|
||||
: context.options
|
||||
const caseType = options[0] || DEFAULT_CASE
|
||||
const objectOption = options[1] || {}
|
||||
const caseChecker = casing.getChecker(caseType)
|
||||
/** @type {RegExp[]} */
|
||||
const ignores = (objectOption.ignores || []).map(toRegExp)
|
||||
|
||||
/**
|
||||
* Check whether the given event name is valid.
|
||||
* @param {string} name The name to check.
|
||||
* @returns {boolean} `true` if the given event name is valid.
|
||||
*/
|
||||
function isValidEventName(name) {
|
||||
return caseChecker(name) || name.startsWith('update:')
|
||||
}
|
||||
|
||||
/**
|
||||
* @param { Literal & { value: string } } nameLiteralNode
|
||||
*/
|
||||
function verify(nameLiteralNode) {
|
||||
const name = nameLiteralNode.value
|
||||
if (isValidEventName(name) || ignores.some((re) => re.test(name))) {
|
||||
return
|
||||
}
|
||||
context.report({
|
||||
node: nameLiteralNode,
|
||||
messageId: 'unexpected',
|
||||
data: {
|
||||
name,
|
||||
caseType
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const programNode = context.getSourceCode().ast
|
||||
|
||||
const callVisitor = {
|
||||
/**
|
||||
* @param {CallExpression} node
|
||||
* @param {VueObjectData} [info]
|
||||
*/
|
||||
CallExpression(node, info) {
|
||||
const nameLiteralNode = getNameParamNode(node)
|
||||
if (!nameLiteralNode) {
|
||||
// cannot check
|
||||
return
|
||||
}
|
||||
|
||||
// verify setup context
|
||||
const setupContext = setupContexts.get(info ? info.node : programNode)
|
||||
if (setupContext) {
|
||||
const { contextReferenceIds, emitReferenceIds } = setupContext
|
||||
if (
|
||||
node.callee.type === 'Identifier' &&
|
||||
emitReferenceIds.has(node.callee)
|
||||
) {
|
||||
// verify setup(props,{emit}) {emit()}
|
||||
verify(nameLiteralNode)
|
||||
} else {
|
||||
const emit = getCalleeMemberNode(node)
|
||||
if (
|
||||
emit &&
|
||||
emit.name === 'emit' &&
|
||||
emit.member.object.type === 'Identifier' &&
|
||||
contextReferenceIds.has(emit.member.object)
|
||||
) {
|
||||
// verify setup(props,context) {context.emit()}
|
||||
verify(nameLiteralNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return utils.defineTemplateBodyVisitor(
|
||||
context,
|
||||
{
|
||||
CallExpression(node) {
|
||||
const callee = node.callee
|
||||
const nameLiteralNode = getNameParamNode(node)
|
||||
if (!nameLiteralNode) {
|
||||
// cannot check
|
||||
return
|
||||
}
|
||||
if (callee.type === 'Identifier' && callee.name === '$emit') {
|
||||
verify(nameLiteralNode)
|
||||
}
|
||||
}
|
||||
},
|
||||
utils.compositingVisitors(
|
||||
utils.defineScriptSetupVisitor(context, {
|
||||
onDefineEmitsEnter(node) {
|
||||
if (
|
||||
!node.parent ||
|
||||
node.parent.type !== 'VariableDeclarator' ||
|
||||
node.parent.init !== node
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const emitParam = node.parent.id
|
||||
if (emitParam.type !== 'Identifier') {
|
||||
return
|
||||
}
|
||||
// const emit = defineEmits()
|
||||
const variable = findVariable(context.getScope(), emitParam)
|
||||
if (!variable) {
|
||||
return
|
||||
}
|
||||
const emitReferenceIds = new Set()
|
||||
for (const reference of variable.references) {
|
||||
emitReferenceIds.add(reference.identifier)
|
||||
}
|
||||
setupContexts.set(programNode, {
|
||||
contextReferenceIds: new Set(),
|
||||
emitReferenceIds
|
||||
})
|
||||
},
|
||||
...callVisitor
|
||||
}),
|
||||
utils.defineVueVisitor(context, {
|
||||
onSetupFunctionEnter(node, { node: vueNode }) {
|
||||
const contextParam = utils.skipDefaultParamValue(node.params[1])
|
||||
if (!contextParam) {
|
||||
// no arguments
|
||||
return
|
||||
}
|
||||
if (
|
||||
contextParam.type === 'RestElement' ||
|
||||
contextParam.type === 'ArrayPattern'
|
||||
) {
|
||||
// cannot check
|
||||
return
|
||||
}
|
||||
const contextReferenceIds = new Set()
|
||||
const emitReferenceIds = new Set()
|
||||
if (contextParam.type === 'ObjectPattern') {
|
||||
const emitProperty = utils.findAssignmentProperty(
|
||||
contextParam,
|
||||
'emit'
|
||||
)
|
||||
if (!emitProperty || emitProperty.value.type !== 'Identifier') {
|
||||
return
|
||||
}
|
||||
const emitParam = emitProperty.value
|
||||
// `setup(props, {emit})`
|
||||
const variable = findVariable(context.getScope(), emitParam)
|
||||
if (!variable) {
|
||||
return
|
||||
}
|
||||
for (const reference of variable.references) {
|
||||
emitReferenceIds.add(reference.identifier)
|
||||
}
|
||||
} else {
|
||||
// `setup(props, context)`
|
||||
const variable = findVariable(context.getScope(), contextParam)
|
||||
if (!variable) {
|
||||
return
|
||||
}
|
||||
for (const reference of variable.references) {
|
||||
contextReferenceIds.add(reference.identifier)
|
||||
}
|
||||
}
|
||||
setupContexts.set(vueNode, {
|
||||
contextReferenceIds,
|
||||
emitReferenceIds
|
||||
})
|
||||
},
|
||||
...callVisitor,
|
||||
onVueObjectExit(node) {
|
||||
setupContexts.delete(node)
|
||||
}
|
||||
}),
|
||||
{
|
||||
CallExpression(node) {
|
||||
const nameLiteralNode = getNameParamNode(node)
|
||||
if (!nameLiteralNode) {
|
||||
// cannot check
|
||||
return
|
||||
}
|
||||
const emit = getCalleeMemberNode(node)
|
||||
// verify $emit
|
||||
if (emit && emit.name === '$emit') {
|
||||
// verify this.$emit()
|
||||
verify(nameLiteralNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
307
app_vue/node_modules/eslint-plugin-vue/lib/rules/define-macros-order.js
generated
vendored
Normal file
307
app_vue/node_modules/eslint-plugin-vue/lib/rules/define-macros-order.js
generated
vendored
Normal file
@ -0,0 +1,307 @@
|
||||
/**
|
||||
* @author Eduard Deisling
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const MACROS_EMITS = 'defineEmits'
|
||||
const MACROS_PROPS = 'defineProps'
|
||||
const ORDER = [MACROS_EMITS, MACROS_PROPS]
|
||||
const DEFAULT_ORDER = [MACROS_PROPS, MACROS_EMITS]
|
||||
|
||||
/**
|
||||
* @param {VElement} scriptSetup
|
||||
* @param {ASTNode} node
|
||||
*/
|
||||
function inScriptSetup(scriptSetup, node) {
|
||||
return (
|
||||
scriptSetup.range[0] <= node.range[0] &&
|
||||
node.range[1] <= scriptSetup.range[1]
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ASTNode} node
|
||||
*/
|
||||
function isUseStrictStatement(node) {
|
||||
return (
|
||||
node.type === 'ExpressionStatement' &&
|
||||
node.expression.type === 'Literal' &&
|
||||
node.expression.value === 'use strict'
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an index of the first statement after imports and interfaces in order
|
||||
* to place defineEmits and defineProps before this statement
|
||||
* @param {VElement} scriptSetup
|
||||
* @param {Program} program
|
||||
*/
|
||||
function getTargetStatementPosition(scriptSetup, program) {
|
||||
const skipStatements = new Set([
|
||||
'ImportDeclaration',
|
||||
'TSInterfaceDeclaration',
|
||||
'TSTypeAliasDeclaration',
|
||||
'DebuggerStatement',
|
||||
'EmptyStatement'
|
||||
])
|
||||
|
||||
for (const [index, item] of program.body.entries()) {
|
||||
if (
|
||||
inScriptSetup(scriptSetup, item) &&
|
||||
!skipStatements.has(item.type) &&
|
||||
!isUseStrictStatement(item)
|
||||
) {
|
||||
return index
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to handle cases like "const props = defineProps(...)"
|
||||
* Define macros must be used only on top, so we can look for "Program" type
|
||||
* inside node.parent.type
|
||||
* @param {CallExpression|ASTNode} node
|
||||
* @return {ASTNode}
|
||||
*/
|
||||
function getDefineMacrosStatement(node) {
|
||||
if (!node.parent) {
|
||||
throw new Error('Node has no parent')
|
||||
}
|
||||
|
||||
if (node.parent.type === 'Program') {
|
||||
return node
|
||||
}
|
||||
|
||||
return getDefineMacrosStatement(node.parent)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/** @param {RuleContext} context */
|
||||
function create(context) {
|
||||
const scriptSetup = utils.getScriptSetupElement(context)
|
||||
|
||||
if (!scriptSetup) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const sourceCode = context.getSourceCode()
|
||||
const options = context.options
|
||||
/** @type {[string, string]} */
|
||||
const order = (options[0] && options[0].order) || DEFAULT_ORDER
|
||||
/** @type {Map<string, ASTNode>} */
|
||||
const macrosNodes = new Map()
|
||||
|
||||
return utils.compositingVisitors(
|
||||
utils.defineScriptSetupVisitor(context, {
|
||||
onDefinePropsExit(node) {
|
||||
macrosNodes.set(MACROS_PROPS, getDefineMacrosStatement(node))
|
||||
},
|
||||
onDefineEmitsExit(node) {
|
||||
macrosNodes.set(MACROS_EMITS, getDefineMacrosStatement(node))
|
||||
}
|
||||
}),
|
||||
{
|
||||
'Program:exit'(program) {
|
||||
const shouldFirstNode = macrosNodes.get(order[0])
|
||||
const shouldSecondNode = macrosNodes.get(order[1])
|
||||
const firstStatementIndex = getTargetStatementPosition(
|
||||
scriptSetup,
|
||||
program
|
||||
)
|
||||
const firstStatement = program.body[firstStatementIndex]
|
||||
|
||||
// have both defineEmits and defineProps
|
||||
if (shouldFirstNode && shouldSecondNode) {
|
||||
const secondStatement = program.body[firstStatementIndex + 1]
|
||||
|
||||
// need move only first
|
||||
if (firstStatement === shouldSecondNode) {
|
||||
reportNotOnTop(order[0], shouldFirstNode, firstStatement)
|
||||
return
|
||||
}
|
||||
|
||||
// need move both defineEmits and defineProps
|
||||
if (firstStatement !== shouldFirstNode) {
|
||||
reportBothNotOnTop(
|
||||
shouldFirstNode,
|
||||
shouldSecondNode,
|
||||
firstStatement
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// need move only second
|
||||
if (secondStatement !== shouldSecondNode) {
|
||||
reportNotOnTop(order[1], shouldSecondNode, shouldFirstNode)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// have only first and need to move it
|
||||
if (shouldFirstNode && firstStatement !== shouldFirstNode) {
|
||||
reportNotOnTop(order[0], shouldFirstNode, firstStatement)
|
||||
return
|
||||
}
|
||||
|
||||
// have only second and need to move it
|
||||
if (shouldSecondNode && firstStatement !== shouldSecondNode) {
|
||||
reportNotOnTop(order[1], shouldSecondNode, firstStatement)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* @param {ASTNode} shouldFirstNode
|
||||
* @param {ASTNode} shouldSecondNode
|
||||
* @param {ASTNode} before
|
||||
*/
|
||||
function reportBothNotOnTop(shouldFirstNode, shouldSecondNode, before) {
|
||||
context.report({
|
||||
node: shouldFirstNode,
|
||||
loc: shouldFirstNode.loc,
|
||||
messageId: 'macrosNotOnTop',
|
||||
data: {
|
||||
macro: order[0]
|
||||
},
|
||||
fix(fixer) {
|
||||
return [
|
||||
...moveNodeBefore(fixer, shouldFirstNode, before),
|
||||
...moveNodeBefore(fixer, shouldSecondNode, before)
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} macro
|
||||
* @param {ASTNode} node
|
||||
* @param {ASTNode} before
|
||||
*/
|
||||
function reportNotOnTop(macro, node, before) {
|
||||
context.report({
|
||||
node,
|
||||
loc: node.loc,
|
||||
messageId: 'macrosNotOnTop',
|
||||
data: {
|
||||
macro
|
||||
},
|
||||
fix(fixer) {
|
||||
return moveNodeBefore(fixer, node, before)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Move all lines of "node" with its comments to before the "target"
|
||||
* @param {RuleFixer} fixer
|
||||
* @param {ASTNode} node
|
||||
* @param {ASTNode} target
|
||||
*/
|
||||
function moveNodeBefore(fixer, node, target) {
|
||||
// get comments under tokens(if any)
|
||||
const beforeNodeToken = sourceCode.getTokenBefore(node)
|
||||
const nodeComment = sourceCode.getTokenAfter(beforeNodeToken, {
|
||||
includeComments: true
|
||||
})
|
||||
const nextNodeComment = sourceCode.getTokenAfter(node, {
|
||||
includeComments: true
|
||||
})
|
||||
// get positions of what we need to remove
|
||||
const cutStart = getLineStartIndex(nodeComment, beforeNodeToken)
|
||||
const cutEnd = getLineStartIndex(nextNodeComment, node)
|
||||
// get space before target
|
||||
const beforeTargetToken = sourceCode.getTokenBefore(target)
|
||||
const targetComment = sourceCode.getTokenAfter(beforeTargetToken, {
|
||||
includeComments: true
|
||||
})
|
||||
const textSpace = getTextBetweenTokens(beforeTargetToken, targetComment)
|
||||
// make insert text: comments + node + space before target
|
||||
const textNode = sourceCode.getText(
|
||||
node,
|
||||
node.range[0] - nodeComment.range[0]
|
||||
)
|
||||
const insertText = textNode + textSpace
|
||||
|
||||
return [
|
||||
fixer.insertTextBefore(targetComment, insertText),
|
||||
fixer.removeRange([cutStart, cutEnd])
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ASTNode} tokenBefore
|
||||
* @param {ASTNode} tokenAfter
|
||||
*/
|
||||
function getTextBetweenTokens(tokenBefore, tokenAfter) {
|
||||
return sourceCode.text.slice(tokenBefore.range[1], tokenAfter.range[0])
|
||||
}
|
||||
|
||||
/**
|
||||
* Get position of the beginning of the token's line(or prevToken end if no line)
|
||||
* @param {ASTNode} token
|
||||
* @param {ASTNode} prevToken
|
||||
*/
|
||||
function getLineStartIndex(token, prevToken) {
|
||||
// if we have next token on the same line - get index right before that token
|
||||
if (token.loc.start.line === prevToken.loc.end.line) {
|
||||
return prevToken.range[1]
|
||||
}
|
||||
|
||||
return sourceCode.getIndexFromLoc({
|
||||
line: token.loc.start.line,
|
||||
column: 0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
docs: {
|
||||
description:
|
||||
'enforce order of `defineEmits` and `defineProps` compiler macros',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/define-macros-order.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
order: {
|
||||
type: 'array',
|
||||
items: {
|
||||
enum: Object.values(ORDER)
|
||||
},
|
||||
uniqueItems: true,
|
||||
additionalItems: false
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
macrosNotOnTop:
|
||||
'{{macro}} should be the first statement in `<script setup>` (after any potential import statements or type definitions).'
|
||||
}
|
||||
},
|
||||
create
|
||||
}
|
9
app_vue/node_modules/eslint-plugin-vue/lib/rules/dot-location.js
generated
vendored
Normal file
9
app_vue/node_modules/eslint-plugin-vue/lib/rules/dot-location.js
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('dot-location')
|
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/dot-notation.js
generated
vendored
Normal file
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/dot-notation.js
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('dot-notation', {
|
||||
applyDocument: true
|
||||
})
|
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/eqeqeq.js
generated
vendored
Normal file
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/eqeqeq.js
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('eqeqeq', {
|
||||
applyDocument: true
|
||||
})
|
230
app_vue/node_modules/eslint-plugin-vue/lib/rules/experimental-script-setup-vars.js
generated
vendored
Normal file
230
app_vue/node_modules/eslint-plugin-vue/lib/rules/experimental-script-setup-vars.js
generated
vendored
Normal file
@ -0,0 +1,230 @@
|
||||
/**
|
||||
* @fileoverview prevent variables defined in `<script setup>` to be marked as undefined
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const Module = require('module')
|
||||
const path = require('path')
|
||||
const utils = require('../utils')
|
||||
const AST = require('vue-eslint-parser').AST
|
||||
|
||||
const ecmaVersion = 2020
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'prevent variables defined in `<script setup>` to be marked as undefined', // eslint-disable-line eslint-plugin/require-meta-docs-description
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/experimental-script-setup-vars.html'
|
||||
},
|
||||
deprecated: true,
|
||||
schema: []
|
||||
},
|
||||
/**
|
||||
* @param {RuleContext} context - The rule context.
|
||||
* @returns {RuleListener} AST event handlers.
|
||||
*/
|
||||
create(context) {
|
||||
const documentFragment =
|
||||
context.parserServices.getDocumentFragment &&
|
||||
context.parserServices.getDocumentFragment()
|
||||
if (!documentFragment) {
|
||||
return {}
|
||||
}
|
||||
const sourceCode = context.getSourceCode()
|
||||
const scriptElement = documentFragment.children
|
||||
.filter(utils.isVElement)
|
||||
.find(
|
||||
(element) =>
|
||||
element.name === 'script' &&
|
||||
element.range[0] <= sourceCode.ast.range[0] &&
|
||||
sourceCode.ast.range[1] <= element.range[1]
|
||||
)
|
||||
if (!scriptElement) {
|
||||
return {}
|
||||
}
|
||||
const setupAttr = utils.getAttribute(scriptElement, 'setup')
|
||||
if (!setupAttr || !setupAttr.value) {
|
||||
return {}
|
||||
}
|
||||
const value = setupAttr.value.value
|
||||
|
||||
let eslintScope
|
||||
try {
|
||||
eslintScope = getESLintModule('eslint-scope', () =>
|
||||
// @ts-ignore
|
||||
require('eslint-scope')
|
||||
)
|
||||
} catch (_e) {
|
||||
context.report({
|
||||
node: setupAttr,
|
||||
message: 'Can not be resolved eslint-scope.'
|
||||
})
|
||||
return {}
|
||||
}
|
||||
let espree
|
||||
try {
|
||||
espree = getESLintModule('espree', () =>
|
||||
// @ts-ignore
|
||||
require('espree')
|
||||
)
|
||||
} catch (_e) {
|
||||
context.report({
|
||||
node: setupAttr,
|
||||
message: 'Can not be resolved espree.'
|
||||
})
|
||||
return {}
|
||||
}
|
||||
|
||||
const globalScope = sourceCode.scopeManager.scopes[0]
|
||||
|
||||
/** @type {string[]} */
|
||||
let vars
|
||||
try {
|
||||
vars = parseSetup(value, espree, eslintScope)
|
||||
} catch (_e) {
|
||||
context.report({
|
||||
node: setupAttr.value,
|
||||
message: 'Parsing error.'
|
||||
})
|
||||
return {}
|
||||
}
|
||||
|
||||
// Define configured global variables.
|
||||
for (const id of vars) {
|
||||
const tempVariable = globalScope.set.get(id)
|
||||
|
||||
/** @type {Variable} */
|
||||
let variable
|
||||
if (!tempVariable) {
|
||||
variable = new eslintScope.Variable(id, globalScope)
|
||||
|
||||
globalScope.variables.push(variable)
|
||||
globalScope.set.set(id, variable)
|
||||
} else {
|
||||
variable = tempVariable
|
||||
}
|
||||
|
||||
variable.eslintImplicitGlobalSetting = 'readonly'
|
||||
variable.eslintExplicitGlobal = undefined
|
||||
variable.eslintExplicitGlobalComments = undefined
|
||||
variable.writeable = false
|
||||
}
|
||||
|
||||
/*
|
||||
* "through" contains all references which definitions cannot be found.
|
||||
* Since we augment the global scope using configuration, we need to update
|
||||
* references and remove the ones that were added by configuration.
|
||||
*/
|
||||
globalScope.through = globalScope.through.filter((reference) => {
|
||||
const name = reference.identifier.name
|
||||
const variable = globalScope.set.get(name)
|
||||
|
||||
if (variable) {
|
||||
/*
|
||||
* Links the variable and the reference.
|
||||
* And this reference is removed from `Scope#through`.
|
||||
*/
|
||||
reference.resolved = variable
|
||||
variable.references.push(reference)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} code
|
||||
* @param {any} espree
|
||||
* @param {any} eslintScope
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function parseSetup(code, espree, eslintScope) {
|
||||
/** @type {Program} */
|
||||
const ast = espree.parse(`(${code})=>{}`, { ecmaVersion })
|
||||
const result = eslintScope.analyze(ast, {
|
||||
ignoreEval: true,
|
||||
nodejsScope: false,
|
||||
ecmaVersion,
|
||||
sourceType: 'script',
|
||||
fallback: AST.getFallbackKeys
|
||||
})
|
||||
|
||||
const variables = /** @type {Variable[]} */ (
|
||||
result.globalScope.childScopes[0].variables
|
||||
)
|
||||
|
||||
return variables.map((v) => v.name)
|
||||
}
|
||||
|
||||
const createRequire =
|
||||
// Added in v12.2.0
|
||||
Module.createRequire ||
|
||||
// Added in v10.12.0, but deprecated in v12.2.0.
|
||||
Module.createRequireFromPath ||
|
||||
// Polyfill - This is not executed on the tests on node@>=10.
|
||||
/**
|
||||
* @param {string} filename
|
||||
*/
|
||||
function (filename) {
|
||||
const mod = new Module(filename)
|
||||
|
||||
mod.filename = filename
|
||||
// @ts-ignore
|
||||
mod.paths = Module._nodeModulePaths(path.dirname(filename))
|
||||
// @ts-ignore
|
||||
mod._compile('module.exports = require;', filename)
|
||||
return mod.exports
|
||||
}
|
||||
|
||||
/** @type { { 'espree'?: any, 'eslint-scope'?: any } } */
|
||||
const modulesCache = {}
|
||||
|
||||
/**
|
||||
* @param {string} p
|
||||
*/
|
||||
function isLinterPath(p) {
|
||||
return (
|
||||
// ESLint 6 and above
|
||||
p.includes(`eslint${path.sep}lib${path.sep}linter${path.sep}linter.js`) ||
|
||||
// ESLint 5
|
||||
p.includes(`eslint${path.sep}lib${path.sep}linter.js`)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Load module from the loaded ESLint.
|
||||
* If the loaded ESLint was not found, just returns `fallback()`.
|
||||
* @param {'espree' | 'eslint-scope'} name
|
||||
* @param { () => any } fallback
|
||||
*/
|
||||
function getESLintModule(name, fallback) {
|
||||
if (!modulesCache[name]) {
|
||||
// Lookup the loaded eslint
|
||||
const linterPath = Object.keys(require.cache).find(isLinterPath)
|
||||
if (linterPath) {
|
||||
try {
|
||||
modulesCache[name] = createRequire(linterPath)(name)
|
||||
} catch (_e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
if (!modulesCache[name]) {
|
||||
modulesCache[name] = fallback()
|
||||
}
|
||||
}
|
||||
|
||||
return modulesCache[name]
|
||||
}
|
98
app_vue/node_modules/eslint-plugin-vue/lib/rules/first-attribute-linebreak.js
generated
vendored
Normal file
98
app_vue/node_modules/eslint-plugin-vue/lib/rules/first-attribute-linebreak.js
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
/**
|
||||
* @fileoverview Enforce the location of first attribute
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
const utils = require('../utils')
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
docs: {
|
||||
description: 'enforce the location of first attribute',
|
||||
categories: ['vue3-strongly-recommended', 'strongly-recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/first-attribute-linebreak.html'
|
||||
},
|
||||
fixable: 'whitespace', // or "code" or "whitespace"
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
multiline: { enum: ['below', 'beside', 'ignore'] },
|
||||
singleline: { enum: ['below', 'beside', 'ignore'] }
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
expected: 'Expected a linebreak before this attribute.',
|
||||
unexpected: 'Expected no linebreak before this attribute.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
/** @type {"below" | "beside" | "ignore"} */
|
||||
const singleline =
|
||||
(context.options[0] && context.options[0].singleline) || 'ignore'
|
||||
/** @type {"below" | "beside" | "ignore"} */
|
||||
const multiline =
|
||||
(context.options[0] && context.options[0].multiline) || 'below'
|
||||
|
||||
const template =
|
||||
context.parserServices.getTemplateBodyTokenStore &&
|
||||
context.parserServices.getTemplateBodyTokenStore()
|
||||
|
||||
/**
|
||||
* Report attribute
|
||||
* @param {VAttribute | VDirective} firstAttribute
|
||||
* @param { "below" | "beside"} location
|
||||
*/
|
||||
function report(firstAttribute, location) {
|
||||
context.report({
|
||||
node: firstAttribute,
|
||||
messageId: location === 'beside' ? 'unexpected' : 'expected',
|
||||
fix(fixer) {
|
||||
const prevToken = template.getTokenBefore(firstAttribute, {
|
||||
includeComments: true
|
||||
})
|
||||
return fixer.replaceTextRange(
|
||||
[prevToken.range[1], firstAttribute.range[0]],
|
||||
location === 'beside' ? ' ' : '\n'
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
VStartTag(node) {
|
||||
const firstAttribute = node.attributes[0]
|
||||
if (!firstAttribute) return
|
||||
|
||||
const lastAttribute = node.attributes[node.attributes.length - 1]
|
||||
|
||||
const location =
|
||||
firstAttribute.loc.start.line === lastAttribute.loc.end.line
|
||||
? singleline
|
||||
: multiline
|
||||
if (location === 'ignore') {
|
||||
return
|
||||
}
|
||||
|
||||
if (location === 'beside') {
|
||||
if (node.loc.start.line === firstAttribute.loc.start.line) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (node.loc.start.line < firstAttribute.loc.start.line) {
|
||||
return
|
||||
}
|
||||
}
|
||||
report(firstAttribute, location)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
12
app_vue/node_modules/eslint-plugin-vue/lib/rules/func-call-spacing.js
generated
vendored
Normal file
12
app_vue/node_modules/eslint-plugin-vue/lib/rules/func-call-spacing.js
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('func-call-spacing', {
|
||||
skipDynamicArguments: true,
|
||||
applyDocument: true
|
||||
})
|
146
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-button-has-type.js
generated
vendored
Normal file
146
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-button-has-type.js
generated
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
/**
|
||||
* @fileoverview Disallow usage of button without an explicit type attribute
|
||||
* @author Jonathan Santerre <jonathan@santerre.dev>
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const optionDefaults = {
|
||||
button: true,
|
||||
submit: true,
|
||||
reset: true
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description:
|
||||
'disallow usage of button without an explicit type attribute',
|
||||
categories: null,
|
||||
url: 'https://eslint.vuejs.org/rules/html-button-has-type.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
button: {
|
||||
default: optionDefaults.button,
|
||||
type: 'boolean'
|
||||
},
|
||||
submit: {
|
||||
default: optionDefaults.submit,
|
||||
type: 'boolean'
|
||||
},
|
||||
reset: {
|
||||
default: optionDefaults.reset,
|
||||
type: 'boolean'
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
missingTypeAttribute: 'Missing an explicit type attribute for button.',
|
||||
invalidTypeAttribute:
|
||||
'{{value}} is an invalid value for button type attribute.',
|
||||
forbiddenTypeAttribute:
|
||||
'{{value}} is a forbidden value for button type attribute.',
|
||||
emptyTypeAttribute: 'A value must be set for button type attribute.'
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {RuleContext} context - The rule context.
|
||||
* @returns {RuleListener} AST event handlers.
|
||||
*/
|
||||
create(context) {
|
||||
/**
|
||||
* @typedef {object} Configuration
|
||||
* @property {boolean} button
|
||||
* @property {boolean} submit
|
||||
* @property {boolean} reset
|
||||
*/
|
||||
/** @type {Configuration} */
|
||||
const configuration = Object.assign({}, optionDefaults, context.options[0])
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} type
|
||||
* @returns {type is 'button' | 'submit' | 'reset'}
|
||||
*/
|
||||
function isButtonType(type) {
|
||||
return type === 'button' || type === 'submit' || type === 'reset'
|
||||
}
|
||||
/**
|
||||
* @param {ASTNode} node
|
||||
* @param {string} messageId
|
||||
* @param {any} [data]
|
||||
*/
|
||||
function report(node, messageId, data) {
|
||||
context.report({
|
||||
node,
|
||||
messageId,
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VAttribute} attribute
|
||||
*/
|
||||
function validateAttribute(attribute) {
|
||||
const value = attribute.value
|
||||
if (!value || !value.value) {
|
||||
report(value || attribute, 'emptyTypeAttribute')
|
||||
return
|
||||
}
|
||||
|
||||
const strValue = value.value
|
||||
if (!isButtonType(strValue)) {
|
||||
report(value, 'invalidTypeAttribute', { value: strValue })
|
||||
} else if (!configuration[strValue]) {
|
||||
report(value, 'forbiddenTypeAttribute', { value: strValue })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VDirective} directive
|
||||
*/
|
||||
function validateDirective(directive) {
|
||||
const value = directive.value
|
||||
if (!value || !value.expression) {
|
||||
report(value || directive, 'emptyTypeAttribute')
|
||||
}
|
||||
}
|
||||
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
/**
|
||||
* @param {VElement} node
|
||||
*/
|
||||
"VElement[rawName='button']"(node) {
|
||||
const typeAttr = utils.getAttribute(node, 'type')
|
||||
if (typeAttr) {
|
||||
validateAttribute(typeAttr)
|
||||
return
|
||||
}
|
||||
const typeDir = utils.getDirective(node, 'bind', 'type')
|
||||
if (typeDir) {
|
||||
validateDirective(typeDir)
|
||||
return
|
||||
}
|
||||
|
||||
report(node.startTag, 'missingTypeAttribute')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
115
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-closing-bracket-newline.js
generated
vendored
Normal file
115
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-closing-bracket-newline.js
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @author Toru Nagashima
|
||||
* @copyright 2016 Toru Nagashima. All rights reserved.
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {number} lineBreaks
|
||||
*/
|
||||
function getPhrase(lineBreaks) {
|
||||
switch (lineBreaks) {
|
||||
case 0:
|
||||
return 'no line breaks'
|
||||
case 1:
|
||||
return '1 line break'
|
||||
default:
|
||||
return `${lineBreaks} line breaks`
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
docs: {
|
||||
description:
|
||||
"require or disallow a line break before tag's closing brackets",
|
||||
categories: ['vue3-strongly-recommended', 'strongly-recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/html-closing-bracket-newline.html'
|
||||
},
|
||||
fixable: 'whitespace',
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
singleline: { enum: ['always', 'never'] },
|
||||
multiline: { enum: ['always', 'never'] }
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const options = Object.assign(
|
||||
{},
|
||||
{
|
||||
singleline: 'never',
|
||||
multiline: 'always'
|
||||
},
|
||||
context.options[0] || {}
|
||||
)
|
||||
const template =
|
||||
context.parserServices.getTemplateBodyTokenStore &&
|
||||
context.parserServices.getTemplateBodyTokenStore()
|
||||
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
/** @param {VStartTag | VEndTag} node */
|
||||
'VStartTag, VEndTag'(node) {
|
||||
const closingBracketToken = template.getLastToken(node)
|
||||
if (
|
||||
closingBracketToken.type !== 'HTMLSelfClosingTagClose' &&
|
||||
closingBracketToken.type !== 'HTMLTagClose'
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const prevToken = template.getTokenBefore(closingBracketToken)
|
||||
const type =
|
||||
node.loc.start.line === prevToken.loc.end.line
|
||||
? 'singleline'
|
||||
: 'multiline'
|
||||
const expectedLineBreaks = options[type] === 'always' ? 1 : 0
|
||||
const actualLineBreaks =
|
||||
closingBracketToken.loc.start.line - prevToken.loc.end.line
|
||||
|
||||
if (actualLineBreaks !== expectedLineBreaks) {
|
||||
context.report({
|
||||
node,
|
||||
loc: {
|
||||
start: prevToken.loc.end,
|
||||
end: closingBracketToken.loc.start
|
||||
},
|
||||
message:
|
||||
'Expected {{expected}} before closing bracket, but {{actual}} found.',
|
||||
data: {
|
||||
expected: getPhrase(expectedLineBreaks),
|
||||
actual: getPhrase(actualLineBreaks)
|
||||
},
|
||||
fix(fixer) {
|
||||
/** @type {Range} */
|
||||
const range = [prevToken.range[1], closingBracketToken.range[0]]
|
||||
const text = '\n'.repeat(expectedLineBreaks)
|
||||
return fixer.replaceTextRange(range, text)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
137
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-closing-bracket-spacing.js
generated
vendored
Normal file
137
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-closing-bracket-spacing.js
generated
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
/**
|
||||
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @typedef { {startTag?:"always"|"never",endTag?:"always"|"never",selfClosingTag?:"always"|"never"} } Options
|
||||
*/
|
||||
|
||||
/**
|
||||
* Normalize options.
|
||||
* @param {Options} options The options user configured.
|
||||
* @param {ParserServices.TokenStore} tokens The token store of template body.
|
||||
* @returns {Options & { detectType: (node: VStartTag | VEndTag) => 'never' | 'always' | null }} The normalized options.
|
||||
*/
|
||||
function parseOptions(options, tokens) {
|
||||
const opts = Object.assign(
|
||||
{
|
||||
startTag: 'never',
|
||||
endTag: 'never',
|
||||
selfClosingTag: 'always'
|
||||
},
|
||||
options
|
||||
)
|
||||
return Object.assign(opts, {
|
||||
/**
|
||||
* @param {VStartTag | VEndTag} node
|
||||
* @returns {'never' | 'always' | null}
|
||||
*/
|
||||
detectType(node) {
|
||||
const openType = tokens.getFirstToken(node).type
|
||||
const closeType = tokens.getLastToken(node).type
|
||||
|
||||
if (openType === 'HTMLEndTagOpen' && closeType === 'HTMLTagClose') {
|
||||
return opts.endTag
|
||||
}
|
||||
if (openType === 'HTMLTagOpen' && closeType === 'HTMLTagClose') {
|
||||
return opts.startTag
|
||||
}
|
||||
if (
|
||||
openType === 'HTMLTagOpen' &&
|
||||
closeType === 'HTMLSelfClosingTagClose'
|
||||
) {
|
||||
return opts.selfClosingTag
|
||||
}
|
||||
return null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
docs: {
|
||||
description: "require or disallow a space before tag's closing brackets",
|
||||
categories: ['vue3-strongly-recommended', 'strongly-recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/html-closing-bracket-spacing.html'
|
||||
},
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
startTag: { enum: ['always', 'never'] },
|
||||
endTag: { enum: ['always', 'never'] },
|
||||
selfClosingTag: { enum: ['always', 'never'] }
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
fixable: 'whitespace'
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const sourceCode = context.getSourceCode()
|
||||
const tokens =
|
||||
context.parserServices.getTemplateBodyTokenStore &&
|
||||
context.parserServices.getTemplateBodyTokenStore()
|
||||
const options = parseOptions(context.options[0], tokens)
|
||||
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
/** @param {VStartTag | VEndTag} node */
|
||||
'VStartTag, VEndTag'(node) {
|
||||
const type = options.detectType(node)
|
||||
const lastToken = tokens.getLastToken(node)
|
||||
const prevToken = tokens.getLastToken(node, 1)
|
||||
|
||||
// Skip if EOF exists in the tag or linebreak exists before `>`.
|
||||
if (
|
||||
type == null ||
|
||||
prevToken == null ||
|
||||
prevToken.loc.end.line !== lastToken.loc.start.line
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check and report.
|
||||
const hasSpace = prevToken.range[1] !== lastToken.range[0]
|
||||
if (type === 'always' && !hasSpace) {
|
||||
context.report({
|
||||
node,
|
||||
loc: lastToken.loc,
|
||||
message: "Expected a space before '{{bracket}}', but not found.",
|
||||
data: { bracket: sourceCode.getText(lastToken) },
|
||||
fix: (fixer) => fixer.insertTextBefore(lastToken, ' ')
|
||||
})
|
||||
} else if (type === 'never' && hasSpace) {
|
||||
context.report({
|
||||
node,
|
||||
loc: {
|
||||
start: prevToken.loc.end,
|
||||
end: lastToken.loc.end
|
||||
},
|
||||
message: "Expected no space before '{{bracket}}', but found.",
|
||||
data: { bracket: sourceCode.getText(lastToken) },
|
||||
fix: (fixer) =>
|
||||
fixer.removeRange([prevToken.range[1], lastToken.range[0]])
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
215
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-comment-content-newline.js
generated
vendored
Normal file
215
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-comment-content-newline.js
generated
vendored
Normal file
@ -0,0 +1,215 @@
|
||||
/**
|
||||
* @author Yosuke ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const htmlComments = require('../utils/html-comments')
|
||||
|
||||
/**
|
||||
* @typedef { import('../utils/html-comments').ParsedHTMLComment } ParsedHTMLComment
|
||||
*/
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {any} param
|
||||
*/
|
||||
function parseOption(param) {
|
||||
if (param && typeof param === 'string') {
|
||||
return {
|
||||
singleline: param,
|
||||
multiline: param
|
||||
}
|
||||
}
|
||||
return Object.assign(
|
||||
{
|
||||
singleline: 'never',
|
||||
multiline: 'always'
|
||||
},
|
||||
param
|
||||
)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
|
||||
docs: {
|
||||
description: 'enforce unified line brake in HTML comments',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/html-comment-content-newline.html'
|
||||
},
|
||||
fixable: 'whitespace',
|
||||
schema: [
|
||||
{
|
||||
anyOf: [
|
||||
{
|
||||
enum: ['always', 'never']
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
singleline: { enum: ['always', 'never', 'ignore'] },
|
||||
multiline: { enum: ['always', 'never', 'ignore'] }
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
exceptions: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
expectedAfterHTMLCommentOpen: "Expected line break after '<!--'.",
|
||||
expectedBeforeHTMLCommentOpen: "Expected line break before '-->'.",
|
||||
expectedAfterExceptionBlock: 'Expected line break after exception block.',
|
||||
expectedBeforeExceptionBlock:
|
||||
'Expected line break before exception block.',
|
||||
unexpectedAfterHTMLCommentOpen: "Unexpected line breaks after '<!--'.",
|
||||
unexpectedBeforeHTMLCommentOpen: "Unexpected line breaks before '-->'."
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const option = parseOption(context.options[0])
|
||||
return htmlComments.defineVisitor(
|
||||
context,
|
||||
context.options[1],
|
||||
(comment) => {
|
||||
const { value, openDecoration, closeDecoration } = comment
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
|
||||
const startLine = openDecoration
|
||||
? openDecoration.loc.end.line
|
||||
: value.loc.start.line
|
||||
const endLine = closeDecoration
|
||||
? closeDecoration.loc.start.line
|
||||
: value.loc.end.line
|
||||
const newlineType =
|
||||
startLine === endLine ? option.singleline : option.multiline
|
||||
if (newlineType === 'ignore') {
|
||||
return
|
||||
}
|
||||
checkCommentOpen(comment, newlineType !== 'never')
|
||||
checkCommentClose(comment, newlineType !== 'never')
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Reports the newline before the contents of a given comment if it's invalid.
|
||||
* @param {ParsedHTMLComment} comment - comment data.
|
||||
* @param {boolean} requireNewline - `true` if line breaks are required.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkCommentOpen(comment, requireNewline) {
|
||||
const { value, openDecoration, open } = comment
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
const beforeToken = openDecoration || open
|
||||
|
||||
if (requireNewline) {
|
||||
if (beforeToken.loc.end.line < value.loc.start.line) {
|
||||
// Is valid
|
||||
return
|
||||
}
|
||||
context.report({
|
||||
loc: {
|
||||
start: beforeToken.loc.end,
|
||||
end: value.loc.start
|
||||
},
|
||||
messageId: openDecoration
|
||||
? 'expectedAfterExceptionBlock'
|
||||
: 'expectedAfterHTMLCommentOpen',
|
||||
fix: openDecoration
|
||||
? undefined
|
||||
: (fixer) => fixer.insertTextAfter(beforeToken, '\n')
|
||||
})
|
||||
} else {
|
||||
if (beforeToken.loc.end.line === value.loc.start.line) {
|
||||
// Is valid
|
||||
return
|
||||
}
|
||||
context.report({
|
||||
loc: {
|
||||
start: beforeToken.loc.end,
|
||||
end: value.loc.start
|
||||
},
|
||||
messageId: 'unexpectedAfterHTMLCommentOpen',
|
||||
fix: (fixer) =>
|
||||
fixer.replaceTextRange([beforeToken.range[1], value.range[0]], ' ')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports the space after the contents of a given comment if it's invalid.
|
||||
* @param {ParsedHTMLComment} comment - comment data.
|
||||
* @param {boolean} requireNewline - `true` if line breaks are required.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkCommentClose(comment, requireNewline) {
|
||||
const { value, closeDecoration, close } = comment
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
const afterToken = closeDecoration || close
|
||||
|
||||
if (requireNewline) {
|
||||
if (value.loc.end.line < afterToken.loc.start.line) {
|
||||
// Is valid
|
||||
return
|
||||
}
|
||||
context.report({
|
||||
loc: {
|
||||
start: value.loc.end,
|
||||
end: afterToken.loc.start
|
||||
},
|
||||
messageId: closeDecoration
|
||||
? 'expectedBeforeExceptionBlock'
|
||||
: 'expectedBeforeHTMLCommentOpen',
|
||||
fix: closeDecoration
|
||||
? undefined
|
||||
: (fixer) => fixer.insertTextBefore(afterToken, '\n')
|
||||
})
|
||||
} else {
|
||||
if (value.loc.end.line === afterToken.loc.start.line) {
|
||||
// Is valid
|
||||
return
|
||||
}
|
||||
context.report({
|
||||
loc: {
|
||||
start: value.loc.end,
|
||||
end: afterToken.loc.start
|
||||
},
|
||||
messageId: 'unexpectedBeforeHTMLCommentOpen',
|
||||
fix: (fixer) =>
|
||||
fixer.replaceTextRange([value.range[1], afterToken.range[0]], ' ')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
179
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-comment-content-spacing.js
generated
vendored
Normal file
179
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-comment-content-spacing.js
generated
vendored
Normal file
@ -0,0 +1,179 @@
|
||||
/**
|
||||
* @author Yosuke ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const htmlComments = require('../utils/html-comments')
|
||||
|
||||
/**
|
||||
* @typedef { import('../utils/html-comments').ParsedHTMLComment } ParsedHTMLComment
|
||||
*/
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
|
||||
docs: {
|
||||
description: 'enforce unified spacing in HTML comments',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/html-comment-content-spacing.html'
|
||||
},
|
||||
fixable: 'whitespace',
|
||||
schema: [
|
||||
{
|
||||
enum: ['always', 'never']
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
exceptions: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
expectedAfterHTMLCommentOpen: "Expected space after '<!--'.",
|
||||
expectedBeforeHTMLCommentOpen: "Expected space before '-->'.",
|
||||
expectedAfterExceptionBlock: 'Expected space after exception block.',
|
||||
expectedBeforeExceptionBlock: 'Expected space before exception block.',
|
||||
unexpectedAfterHTMLCommentOpen: "Unexpected space after '<!--'.",
|
||||
unexpectedBeforeHTMLCommentOpen: "Unexpected space before '-->'."
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
// Unless the first option is never, require a space
|
||||
const requireSpace = context.options[0] !== 'never'
|
||||
return htmlComments.defineVisitor(
|
||||
context,
|
||||
context.options[1],
|
||||
(comment) => {
|
||||
checkCommentOpen(comment)
|
||||
checkCommentClose(comment)
|
||||
},
|
||||
{ includeDirectives: true }
|
||||
)
|
||||
|
||||
/**
|
||||
* Reports the space before the contents of a given comment if it's invalid.
|
||||
* @param {ParsedHTMLComment} comment - comment data.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkCommentOpen(comment) {
|
||||
const { value, openDecoration, open } = comment
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
const beforeToken = openDecoration || open
|
||||
if (beforeToken.loc.end.line !== value.loc.start.line) {
|
||||
// Ignore newline
|
||||
return
|
||||
}
|
||||
|
||||
if (requireSpace) {
|
||||
if (beforeToken.range[1] < value.range[0]) {
|
||||
// Is valid
|
||||
return
|
||||
}
|
||||
context.report({
|
||||
loc: {
|
||||
start: beforeToken.loc.end,
|
||||
end: value.loc.start
|
||||
},
|
||||
messageId: openDecoration
|
||||
? 'expectedAfterExceptionBlock'
|
||||
: 'expectedAfterHTMLCommentOpen',
|
||||
fix: openDecoration
|
||||
? undefined
|
||||
: (fixer) => fixer.insertTextAfter(beforeToken, ' ')
|
||||
})
|
||||
} else {
|
||||
if (openDecoration) {
|
||||
// Ignore expection block
|
||||
return
|
||||
}
|
||||
if (beforeToken.range[1] === value.range[0]) {
|
||||
// Is valid
|
||||
return
|
||||
}
|
||||
context.report({
|
||||
loc: {
|
||||
start: beforeToken.loc.end,
|
||||
end: value.loc.start
|
||||
},
|
||||
messageId: 'unexpectedAfterHTMLCommentOpen',
|
||||
fix: (fixer) =>
|
||||
fixer.removeRange([beforeToken.range[1], value.range[0]])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports the space after the contents of a given comment if it's invalid.
|
||||
* @param {ParsedHTMLComment} comment - comment data.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkCommentClose(comment) {
|
||||
const { value, closeDecoration, close } = comment
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
const afterToken = closeDecoration || close
|
||||
if (value.loc.end.line !== afterToken.loc.start.line) {
|
||||
// Ignore newline
|
||||
return
|
||||
}
|
||||
|
||||
if (requireSpace) {
|
||||
if (value.range[1] < afterToken.range[0]) {
|
||||
// Is valid
|
||||
return
|
||||
}
|
||||
context.report({
|
||||
loc: {
|
||||
start: value.loc.end,
|
||||
end: afterToken.loc.start
|
||||
},
|
||||
messageId: closeDecoration
|
||||
? 'expectedBeforeExceptionBlock'
|
||||
: 'expectedBeforeHTMLCommentOpen',
|
||||
fix: closeDecoration
|
||||
? undefined
|
||||
: (fixer) => fixer.insertTextBefore(afterToken, ' ')
|
||||
})
|
||||
} else {
|
||||
if (closeDecoration) {
|
||||
// Ignore expection block
|
||||
return
|
||||
}
|
||||
if (value.range[1] === afterToken.range[0]) {
|
||||
// Is valid
|
||||
return
|
||||
}
|
||||
context.report({
|
||||
loc: {
|
||||
start: value.loc.end,
|
||||
end: afterToken.loc.start
|
||||
},
|
||||
messageId: 'unexpectedBeforeHTMLCommentOpen',
|
||||
fix: (fixer) =>
|
||||
fixer.removeRange([value.range[1], afterToken.range[0]])
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
258
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-comment-indent.js
generated
vendored
Normal file
258
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-comment-indent.js
generated
vendored
Normal file
@ -0,0 +1,258 @@
|
||||
/**
|
||||
* @author Yosuke ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const htmlComments = require('../utils/html-comments')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Normalize options.
|
||||
* @param {number|"tab"|undefined} type The type of indentation.
|
||||
* @returns { { indentChar: string, indentSize: number, indentText: string } } Normalized options.
|
||||
*/
|
||||
function parseOptions(type) {
|
||||
const ret = {
|
||||
indentChar: ' ',
|
||||
indentSize: 2,
|
||||
indentText: ''
|
||||
}
|
||||
|
||||
if (Number.isSafeInteger(type)) {
|
||||
ret.indentSize = Number(type)
|
||||
} else if (type === 'tab') {
|
||||
ret.indentChar = '\t'
|
||||
ret.indentSize = 1
|
||||
}
|
||||
ret.indentText = ret.indentChar.repeat(ret.indentSize)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} s
|
||||
* @param {string} [unitChar]
|
||||
*/
|
||||
function toDisplay(s, unitChar) {
|
||||
if (s.length === 0 && unitChar) {
|
||||
return `0 ${toUnit(unitChar)}s`
|
||||
}
|
||||
const char = s[0]
|
||||
if (char === ' ' || char === '\t') {
|
||||
if (s.split('').every((c) => c === char)) {
|
||||
return `${s.length} ${toUnit(char)}${s.length === 1 ? '' : 's'}`
|
||||
}
|
||||
}
|
||||
|
||||
return JSON.stringify(s)
|
||||
}
|
||||
|
||||
/** @param {string} char */
|
||||
function toUnit(char) {
|
||||
if (char === '\t') {
|
||||
return 'tab'
|
||||
}
|
||||
if (char === ' ') {
|
||||
return 'space'
|
||||
}
|
||||
return JSON.stringify(char)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
|
||||
docs: {
|
||||
description: 'enforce consistent indentation in HTML comments',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/html-comment-indent.html'
|
||||
},
|
||||
fixable: 'whitespace',
|
||||
schema: [
|
||||
{
|
||||
anyOf: [{ type: 'integer', minimum: 0 }, { enum: ['tab'] }]
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
unexpectedBaseIndentation:
|
||||
'Expected base point indentation of {{expected}}, but found {{actual}}.',
|
||||
missingBaseIndentation:
|
||||
'Expected base point indentation of {{expected}}, but not found.',
|
||||
unexpectedIndentationCharacter:
|
||||
'Expected {{expected}} character, but found {{actual}} character.',
|
||||
unexpectedIndentation:
|
||||
'Expected indentation of {{expected}} but found {{actual}}.',
|
||||
unexpectedRelativeIndentation:
|
||||
'Expected relative indentation of {{expected}} but found {{actual}}.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const options = parseOptions(context.options[0])
|
||||
const sourceCode = context.getSourceCode()
|
||||
return htmlComments.defineVisitor(
|
||||
context,
|
||||
null,
|
||||
(comment) => {
|
||||
const baseIndentText = getLineIndentText(comment.open.loc.start.line)
|
||||
let endLine
|
||||
if (comment.value) {
|
||||
const startLine = comment.value.loc.start.line
|
||||
endLine = comment.value.loc.end.line
|
||||
|
||||
const checkStartLine =
|
||||
comment.open.loc.end.line === startLine ? startLine + 1 : startLine
|
||||
|
||||
for (let line = checkStartLine; line <= endLine; line++) {
|
||||
validateIndentForLine(line, baseIndentText, 1)
|
||||
}
|
||||
} else {
|
||||
endLine = comment.open.loc.end.line
|
||||
}
|
||||
|
||||
if (endLine < comment.close.loc.start.line) {
|
||||
// `-->`
|
||||
validateIndentForLine(comment.close.loc.start.line, baseIndentText, 0)
|
||||
}
|
||||
},
|
||||
{ includeDirectives: true }
|
||||
)
|
||||
|
||||
/**
|
||||
* Checks whether the given line is a blank line.
|
||||
* @param {number} line The number of line. Begins with 1.
|
||||
* @returns {boolean} `true` if the given line is a blank line
|
||||
*/
|
||||
function isEmptyLine(line) {
|
||||
const lineText = sourceCode.getLines()[line - 1]
|
||||
return !lineText.trim()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actual indentation of the given line.
|
||||
* @param {number} line The number of line. Begins with 1.
|
||||
* @returns {string} The actual indentation text
|
||||
*/
|
||||
function getLineIndentText(line) {
|
||||
const lineText = sourceCode.getLines()[line - 1]
|
||||
const charIndex = lineText.search(/\S/)
|
||||
// already checked
|
||||
// if (charIndex < 0) {
|
||||
// return lineText
|
||||
// }
|
||||
return lineText.slice(0, charIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the function which fixes the problem.
|
||||
* @param {number} line The number of line.
|
||||
* @param {string} actualIndentText The actual indentation text.
|
||||
* @param {string} expectedIndentText The expected indentation text.
|
||||
* @returns { (fixer: RuleFixer) => Fix } The defined function.
|
||||
*/
|
||||
function defineFix(line, actualIndentText, expectedIndentText) {
|
||||
return (fixer) => {
|
||||
const start = sourceCode.getIndexFromLoc({
|
||||
line,
|
||||
column: 0
|
||||
})
|
||||
return fixer.replaceTextRange(
|
||||
[start, start + actualIndentText.length],
|
||||
expectedIndentText
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the indentation of a line.
|
||||
* @param {number} line The number of line. Begins with 1.
|
||||
* @param {string} baseIndentText The expected base indentation text.
|
||||
* @param {number} offset The number of the indentation offset.
|
||||
*/
|
||||
function validateIndentForLine(line, baseIndentText, offset) {
|
||||
if (isEmptyLine(line)) {
|
||||
return
|
||||
}
|
||||
const actualIndentText = getLineIndentText(line)
|
||||
|
||||
const expectedOffsetIndentText = options.indentText.repeat(offset)
|
||||
const expectedIndentText = baseIndentText + expectedOffsetIndentText
|
||||
|
||||
// validate base indent
|
||||
if (
|
||||
baseIndentText &&
|
||||
(actualIndentText.length < baseIndentText.length ||
|
||||
!actualIndentText.startsWith(baseIndentText))
|
||||
) {
|
||||
context.report({
|
||||
loc: {
|
||||
start: { line, column: 0 },
|
||||
end: { line, column: actualIndentText.length }
|
||||
},
|
||||
messageId: actualIndentText
|
||||
? 'unexpectedBaseIndentation'
|
||||
: 'missingBaseIndentation',
|
||||
data: {
|
||||
expected: toDisplay(baseIndentText),
|
||||
actual: toDisplay(actualIndentText.slice(0, baseIndentText.length))
|
||||
},
|
||||
fix: defineFix(line, actualIndentText, expectedIndentText)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const actualOffsetIndentText = actualIndentText.slice(
|
||||
baseIndentText.length
|
||||
)
|
||||
|
||||
// validate indent charctor
|
||||
for (let i = 0; i < actualOffsetIndentText.length; ++i) {
|
||||
if (actualOffsetIndentText[i] !== options.indentChar) {
|
||||
context.report({
|
||||
loc: {
|
||||
start: { line, column: baseIndentText.length + i },
|
||||
end: { line, column: baseIndentText.length + i + 1 }
|
||||
},
|
||||
messageId: 'unexpectedIndentationCharacter',
|
||||
data: {
|
||||
expected: toUnit(options.indentChar),
|
||||
actual: toUnit(actualOffsetIndentText[i])
|
||||
},
|
||||
fix: defineFix(line, actualIndentText, expectedIndentText)
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// validate indent length
|
||||
if (actualOffsetIndentText.length !== expectedOffsetIndentText.length) {
|
||||
context.report({
|
||||
loc: {
|
||||
start: { line, column: baseIndentText.length },
|
||||
end: { line, column: actualIndentText.length }
|
||||
},
|
||||
messageId: baseIndentText
|
||||
? 'unexpectedRelativeIndentation'
|
||||
: 'unexpectedIndentation',
|
||||
data: {
|
||||
expected: toDisplay(expectedOffsetIndentText, options.indentChar),
|
||||
actual: toDisplay(actualOffsetIndentText, options.indentChar)
|
||||
},
|
||||
fix: defineFix(line, actualIndentText, expectedIndentText)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
64
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-end-tags.js
generated
vendored
Normal file
64
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-end-tags.js
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @author Toru Nagashima
|
||||
* @copyright 2017 Toru Nagashima. All rights reserved.
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'enforce end tag style',
|
||||
categories: ['vue3-strongly-recommended', 'strongly-recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/html-end-tags.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: []
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
let hasInvalidEOF = false
|
||||
|
||||
return utils.defineTemplateBodyVisitor(
|
||||
context,
|
||||
{
|
||||
VElement(node) {
|
||||
if (hasInvalidEOF) {
|
||||
return
|
||||
}
|
||||
|
||||
const name = node.name
|
||||
const isVoid = utils.isHtmlVoidElementName(name)
|
||||
const isSelfClosing = node.startTag.selfClosing
|
||||
const hasEndTag = node.endTag != null
|
||||
|
||||
if (!isVoid && !hasEndTag && !isSelfClosing) {
|
||||
context.report({
|
||||
node: node.startTag,
|
||||
loc: node.startTag.loc,
|
||||
message: "'<{{name}}>' should have end tag.",
|
||||
data: { name },
|
||||
fix: (fixer) => fixer.insertTextAfter(node, `</${name}>`)
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
Program(node) {
|
||||
hasInvalidEOF = utils.hasInvalidEOF(node)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
81
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-indent.js
generated
vendored
Normal file
81
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-indent.js
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
/**
|
||||
* @author Toru Nagashima
|
||||
* @copyright 2016 Toru Nagashima. All rights reserved.
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const indentCommon = require('../utils/indent-common')
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const tokenStore =
|
||||
context.parserServices.getTemplateBodyTokenStore &&
|
||||
context.parserServices.getTemplateBodyTokenStore()
|
||||
const visitor = indentCommon.defineVisitor(context, tokenStore, {
|
||||
baseIndent: 1
|
||||
})
|
||||
|
||||
return utils.defineTemplateBodyVisitor(context, visitor)
|
||||
},
|
||||
meta: {
|
||||
type: 'layout',
|
||||
docs: {
|
||||
description: 'enforce consistent indentation in `<template>`',
|
||||
categories: ['vue3-strongly-recommended', 'strongly-recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/html-indent.html'
|
||||
},
|
||||
fixable: 'whitespace',
|
||||
schema: [
|
||||
{
|
||||
anyOf: [{ type: 'integer', minimum: 1 }, { enum: ['tab'] }]
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
attribute: { type: 'integer', minimum: 0 },
|
||||
baseIndent: { type: 'integer', minimum: 0 },
|
||||
closeBracket: {
|
||||
anyOf: [
|
||||
{ type: 'integer', minimum: 0 },
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
startTag: { type: 'integer', minimum: 0 },
|
||||
endTag: { type: 'integer', minimum: 0 },
|
||||
selfClosingTag: { type: 'integer', minimum: 0 }
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
},
|
||||
switchCase: { type: 'integer', minimum: 0 },
|
||||
alignAttributesVertically: { type: 'boolean' },
|
||||
ignores: {
|
||||
type: 'array',
|
||||
items: {
|
||||
allOf: [
|
||||
{ type: 'string' },
|
||||
{ not: { type: 'string', pattern: ':exit$' } },
|
||||
{ not: { type: 'string', pattern: '^\\s*$' } }
|
||||
]
|
||||
},
|
||||
uniqueItems: true,
|
||||
additionalItems: false
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
107
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-quotes.js
generated
vendored
Normal file
107
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-quotes.js
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @author Toru Nagashima
|
||||
* @copyright 2017 Toru Nagashima. All rights reserved.
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
docs: {
|
||||
description: 'enforce quotes style of HTML attributes',
|
||||
categories: ['vue3-strongly-recommended', 'strongly-recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/html-quotes.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [
|
||||
{ enum: ['double', 'single'] },
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
avoidEscape: {
|
||||
type: 'boolean'
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const sourceCode = context.getSourceCode()
|
||||
const double = context.options[0] !== 'single'
|
||||
const avoidEscape =
|
||||
context.options[1] && context.options[1].avoidEscape === true
|
||||
const quoteChar = double ? '"' : "'"
|
||||
const quoteName = double ? 'double quotes' : 'single quotes'
|
||||
/** @type {boolean} */
|
||||
let hasInvalidEOF
|
||||
|
||||
return utils.defineTemplateBodyVisitor(
|
||||
context,
|
||||
{
|
||||
'VAttribute[value!=null]'(node) {
|
||||
if (hasInvalidEOF) {
|
||||
return
|
||||
}
|
||||
|
||||
const text = sourceCode.getText(node.value)
|
||||
const firstChar = text[0]
|
||||
|
||||
if (firstChar !== quoteChar) {
|
||||
const quoted = firstChar === "'" || firstChar === '"'
|
||||
if (avoidEscape && quoted) {
|
||||
const contentText = text.slice(1, -1)
|
||||
if (contentText.includes(quoteChar)) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
context.report({
|
||||
node: node.value,
|
||||
loc: node.value.loc,
|
||||
message: 'Expected to be enclosed by {{kind}}.',
|
||||
data: { kind: quoteName },
|
||||
fix(fixer) {
|
||||
const contentText = quoted ? text.slice(1, -1) : text
|
||||
|
||||
const fixToDouble =
|
||||
avoidEscape && !quoted && contentText.includes(quoteChar)
|
||||
? double
|
||||
? contentText.includes("'")
|
||||
: !contentText.includes('"')
|
||||
: double
|
||||
|
||||
const quotePattern = fixToDouble ? /"/g : /'/g
|
||||
const quoteEscaped = fixToDouble ? '"' : '''
|
||||
const fixQuoteChar = fixToDouble ? '"' : "'"
|
||||
|
||||
const replacement =
|
||||
fixQuoteChar +
|
||||
contentText.replace(quotePattern, quoteEscaped) +
|
||||
fixQuoteChar
|
||||
return fixer.replaceText(node.value, replacement)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
Program(node) {
|
||||
hasInvalidEOF = utils.hasInvalidEOF(node)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
224
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-self-closing.js
generated
vendored
Normal file
224
app_vue/node_modules/eslint-plugin-vue/lib/rules/html-self-closing.js
generated
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
/**
|
||||
* @author Toru Nagashima
|
||||
* @copyright 2016 Toru Nagashima. All rights reserved.
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* These strings wil be displayed in error messages.
|
||||
*/
|
||||
const ELEMENT_TYPE_MESSAGES = Object.freeze({
|
||||
NORMAL: 'HTML elements',
|
||||
VOID: 'HTML void elements',
|
||||
COMPONENT: 'Vue.js custom components',
|
||||
SVG: 'SVG elements',
|
||||
MATH: 'MathML elements',
|
||||
UNKNOWN: 'unknown elements'
|
||||
})
|
||||
|
||||
/**
|
||||
* @typedef {object} Options
|
||||
* @property {'always' | 'never'} NORMAL
|
||||
* @property {'always' | 'never'} VOID
|
||||
* @property {'always' | 'never'} COMPONENT
|
||||
* @property {'always' | 'never'} SVG
|
||||
* @property {'always' | 'never'} MATH
|
||||
* @property {null} UNKNOWN
|
||||
*/
|
||||
|
||||
/**
|
||||
* Normalize the given options.
|
||||
* @param {any} options The raw options object.
|
||||
* @returns {Options} Normalized options.
|
||||
*/
|
||||
function parseOptions(options) {
|
||||
return {
|
||||
NORMAL: (options && options.html && options.html.normal) || 'always',
|
||||
VOID: (options && options.html && options.html.void) || 'never',
|
||||
COMPONENT: (options && options.html && options.html.component) || 'always',
|
||||
SVG: (options && options.svg) || 'always',
|
||||
MATH: (options && options.math) || 'always',
|
||||
UNKNOWN: null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the elementType of the given element.
|
||||
* @param {VElement} node The element node to get.
|
||||
* @returns {keyof Options} The elementType of the element.
|
||||
*/
|
||||
function getElementType(node) {
|
||||
if (utils.isCustomComponent(node)) {
|
||||
return 'COMPONENT'
|
||||
}
|
||||
if (utils.isHtmlElementNode(node)) {
|
||||
if (utils.isHtmlVoidElementName(node.name)) {
|
||||
return 'VOID'
|
||||
}
|
||||
return 'NORMAL'
|
||||
}
|
||||
if (utils.isSvgElementNode(node)) {
|
||||
return 'SVG'
|
||||
}
|
||||
if (utils.isMathMLElementNode(node)) {
|
||||
return 'MATH'
|
||||
}
|
||||
return 'UNKNOWN'
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given element is empty or not.
|
||||
* This ignores whitespaces, doesn't ignore comments.
|
||||
* @param {VElement} node The element node to check.
|
||||
* @param {SourceCode} sourceCode The source code object of the current context.
|
||||
* @returns {boolean} `true` if the element is empty.
|
||||
*/
|
||||
function isEmpty(node, sourceCode) {
|
||||
const start = node.startTag.range[1]
|
||||
const end = node.endTag != null ? node.endTag.range[0] : node.range[1]
|
||||
|
||||
return sourceCode.text.slice(start, end).trim() === ''
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
docs: {
|
||||
description: 'enforce self-closing style',
|
||||
categories: ['vue3-strongly-recommended', 'strongly-recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/html-self-closing.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: {
|
||||
definitions: {
|
||||
optionValue: {
|
||||
enum: ['always', 'never', 'any']
|
||||
}
|
||||
},
|
||||
type: 'array',
|
||||
items: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
html: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
normal: { $ref: '#/definitions/optionValue' },
|
||||
void: { $ref: '#/definitions/optionValue' },
|
||||
component: { $ref: '#/definitions/optionValue' }
|
||||
},
|
||||
additionalProperties: false
|
||||
},
|
||||
svg: { $ref: '#/definitions/optionValue' },
|
||||
math: { $ref: '#/definitions/optionValue' }
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
maxItems: 1
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const sourceCode = context.getSourceCode()
|
||||
const options = parseOptions(context.options[0])
|
||||
let hasInvalidEOF = false
|
||||
|
||||
return utils.defineTemplateBodyVisitor(
|
||||
context,
|
||||
{
|
||||
VElement(node) {
|
||||
if (hasInvalidEOF) {
|
||||
return
|
||||
}
|
||||
|
||||
const elementType = getElementType(node)
|
||||
const mode = options[elementType]
|
||||
|
||||
if (
|
||||
mode === 'always' &&
|
||||
!node.startTag.selfClosing &&
|
||||
isEmpty(node, sourceCode)
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
loc: node.loc,
|
||||
message: 'Require self-closing on {{elementType}} (<{{name}}>).',
|
||||
data: {
|
||||
elementType: ELEMENT_TYPE_MESSAGES[elementType],
|
||||
name: node.rawName
|
||||
},
|
||||
fix(fixer) {
|
||||
const tokens =
|
||||
context.parserServices.getTemplateBodyTokenStore()
|
||||
const close = tokens.getLastToken(node.startTag)
|
||||
if (close.type !== 'HTMLTagClose') {
|
||||
return null
|
||||
}
|
||||
return fixer.replaceTextRange(
|
||||
[close.range[0], node.range[1]],
|
||||
'/>'
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (mode === 'never' && node.startTag.selfClosing) {
|
||||
context.report({
|
||||
node,
|
||||
loc: node.loc,
|
||||
message:
|
||||
'Disallow self-closing on {{elementType}} (<{{name}}/>).',
|
||||
data: {
|
||||
elementType: ELEMENT_TYPE_MESSAGES[elementType],
|
||||
name: node.rawName
|
||||
},
|
||||
fix(fixer) {
|
||||
const tokens =
|
||||
context.parserServices.getTemplateBodyTokenStore()
|
||||
const close = tokens.getLastToken(node.startTag)
|
||||
if (close.type !== 'HTMLSelfClosingTagClose') {
|
||||
return null
|
||||
}
|
||||
if (elementType === 'VOID') {
|
||||
return fixer.replaceText(close, '>')
|
||||
}
|
||||
// If only `close` is targeted for replacement, it conflicts with `component-name-in-template-casing`,
|
||||
// so replace the entire element.
|
||||
// return fixer.replaceText(close, `></${node.rawName}>`)
|
||||
const elementPart = sourceCode.text.slice(
|
||||
node.range[0],
|
||||
close.range[0]
|
||||
)
|
||||
return fixer.replaceText(
|
||||
node,
|
||||
`${elementPart}></${node.rawName}>`
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
Program(node) {
|
||||
hasInvalidEOF = utils.hasInvalidEOF(node)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
73
app_vue/node_modules/eslint-plugin-vue/lib/rules/jsx-uses-vars.js
generated
vendored
Normal file
73
app_vue/node_modules/eslint-plugin-vue/lib/rules/jsx-uses-vars.js
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
// the following rule is based on yannickcr/eslint-plugin-react
|
||||
|
||||
/**
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Yannick Croissant
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Prevent variables used in JSX to be marked as unused
|
||||
* @author Yannick Croissant
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'prevent variables used in JSX to be marked as unused', // eslint-disable-line eslint-plugin/require-meta-docs-description
|
||||
categories: ['base'],
|
||||
url: 'https://eslint.vuejs.org/rules/jsx-uses-vars.html'
|
||||
},
|
||||
schema: []
|
||||
},
|
||||
/**
|
||||
* @param {RuleContext} context - The rule context.
|
||||
* @returns {RuleListener} AST event handlers.
|
||||
*/
|
||||
create(context) {
|
||||
return {
|
||||
JSXOpeningElement(node) {
|
||||
let name
|
||||
if (node.name.type === 'JSXIdentifier') {
|
||||
// <Foo>
|
||||
name = node.name.name
|
||||
} else if (node.name.type === 'JSXMemberExpression') {
|
||||
// <Foo...Bar>
|
||||
let parent = node.name.object
|
||||
while (parent.type === 'JSXMemberExpression') {
|
||||
parent = parent.object
|
||||
}
|
||||
name = parent.name
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
context.markVariableAsUsed(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/key-spacing.js
generated
vendored
Normal file
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/key-spacing.js
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('key-spacing', {
|
||||
skipDynamicArguments: true
|
||||
})
|
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/keyword-spacing.js
generated
vendored
Normal file
11
app_vue/node_modules/eslint-plugin-vue/lib/rules/keyword-spacing.js
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('keyword-spacing', {
|
||||
skipDynamicArguments: true
|
||||
})
|
151
app_vue/node_modules/eslint-plugin-vue/lib/rules/match-component-file-name.js
generated
vendored
Normal file
151
app_vue/node_modules/eslint-plugin-vue/lib/rules/match-component-file-name.js
generated
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
/**
|
||||
* @fileoverview Require component name property to match its file name
|
||||
* @author Rodrigo Pedra Brum <rodrigo.pedra@gmail.com>
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
const casing = require('../utils/casing')
|
||||
const path = require('path')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'require component name property to match its file name',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/match-component-file-name.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
extensions: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
},
|
||||
uniqueItems: true,
|
||||
additionalItems: false
|
||||
},
|
||||
shouldMatchCase: {
|
||||
type: 'boolean'
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const options = context.options[0]
|
||||
const shouldMatchCase = (options && options.shouldMatchCase) || false
|
||||
const extensionsArray = options && options.extensions
|
||||
const allowedExtensions = Array.isArray(extensionsArray)
|
||||
? extensionsArray
|
||||
: ['jsx']
|
||||
|
||||
const extension = path.extname(context.getFilename())
|
||||
const filename = path.basename(context.getFilename(), extension)
|
||||
|
||||
/** @type {Rule.ReportDescriptor[]} */
|
||||
const errors = []
|
||||
let componentCount = 0
|
||||
|
||||
if (!allowedExtensions.includes(extension.replace(/^\./, ''))) {
|
||||
return {}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Private
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {string} filename
|
||||
*/
|
||||
function compareNames(name, filename) {
|
||||
if (shouldMatchCase) {
|
||||
return name === filename
|
||||
}
|
||||
|
||||
return (
|
||||
casing.pascalCase(name) === filename ||
|
||||
casing.kebabCase(name) === filename
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Literal | TemplateLiteral} node
|
||||
*/
|
||||
function verifyName(node) {
|
||||
let name
|
||||
if (node.type === 'TemplateLiteral') {
|
||||
const quasis = node.quasis[0]
|
||||
name = quasis.value.cooked
|
||||
} else {
|
||||
name = `${node.value}`
|
||||
}
|
||||
|
||||
if (!compareNames(name, filename)) {
|
||||
errors.push({
|
||||
node,
|
||||
message:
|
||||
'Component name `{{name}}` should match file name `{{filename}}`.',
|
||||
data: { filename, name }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Expression | SpreadElement} node
|
||||
* @returns {node is (Literal | TemplateLiteral)}
|
||||
*/
|
||||
function canVerify(node) {
|
||||
return (
|
||||
node.type === 'Literal' ||
|
||||
(node.type === 'TemplateLiteral' &&
|
||||
node.expressions.length === 0 &&
|
||||
node.quasis.length === 1)
|
||||
)
|
||||
}
|
||||
|
||||
return Object.assign(
|
||||
{},
|
||||
utils.executeOnCallVueComponent(context, (node) => {
|
||||
if (node.arguments.length === 2) {
|
||||
const argument = node.arguments[0]
|
||||
|
||||
if (canVerify(argument)) {
|
||||
verifyName(argument)
|
||||
}
|
||||
}
|
||||
}),
|
||||
utils.executeOnVue(context, (object) => {
|
||||
const node = utils.findProperty(object, 'name')
|
||||
|
||||
componentCount++
|
||||
|
||||
if (!node) return
|
||||
if (!canVerify(node.value)) return
|
||||
verifyName(node.value)
|
||||
}),
|
||||
{
|
||||
'Program:exit'() {
|
||||
if (componentCount > 1) return
|
||||
|
||||
errors.forEach((error) => context.report(error))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
79
app_vue/node_modules/eslint-plugin-vue/lib/rules/match-component-import-name.js
generated
vendored
Normal file
79
app_vue/node_modules/eslint-plugin-vue/lib/rules/match-component-import-name.js
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* @author Doug Wade <douglas.b.wade@gmail.com>
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
const casing = require('../utils/casing')
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
schema: [],
|
||||
docs: {
|
||||
description:
|
||||
'require the registered component name to match the imported component name',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/match-component-import-name.html'
|
||||
},
|
||||
fixable: null,
|
||||
messages: {
|
||||
unexpected:
|
||||
'Component alias {{importedName}} should be one of: {{expectedName}}.'
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {RuleContext} context
|
||||
* @returns {RuleListener}
|
||||
*/
|
||||
create(context) {
|
||||
/**
|
||||
* @param {Identifier} identifier
|
||||
* @return {Array<String>}
|
||||
*/
|
||||
function getExpectedNames(identifier) {
|
||||
return [
|
||||
casing.pascalCase(identifier.name),
|
||||
casing.kebabCase(identifier.name)
|
||||
]
|
||||
}
|
||||
|
||||
return utils.executeOnVueComponent(context, (obj) => {
|
||||
const components = utils.findProperty(obj, 'components')
|
||||
if (
|
||||
!components ||
|
||||
!components.value ||
|
||||
components.value.type !== 'ObjectExpression'
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
components.value.properties.forEach(
|
||||
/** @param {Property | SpreadElement} property */
|
||||
(property) => {
|
||||
if (
|
||||
property.type === 'SpreadElement' ||
|
||||
property.value.type !== 'Identifier' ||
|
||||
property.computed === true
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const importedName = utils.getStaticPropertyName(property) || ''
|
||||
const expectedNames = getExpectedNames(property.value)
|
||||
if (!expectedNames.includes(importedName)) {
|
||||
context.report({
|
||||
node: property,
|
||||
messageId: 'unexpected',
|
||||
data: {
|
||||
importedName,
|
||||
expectedName: expectedNames.join(', ')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
179
app_vue/node_modules/eslint-plugin-vue/lib/rules/max-attributes-per-line.js
generated
vendored
Normal file
179
app_vue/node_modules/eslint-plugin-vue/lib/rules/max-attributes-per-line.js
generated
vendored
Normal file
@ -0,0 +1,179 @@
|
||||
/**
|
||||
* @fileoverview Define the number of attributes allows per line
|
||||
* @author Filipa Lacerda
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
const utils = require('../utils')
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
docs: {
|
||||
description: 'enforce the maximum number of attributes per line',
|
||||
categories: ['vue3-strongly-recommended', 'strongly-recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/max-attributes-per-line.html'
|
||||
},
|
||||
fixable: 'whitespace', // or "code" or "whitespace"
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
singleline: {
|
||||
anyOf: [
|
||||
{
|
||||
type: 'number',
|
||||
minimum: 1
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
max: {
|
||||
type: 'number',
|
||||
minimum: 1
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
},
|
||||
multiline: {
|
||||
anyOf: [
|
||||
{
|
||||
type: 'number',
|
||||
minimum: 1
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
max: {
|
||||
type: 'number',
|
||||
minimum: 1
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const sourceCode = context.getSourceCode()
|
||||
const configuration = parseOptions(context.options[0])
|
||||
const multilineMaximum = configuration.multiline
|
||||
const singlelinemMaximum = configuration.singleline
|
||||
const template =
|
||||
context.parserServices.getTemplateBodyTokenStore &&
|
||||
context.parserServices.getTemplateBodyTokenStore()
|
||||
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
VStartTag(node) {
|
||||
const numberOfAttributes = node.attributes.length
|
||||
|
||||
if (!numberOfAttributes) return
|
||||
|
||||
if (utils.isSingleLine(node)) {
|
||||
if (numberOfAttributes > singlelinemMaximum) {
|
||||
showErrors(node.attributes.slice(singlelinemMaximum))
|
||||
}
|
||||
}
|
||||
|
||||
if (!utils.isSingleLine(node)) {
|
||||
groupAttrsByLine(node.attributes)
|
||||
.filter((attrs) => attrs.length > multilineMaximum)
|
||||
.forEach((attrs) => showErrors(attrs.splice(multilineMaximum)))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* @param {any} options
|
||||
*/
|
||||
function parseOptions(options) {
|
||||
const defaults = {
|
||||
singleline: 1,
|
||||
multiline: 1
|
||||
}
|
||||
|
||||
if (options) {
|
||||
if (typeof options.singleline === 'number') {
|
||||
defaults.singleline = options.singleline
|
||||
} else if (typeof options.singleline === 'object') {
|
||||
if (typeof options.singleline.max === 'number') {
|
||||
defaults.singleline = options.singleline.max
|
||||
}
|
||||
}
|
||||
|
||||
if (options.multiline) {
|
||||
if (typeof options.multiline === 'number') {
|
||||
defaults.multiline = options.multiline
|
||||
} else if (typeof options.multiline === 'object') {
|
||||
if (typeof options.multiline.max === 'number') {
|
||||
defaults.multiline = options.multiline.max
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return defaults
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {(VDirective | VAttribute)[]} attributes
|
||||
*/
|
||||
function showErrors(attributes) {
|
||||
attributes.forEach((prop, i) => {
|
||||
context.report({
|
||||
node: prop,
|
||||
loc: prop.loc,
|
||||
message: "'{{name}}' should be on a new line.",
|
||||
data: { name: sourceCode.getText(prop.key) },
|
||||
fix(fixer) {
|
||||
if (i !== 0) return null
|
||||
|
||||
// Find the closest token before the current prop
|
||||
// that is not a white space
|
||||
const prevToken = /** @type {Token} */ (
|
||||
template.getTokenBefore(prop, {
|
||||
filter: (token) => token.type !== 'HTMLWhitespace'
|
||||
})
|
||||
)
|
||||
|
||||
/** @type {Range} */
|
||||
const range = [prevToken.range[1], prop.range[0]]
|
||||
|
||||
return fixer.replaceTextRange(range, '\n')
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {(VDirective | VAttribute)[]} attributes
|
||||
*/
|
||||
function groupAttrsByLine(attributes) {
|
||||
const propsPerLine = [[attributes[0]]]
|
||||
|
||||
attributes.reduce((previous, current) => {
|
||||
if (previous.loc.end.line === current.loc.start.line) {
|
||||
propsPerLine[propsPerLine.length - 1].push(current)
|
||||
} else {
|
||||
propsPerLine.push([current])
|
||||
}
|
||||
return current
|
||||
})
|
||||
|
||||
return propsPerLine
|
||||
}
|
||||
}
|
||||
}
|
560
app_vue/node_modules/eslint-plugin-vue/lib/rules/max-len.js
generated
vendored
Normal file
560
app_vue/node_modules/eslint-plugin-vue/lib/rules/max-len.js
generated
vendored
Normal file
@ -0,0 +1,560 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* @fileoverview Rule to check for max length on a line of Vue file.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const OPTIONS_SCHEMA = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
code: {
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
},
|
||||
template: {
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
},
|
||||
comments: {
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
},
|
||||
tabWidth: {
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
},
|
||||
ignorePattern: {
|
||||
type: 'string'
|
||||
},
|
||||
ignoreComments: {
|
||||
type: 'boolean'
|
||||
},
|
||||
ignoreTrailingComments: {
|
||||
type: 'boolean'
|
||||
},
|
||||
ignoreUrls: {
|
||||
type: 'boolean'
|
||||
},
|
||||
ignoreStrings: {
|
||||
type: 'boolean'
|
||||
},
|
||||
ignoreTemplateLiterals: {
|
||||
type: 'boolean'
|
||||
},
|
||||
ignoreRegExpLiterals: {
|
||||
type: 'boolean'
|
||||
},
|
||||
ignoreHTMLAttributeValues: {
|
||||
type: 'boolean'
|
||||
},
|
||||
ignoreHTMLTextContents: {
|
||||
type: 'boolean'
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
|
||||
const OPTIONS_OR_INTEGER_SCHEMA = {
|
||||
anyOf: [
|
||||
OPTIONS_SCHEMA,
|
||||
{
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Computes the length of a line that may contain tabs. The width of each
|
||||
* tab will be the number of spaces to the next tab stop.
|
||||
* @param {string} line The line.
|
||||
* @param {number} tabWidth The width of each tab stop in spaces.
|
||||
* @returns {number} The computed line length.
|
||||
* @private
|
||||
*/
|
||||
function computeLineLength(line, tabWidth) {
|
||||
let extraCharacterCount = 0
|
||||
|
||||
const re = /\t/gu
|
||||
let ret
|
||||
while ((ret = re.exec(line))) {
|
||||
const offset = ret.index
|
||||
const totalOffset = offset + extraCharacterCount
|
||||
const previousTabStopOffset = tabWidth ? totalOffset % tabWidth : 0
|
||||
const spaceCount = tabWidth - previousTabStopOffset
|
||||
extraCharacterCount += spaceCount - 1 // -1 for the replaced tab
|
||||
}
|
||||
|
||||
return Array.from(line).length + extraCharacterCount
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if a given comment is trailing: it starts on the current line and
|
||||
* extends to or past the end of the current line.
|
||||
* @param {string} line The source line we want to check for a trailing comment on
|
||||
* @param {number} lineNumber The one-indexed line number for line
|
||||
* @param {Token | null} comment The comment to inspect
|
||||
* @returns {comment is Token} If the comment is trailing on the given line
|
||||
*/
|
||||
function isTrailingComment(line, lineNumber, comment) {
|
||||
return Boolean(
|
||||
comment &&
|
||||
comment.loc.start.line === lineNumber &&
|
||||
lineNumber <= comment.loc.end.line &&
|
||||
(comment.loc.end.line > lineNumber ||
|
||||
comment.loc.end.column === line.length)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if a comment encompasses the entire line.
|
||||
* @param {string} line The source line with a trailing comment
|
||||
* @param {number} lineNumber The one-indexed line number this is on
|
||||
* @param {Token | null} comment The comment to remove
|
||||
* @returns {boolean} If the comment covers the entire line
|
||||
*/
|
||||
function isFullLineComment(line, lineNumber, comment) {
|
||||
if (!comment) {
|
||||
return false
|
||||
}
|
||||
const start = comment.loc.start
|
||||
const end = comment.loc.end
|
||||
const isFirstTokenOnLine = !line.slice(0, comment.loc.start.column).trim()
|
||||
|
||||
return (
|
||||
comment &&
|
||||
(start.line < lineNumber ||
|
||||
(start.line === lineNumber && isFirstTokenOnLine)) &&
|
||||
(end.line > lineNumber ||
|
||||
(end.line === lineNumber && end.column === line.length))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the line after the comment and any remaining trailing whitespace is
|
||||
* stripped.
|
||||
* @param {string} line The source line with a trailing comment
|
||||
* @param {Token} comment The comment to remove
|
||||
* @returns {string} Line without comment and trailing whitepace
|
||||
*/
|
||||
function stripTrailingComment(line, comment) {
|
||||
// loc.column is zero-indexed
|
||||
return line.slice(0, comment.loc.start.column).replace(/\s+$/u, '')
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that an array exists at [key] on `object`, and add `value` to it.
|
||||
*
|
||||
* @param { { [key: number]: Token[] } } object the object to mutate
|
||||
* @param {number} key the object's key
|
||||
* @param {Token} value the value to add
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function ensureArrayAndPush(object, key, value) {
|
||||
if (!Array.isArray(object[key])) {
|
||||
object[key] = []
|
||||
}
|
||||
object[key].push(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* A reducer to group an AST node by line number, both start and end.
|
||||
*
|
||||
* @param { { [key: number]: Token[] } } acc the accumulator
|
||||
* @param {Token} node the AST node in question
|
||||
* @returns { { [key: number]: Token[] } } the modified accumulator
|
||||
* @private
|
||||
*/
|
||||
function groupByLineNumber(acc, node) {
|
||||
for (let i = node.loc.start.line; i <= node.loc.end.line; ++i) {
|
||||
ensureArrayAndPush(acc, i, node)
|
||||
}
|
||||
return acc
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
|
||||
docs: {
|
||||
description: 'enforce a maximum line length in `.vue` files',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/max-len.html',
|
||||
extensionRule: true,
|
||||
coreRuleUrl: 'https://eslint.org/docs/rules/max-len'
|
||||
},
|
||||
|
||||
schema: [
|
||||
OPTIONS_OR_INTEGER_SCHEMA,
|
||||
OPTIONS_OR_INTEGER_SCHEMA,
|
||||
OPTIONS_SCHEMA
|
||||
],
|
||||
messages: {
|
||||
max: 'This line has a length of {{lineLength}}. Maximum allowed is {{maxLength}}.',
|
||||
maxComment:
|
||||
'This line has a comment length of {{lineLength}}. Maximum allowed is {{maxCommentLength}}.'
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {RuleContext} context - The rule context.
|
||||
* @returns {RuleListener} AST event handlers.
|
||||
*/
|
||||
create(context) {
|
||||
/*
|
||||
* Inspired by http://tools.ietf.org/html/rfc3986#appendix-B, however:
|
||||
* - They're matching an entire string that we know is a URI
|
||||
* - We're matching part of a string where we think there *might* be a URL
|
||||
* - We're only concerned about URLs, as picking out any URI would cause
|
||||
* too many false positives
|
||||
* - We don't care about matching the entire URL, any small segment is fine
|
||||
*/
|
||||
const URL_REGEXP = /[^:/?#]:\/\/[^?#]/u
|
||||
|
||||
const sourceCode = context.getSourceCode()
|
||||
/** @type {Token[]} */
|
||||
const tokens = []
|
||||
/** @type {(HTMLComment | HTMLBogusComment | Comment)[]} */
|
||||
const comments = []
|
||||
/** @type {VLiteral[]} */
|
||||
const htmlAttributeValues = []
|
||||
|
||||
// The options object must be the last option specified…
|
||||
const options = Object.assign(
|
||||
{},
|
||||
context.options[context.options.length - 1]
|
||||
)
|
||||
|
||||
// …but max code length…
|
||||
if (typeof context.options[0] === 'number') {
|
||||
options.code = context.options[0]
|
||||
}
|
||||
|
||||
// …and tabWidth can be optionally specified directly as integers.
|
||||
if (typeof context.options[1] === 'number') {
|
||||
options.tabWidth = context.options[1]
|
||||
}
|
||||
/** @type {number} */
|
||||
const scriptMaxLength = typeof options.code === 'number' ? options.code : 80
|
||||
/** @type {number} */
|
||||
const tabWidth = typeof options.tabWidth === 'number' ? options.tabWidth : 2 // default value of `vue/html-indent`
|
||||
/** @type {number} */
|
||||
const templateMaxLength =
|
||||
typeof options.template === 'number' ? options.template : scriptMaxLength
|
||||
const ignoreComments = !!options.ignoreComments
|
||||
const ignoreStrings = !!options.ignoreStrings
|
||||
const ignoreTemplateLiterals = !!options.ignoreTemplateLiterals
|
||||
const ignoreRegExpLiterals = !!options.ignoreRegExpLiterals
|
||||
const ignoreTrailingComments =
|
||||
!!options.ignoreTrailingComments || !!options.ignoreComments
|
||||
const ignoreUrls = !!options.ignoreUrls
|
||||
const ignoreHTMLAttributeValues = !!options.ignoreHTMLAttributeValues
|
||||
const ignoreHTMLTextContents = !!options.ignoreHTMLTextContents
|
||||
/** @type {number} */
|
||||
const maxCommentLength = options.comments
|
||||
/** @type {RegExp} */
|
||||
let ignorePattern = options.ignorePattern || null
|
||||
|
||||
if (ignorePattern) {
|
||||
ignorePattern = new RegExp(ignorePattern, 'u')
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Retrieves an array containing all strings (" or ') in the source code.
|
||||
*
|
||||
* @returns {Token[]} An array of string nodes.
|
||||
*/
|
||||
function getAllStrings() {
|
||||
return tokens.filter(
|
||||
(token) =>
|
||||
token.type === 'String' ||
|
||||
(token.type === 'JSXText' &&
|
||||
sourceCode.getNodeByRangeIndex(token.range[0] - 1).type ===
|
||||
'JSXAttribute')
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an array containing all template literals in the source code.
|
||||
*
|
||||
* @returns {Token[]} An array of template literal nodes.
|
||||
*/
|
||||
function getAllTemplateLiterals() {
|
||||
return tokens.filter((token) => token.type === 'Template')
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an array containing all RegExp literals in the source code.
|
||||
*
|
||||
* @returns {Token[]} An array of RegExp literal nodes.
|
||||
*/
|
||||
function getAllRegExpLiterals() {
|
||||
return tokens.filter((token) => token.type === 'RegularExpression')
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an array containing all HTML texts in the source code.
|
||||
*
|
||||
* @returns {Token[]} An array of HTML text nodes.
|
||||
*/
|
||||
function getAllHTMLTextContents() {
|
||||
return tokens.filter((token) => token.type === 'HTMLText')
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the program for max length
|
||||
* @param {Program} node Node to examine
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function checkProgramForMaxLength(node) {
|
||||
const programNode = node
|
||||
const templateBody = node.templateBody
|
||||
|
||||
// setup tokens
|
||||
const scriptTokens = sourceCode.ast.tokens
|
||||
const scriptComments = sourceCode.getAllComments()
|
||||
|
||||
if (context.parserServices.getTemplateBodyTokenStore && templateBody) {
|
||||
const tokenStore = context.parserServices.getTemplateBodyTokenStore()
|
||||
|
||||
const templateTokens = tokenStore.getTokens(templateBody, {
|
||||
includeComments: true
|
||||
})
|
||||
|
||||
if (templateBody.range[0] < programNode.range[0]) {
|
||||
tokens.push(...templateTokens, ...scriptTokens)
|
||||
} else {
|
||||
tokens.push(...scriptTokens, ...templateTokens)
|
||||
}
|
||||
} else {
|
||||
tokens.push(...scriptTokens)
|
||||
}
|
||||
|
||||
if (ignoreComments || maxCommentLength || ignoreTrailingComments) {
|
||||
// list of comments to ignore
|
||||
if (templateBody) {
|
||||
if (templateBody.range[0] < programNode.range[0]) {
|
||||
comments.push(...templateBody.comments, ...scriptComments)
|
||||
} else {
|
||||
comments.push(...scriptComments, ...templateBody.comments)
|
||||
}
|
||||
} else {
|
||||
comments.push(...scriptComments)
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {Range} */
|
||||
let scriptLinesRange
|
||||
if (scriptTokens.length) {
|
||||
if (scriptComments.length) {
|
||||
scriptLinesRange = [
|
||||
Math.min(
|
||||
scriptTokens[0].loc.start.line,
|
||||
scriptComments[0].loc.start.line
|
||||
),
|
||||
Math.max(
|
||||
scriptTokens[scriptTokens.length - 1].loc.end.line,
|
||||
scriptComments[scriptComments.length - 1].loc.end.line
|
||||
)
|
||||
]
|
||||
} else {
|
||||
scriptLinesRange = [
|
||||
scriptTokens[0].loc.start.line,
|
||||
scriptTokens[scriptTokens.length - 1].loc.end.line
|
||||
]
|
||||
}
|
||||
} else if (scriptComments.length) {
|
||||
scriptLinesRange = [
|
||||
scriptComments[0].loc.start.line,
|
||||
scriptComments[scriptComments.length - 1].loc.end.line
|
||||
]
|
||||
}
|
||||
const templateLinesRange = templateBody && [
|
||||
templateBody.loc.start.line,
|
||||
templateBody.loc.end.line
|
||||
]
|
||||
|
||||
// split (honors line-ending)
|
||||
const lines = sourceCode.lines
|
||||
|
||||
const strings = getAllStrings()
|
||||
const stringsByLine = strings.reduce(groupByLineNumber, {})
|
||||
|
||||
const templateLiterals = getAllTemplateLiterals()
|
||||
const templateLiteralsByLine = templateLiterals.reduce(
|
||||
groupByLineNumber,
|
||||
{}
|
||||
)
|
||||
|
||||
const regExpLiterals = getAllRegExpLiterals()
|
||||
const regExpLiteralsByLine = regExpLiterals.reduce(groupByLineNumber, {})
|
||||
|
||||
const htmlAttributeValuesByLine = htmlAttributeValues.reduce(
|
||||
groupByLineNumber,
|
||||
{}
|
||||
)
|
||||
|
||||
const htmlTextContents = getAllHTMLTextContents()
|
||||
const htmlTextContentsByLine = htmlTextContents.reduce(
|
||||
groupByLineNumber,
|
||||
{}
|
||||
)
|
||||
|
||||
const commentsByLine = comments.reduce(groupByLineNumber, {})
|
||||
|
||||
lines.forEach((line, i) => {
|
||||
// i is zero-indexed, line numbers are one-indexed
|
||||
const lineNumber = i + 1
|
||||
|
||||
const inScript =
|
||||
scriptLinesRange &&
|
||||
scriptLinesRange[0] <= lineNumber &&
|
||||
lineNumber <= scriptLinesRange[1]
|
||||
const inTemplate =
|
||||
templateLinesRange &&
|
||||
templateLinesRange[0] <= lineNumber &&
|
||||
lineNumber <= templateLinesRange[1]
|
||||
// check if line is inside a script or template.
|
||||
if (!inScript && !inTemplate) {
|
||||
// out of range.
|
||||
return
|
||||
}
|
||||
const maxLength =
|
||||
inScript && inTemplate
|
||||
? Math.max(scriptMaxLength, templateMaxLength)
|
||||
: inScript
|
||||
? scriptMaxLength
|
||||
: templateMaxLength
|
||||
|
||||
if (
|
||||
(ignoreStrings && stringsByLine[lineNumber]) ||
|
||||
(ignoreTemplateLiterals && templateLiteralsByLine[lineNumber]) ||
|
||||
(ignoreRegExpLiterals && regExpLiteralsByLine[lineNumber]) ||
|
||||
(ignoreHTMLAttributeValues &&
|
||||
htmlAttributeValuesByLine[lineNumber]) ||
|
||||
(ignoreHTMLTextContents && htmlTextContentsByLine[lineNumber])
|
||||
) {
|
||||
// ignore this line
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
* if we're checking comment length; we need to know whether this
|
||||
* line is a comment
|
||||
*/
|
||||
let lineIsComment = false
|
||||
let textToMeasure
|
||||
|
||||
/*
|
||||
* comments to check.
|
||||
*/
|
||||
if (commentsByLine[lineNumber]) {
|
||||
const commentList = [...commentsByLine[lineNumber]]
|
||||
|
||||
let comment = commentList.pop() || null
|
||||
|
||||
if (isFullLineComment(line, lineNumber, comment)) {
|
||||
lineIsComment = true
|
||||
textToMeasure = line
|
||||
} else if (
|
||||
ignoreTrailingComments &&
|
||||
isTrailingComment(line, lineNumber, comment)
|
||||
) {
|
||||
textToMeasure = stripTrailingComment(line, comment)
|
||||
|
||||
// ignore multiple trailing comments in the same line
|
||||
comment = commentList.pop() || null
|
||||
|
||||
while (isTrailingComment(textToMeasure, lineNumber, comment)) {
|
||||
textToMeasure = stripTrailingComment(textToMeasure, comment)
|
||||
}
|
||||
} else {
|
||||
textToMeasure = line
|
||||
}
|
||||
} else {
|
||||
textToMeasure = line
|
||||
}
|
||||
|
||||
if (
|
||||
(ignorePattern && ignorePattern.test(textToMeasure)) ||
|
||||
(ignoreUrls && URL_REGEXP.test(textToMeasure))
|
||||
) {
|
||||
// ignore this line
|
||||
return
|
||||
}
|
||||
|
||||
const lineLength = computeLineLength(textToMeasure, tabWidth)
|
||||
const commentLengthApplies = lineIsComment && maxCommentLength
|
||||
|
||||
if (lineIsComment && ignoreComments) {
|
||||
return
|
||||
}
|
||||
|
||||
if (commentLengthApplies) {
|
||||
if (lineLength > maxCommentLength) {
|
||||
context.report({
|
||||
node,
|
||||
loc: { line: lineNumber, column: 0 },
|
||||
messageId: 'maxComment',
|
||||
data: {
|
||||
lineLength,
|
||||
maxCommentLength
|
||||
}
|
||||
})
|
||||
}
|
||||
} else if (lineLength > maxLength) {
|
||||
context.report({
|
||||
node,
|
||||
loc: { line: lineNumber, column: 0 },
|
||||
messageId: 'max',
|
||||
data: {
|
||||
lineLength,
|
||||
maxLength
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Public API
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
return utils.compositingVisitors(
|
||||
utils.defineTemplateBodyVisitor(context, {
|
||||
/** @param {VLiteral} node */
|
||||
'VAttribute[directive=false] > VLiteral'(node) {
|
||||
htmlAttributeValues.push(node)
|
||||
}
|
||||
}),
|
||||
{
|
||||
'Program:exit'(node) {
|
||||
checkProgramForMaxLength(node)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
132
app_vue/node_modules/eslint-plugin-vue/lib/rules/multi-word-component-names.js
generated
vendored
Normal file
132
app_vue/node_modules/eslint-plugin-vue/lib/rules/multi-word-component-names.js
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
/**
|
||||
* @author Marton Csordas
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const path = require('path')
|
||||
const casing = require('../utils/casing')
|
||||
const utils = require('../utils')
|
||||
|
||||
const RESERVED_NAMES_IN_VUE3 = new Set(
|
||||
require('../utils/vue3-builtin-components')
|
||||
)
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'require component names to be always multi-word',
|
||||
categories: ['vue3-essential', 'essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/multi-word-component-names.html'
|
||||
},
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
ignores: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
uniqueItems: true,
|
||||
additionalItems: false
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
unexpected: 'Component name "{{value}}" should always be multi-word.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
/** @type {Set<string>} */
|
||||
const ignores = new Set()
|
||||
ignores.add('App')
|
||||
ignores.add('app')
|
||||
for (const ignore of (context.options[0] && context.options[0].ignores) ||
|
||||
[]) {
|
||||
ignores.add(ignore)
|
||||
if (casing.isPascalCase(ignore)) {
|
||||
// PascalCase
|
||||
ignores.add(casing.kebabCase(ignore))
|
||||
}
|
||||
}
|
||||
let hasVue = utils.isScriptSetup(context)
|
||||
let hasName = false
|
||||
|
||||
/**
|
||||
* Returns true if the given component name is valid, otherwise false.
|
||||
* @param {string} name
|
||||
* */
|
||||
function isValidComponentName(name) {
|
||||
if (ignores.has(name) || RESERVED_NAMES_IN_VUE3.has(name)) {
|
||||
return true
|
||||
}
|
||||
const elements = casing.kebabCase(name).split('-')
|
||||
return elements.length > 1
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Expression | SpreadElement} nameNode
|
||||
*/
|
||||
function validateName(nameNode) {
|
||||
if (nameNode.type !== 'Literal') return
|
||||
const componentName = `${nameNode.value}`
|
||||
if (!isValidComponentName(componentName)) {
|
||||
context.report({
|
||||
node: nameNode,
|
||||
messageId: 'unexpected',
|
||||
data: {
|
||||
value: componentName
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return utils.compositingVisitors(
|
||||
utils.executeOnCallVueComponent(context, (node) => {
|
||||
hasVue = true
|
||||
if (node.arguments.length !== 2) return
|
||||
hasName = true
|
||||
validateName(node.arguments[0])
|
||||
}),
|
||||
utils.executeOnVue(context, (obj) => {
|
||||
hasVue = true
|
||||
const node = utils.findProperty(obj, 'name')
|
||||
if (!node) return
|
||||
hasName = true
|
||||
validateName(node.value)
|
||||
}),
|
||||
{
|
||||
/** @param {Program} node */
|
||||
'Program:exit'(node) {
|
||||
if (hasName) return
|
||||
if (!hasVue && node.body.length > 0) return
|
||||
const fileName = context.getFilename()
|
||||
const componentName = path.basename(fileName, path.extname(fileName))
|
||||
if (
|
||||
utils.isVueFile(fileName) &&
|
||||
!isValidComponentName(componentName)
|
||||
) {
|
||||
context.report({
|
||||
messageId: 'unexpected',
|
||||
data: {
|
||||
value: componentName
|
||||
},
|
||||
loc: { line: 1, column: 0 }
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
243
app_vue/node_modules/eslint-plugin-vue/lib/rules/multiline-html-element-content-newline.js
generated
vendored
Normal file
243
app_vue/node_modules/eslint-plugin-vue/lib/rules/multiline-html-element-content-newline.js
generated
vendored
Normal file
@ -0,0 +1,243 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
const casing = require('../utils/casing')
|
||||
const INLINE_ELEMENTS = require('../utils/inline-non-void-elements.json')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {VElement & { endTag: VEndTag }} element
|
||||
*/
|
||||
function isMultilineElement(element) {
|
||||
return element.loc.start.line < element.endTag.loc.start.line
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} options
|
||||
*/
|
||||
function parseOptions(options) {
|
||||
return Object.assign(
|
||||
{
|
||||
ignores: ['pre', 'textarea'].concat(INLINE_ELEMENTS),
|
||||
ignoreWhenEmpty: true,
|
||||
allowEmptyLines: false
|
||||
},
|
||||
options
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} lineBreaks
|
||||
*/
|
||||
function getPhrase(lineBreaks) {
|
||||
switch (lineBreaks) {
|
||||
case 0:
|
||||
return 'no'
|
||||
default:
|
||||
return `${lineBreaks}`
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Check whether the given element is empty or not.
|
||||
* This ignores whitespaces, doesn't ignore comments.
|
||||
* @param {VElement & { endTag: VEndTag }} node The element node to check.
|
||||
* @param {SourceCode} sourceCode The source code object of the current context.
|
||||
* @returns {boolean} `true` if the element is empty.
|
||||
*/
|
||||
function isEmpty(node, sourceCode) {
|
||||
const start = node.startTag.range[1]
|
||||
const end = node.endTag.range[0]
|
||||
return sourceCode.text.slice(start, end).trim() === ''
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
docs: {
|
||||
description:
|
||||
'require a line break before and after the contents of a multiline element',
|
||||
categories: ['vue3-strongly-recommended', 'strongly-recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/multiline-html-element-content-newline.html'
|
||||
},
|
||||
fixable: 'whitespace',
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
ignoreWhenEmpty: {
|
||||
type: 'boolean'
|
||||
},
|
||||
ignores: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
uniqueItems: true,
|
||||
additionalItems: false
|
||||
},
|
||||
allowEmptyLines: {
|
||||
type: 'boolean'
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
unexpectedAfterClosingBracket:
|
||||
'Expected 1 line break after opening tag (`<{{name}}>`), but {{actual}} line breaks found.',
|
||||
unexpectedBeforeOpeningBracket:
|
||||
'Expected 1 line break before closing tag (`</{{name}}>`), but {{actual}} line breaks found.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const options = parseOptions(context.options[0])
|
||||
const ignores = options.ignores
|
||||
const ignoreWhenEmpty = options.ignoreWhenEmpty
|
||||
const allowEmptyLines = options.allowEmptyLines
|
||||
const template =
|
||||
context.parserServices.getTemplateBodyTokenStore &&
|
||||
context.parserServices.getTemplateBodyTokenStore()
|
||||
const sourceCode = context.getSourceCode()
|
||||
|
||||
/** @type {VElement | null} */
|
||||
let inIgnoreElement = null
|
||||
|
||||
/**
|
||||
* @param {VElement} node
|
||||
*/
|
||||
function isIgnoredElement(node) {
|
||||
return (
|
||||
ignores.includes(node.name) ||
|
||||
ignores.includes(casing.pascalCase(node.rawName)) ||
|
||||
ignores.includes(casing.kebabCase(node.rawName))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} lineBreaks
|
||||
*/
|
||||
function isInvalidLineBreaks(lineBreaks) {
|
||||
if (allowEmptyLines) {
|
||||
return lineBreaks === 0
|
||||
} else {
|
||||
return lineBreaks !== 1
|
||||
}
|
||||
}
|
||||
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
VElement(node) {
|
||||
if (inIgnoreElement) {
|
||||
return
|
||||
}
|
||||
if (isIgnoredElement(node)) {
|
||||
// ignore element name
|
||||
inIgnoreElement = node
|
||||
return
|
||||
}
|
||||
if (node.startTag.selfClosing || !node.endTag) {
|
||||
// self closing
|
||||
return
|
||||
}
|
||||
|
||||
const element = /** @type {VElement & { endTag: VEndTag }} */ (node)
|
||||
|
||||
if (!isMultilineElement(element)) {
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {SourceCode.CursorWithCountOptions}
|
||||
*/
|
||||
const getTokenOption = {
|
||||
includeComments: true,
|
||||
filter: (token) => token.type !== 'HTMLWhitespace'
|
||||
}
|
||||
if (
|
||||
ignoreWhenEmpty &&
|
||||
element.children.length === 0 &&
|
||||
template.getFirstTokensBetween(
|
||||
element.startTag,
|
||||
element.endTag,
|
||||
getTokenOption
|
||||
).length === 0
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const contentFirst = /** @type {Token} */ (
|
||||
template.getTokenAfter(element.startTag, getTokenOption)
|
||||
)
|
||||
const contentLast = /** @type {Token} */ (
|
||||
template.getTokenBefore(element.endTag, getTokenOption)
|
||||
)
|
||||
|
||||
const beforeLineBreaks =
|
||||
contentFirst.loc.start.line - element.startTag.loc.end.line
|
||||
const afterLineBreaks =
|
||||
element.endTag.loc.start.line - contentLast.loc.end.line
|
||||
if (isInvalidLineBreaks(beforeLineBreaks)) {
|
||||
context.report({
|
||||
node: template.getLastToken(element.startTag),
|
||||
loc: {
|
||||
start: element.startTag.loc.end,
|
||||
end: contentFirst.loc.start
|
||||
},
|
||||
messageId: 'unexpectedAfterClosingBracket',
|
||||
data: {
|
||||
name: element.rawName,
|
||||
actual: getPhrase(beforeLineBreaks)
|
||||
},
|
||||
fix(fixer) {
|
||||
/** @type {Range} */
|
||||
const range = [element.startTag.range[1], contentFirst.range[0]]
|
||||
return fixer.replaceTextRange(range, '\n')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (isEmpty(element, sourceCode)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (isInvalidLineBreaks(afterLineBreaks)) {
|
||||
context.report({
|
||||
node: template.getFirstToken(element.endTag),
|
||||
loc: {
|
||||
start: contentLast.loc.end,
|
||||
end: element.endTag.loc.start
|
||||
},
|
||||
messageId: 'unexpectedBeforeOpeningBracket',
|
||||
data: {
|
||||
name: element.name,
|
||||
actual: getPhrase(afterLineBreaks)
|
||||
},
|
||||
fix(fixer) {
|
||||
/** @type {Range} */
|
||||
const range = [contentLast.range[1], element.endTag.range[0]]
|
||||
return fixer.replaceTextRange(range, '\n')
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
'VElement:exit'(node) {
|
||||
if (inIgnoreElement === node) {
|
||||
inIgnoreElement = null
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
107
app_vue/node_modules/eslint-plugin-vue/lib/rules/mustache-interpolation-spacing.js
generated
vendored
Normal file
107
app_vue/node_modules/eslint-plugin-vue/lib/rules/mustache-interpolation-spacing.js
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @fileoverview enforce unified spacing in mustache interpolations.
|
||||
* @author Armano
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
docs: {
|
||||
description: 'enforce unified spacing in mustache interpolations',
|
||||
categories: ['vue3-strongly-recommended', 'strongly-recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/mustache-interpolation-spacing.html'
|
||||
},
|
||||
fixable: 'whitespace',
|
||||
schema: [
|
||||
{
|
||||
enum: ['always', 'never']
|
||||
}
|
||||
]
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const options = context.options[0] || 'always'
|
||||
const template =
|
||||
context.parserServices.getTemplateBodyTokenStore &&
|
||||
context.parserServices.getTemplateBodyTokenStore()
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
/** @param {VExpressionContainer} node */
|
||||
'VExpressionContainer[expression!=null]'(node) {
|
||||
const openBrace = template.getFirstToken(node)
|
||||
const closeBrace = template.getLastToken(node)
|
||||
|
||||
if (
|
||||
!openBrace ||
|
||||
!closeBrace ||
|
||||
openBrace.type !== 'VExpressionStart' ||
|
||||
closeBrace.type !== 'VExpressionEnd'
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const firstToken = template.getTokenAfter(openBrace, {
|
||||
includeComments: true
|
||||
})
|
||||
const lastToken = template.getTokenBefore(closeBrace, {
|
||||
includeComments: true
|
||||
})
|
||||
|
||||
if (options === 'always') {
|
||||
if (openBrace.range[1] === firstToken.range[0]) {
|
||||
context.report({
|
||||
node: openBrace,
|
||||
message: "Expected 1 space after '{{', but not found.",
|
||||
fix: (fixer) => fixer.insertTextAfter(openBrace, ' ')
|
||||
})
|
||||
}
|
||||
if (closeBrace.range[0] === lastToken.range[1]) {
|
||||
context.report({
|
||||
node: closeBrace,
|
||||
message: "Expected 1 space before '}}', but not found.",
|
||||
fix: (fixer) => fixer.insertTextBefore(closeBrace, ' ')
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (openBrace.range[1] !== firstToken.range[0]) {
|
||||
context.report({
|
||||
loc: {
|
||||
start: openBrace.loc.start,
|
||||
end: firstToken.loc.start
|
||||
},
|
||||
message: "Expected no space after '{{', but found.",
|
||||
fix: (fixer) =>
|
||||
fixer.removeRange([openBrace.range[1], firstToken.range[0]])
|
||||
})
|
||||
}
|
||||
if (closeBrace.range[0] !== lastToken.range[1]) {
|
||||
context.report({
|
||||
loc: {
|
||||
start: lastToken.loc.end,
|
||||
end: closeBrace.loc.end
|
||||
},
|
||||
message: "Expected no space before '}}', but found.",
|
||||
fix: (fixer) =>
|
||||
fixer.removeRange([lastToken.range[1], closeBrace.range[0]])
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
71
app_vue/node_modules/eslint-plugin-vue/lib/rules/name-property-casing.js
generated
vendored
Normal file
71
app_vue/node_modules/eslint-plugin-vue/lib/rules/name-property-casing.js
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @fileoverview Requires specific casing for the name property in Vue components
|
||||
* @author Armano
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
const casing = require('../utils/casing')
|
||||
const allowedCaseOptions = ['PascalCase', 'kebab-case']
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description:
|
||||
'enforce specific casing for the name property in Vue components',
|
||||
categories: ['vue3-strongly-recommended', 'strongly-recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/name-property-casing.html'
|
||||
},
|
||||
deprecated: true,
|
||||
replacedBy: ['component-definition-name-casing'],
|
||||
fixable: 'code', // or "code" or "whitespace"
|
||||
schema: [
|
||||
{
|
||||
enum: allowedCaseOptions
|
||||
}
|
||||
]
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const options = context.options[0]
|
||||
const caseType =
|
||||
allowedCaseOptions.indexOf(options) !== -1 ? options : 'PascalCase'
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
return utils.executeOnVue(context, (obj) => {
|
||||
const node = utils.findProperty(obj, 'name')
|
||||
|
||||
if (!node) return
|
||||
const valueNode = node.value
|
||||
if (valueNode.type !== 'Literal') return
|
||||
|
||||
if (!casing.getChecker(caseType)(`${valueNode.value}`)) {
|
||||
const value = casing.getExactConverter(caseType)(`${valueNode.value}`)
|
||||
context.report({
|
||||
node: valueNode,
|
||||
message: 'Property name "{{value}}" is not {{caseType}}.',
|
||||
data: {
|
||||
value: `${valueNode.value}`,
|
||||
caseType
|
||||
},
|
||||
fix: (fixer) =>
|
||||
fixer.replaceText(
|
||||
valueNode,
|
||||
context
|
||||
.getSourceCode()
|
||||
.getText(valueNode)
|
||||
.replace(`${valueNode.value}`, value)
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
154
app_vue/node_modules/eslint-plugin-vue/lib/rules/new-line-between-multi-line-property.js
generated
vendored
Normal file
154
app_vue/node_modules/eslint-plugin-vue/lib/rules/new-line-between-multi-line-property.js
generated
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
/**
|
||||
* @fileoverview Enforce new lines between multi-line properties in Vue components.
|
||||
* @author IWANABETHATGUY
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
/**
|
||||
* @param {Token} node
|
||||
*/
|
||||
function isComma(node) {
|
||||
return node.type === 'Punctuator' && node.value === ','
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the between given nodes has empty line.
|
||||
* @param {SourceCode} sourceCode
|
||||
* @param {ASTNode} pre
|
||||
* @param {ASTNode} cur
|
||||
*/
|
||||
function* iterateBetweenTokens(sourceCode, pre, cur) {
|
||||
yield sourceCode.getLastToken(pre)
|
||||
yield* sourceCode.getTokensBetween(pre, cur, {
|
||||
includeComments: true
|
||||
})
|
||||
yield sourceCode.getFirstToken(cur)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the between given nodes has empty line.
|
||||
* @param {SourceCode} sourceCode
|
||||
* @param {ASTNode} pre
|
||||
* @param {ASTNode} cur
|
||||
*/
|
||||
function hasEmptyLine(sourceCode, pre, cur) {
|
||||
/** @type {Token|null} */
|
||||
let preToken = null
|
||||
for (const token of iterateBetweenTokens(sourceCode, pre, cur)) {
|
||||
if (preToken && token.loc.start.line - preToken.loc.end.line >= 2) {
|
||||
return true
|
||||
}
|
||||
preToken = token
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
docs: {
|
||||
description:
|
||||
'enforce new lines between multi-line properties in Vue components',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/new-line-between-multi-line-property.html'
|
||||
},
|
||||
fixable: 'whitespace', // or "code" or "whitespace"
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
// number of line you want to insert after multi-line property
|
||||
minLineOfMultilineProperty: {
|
||||
type: 'number',
|
||||
minimum: 2
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
let minLineOfMultilineProperty = 2
|
||||
if (
|
||||
context.options &&
|
||||
context.options[0] &&
|
||||
context.options[0].minLineOfMultilineProperty
|
||||
) {
|
||||
minLineOfMultilineProperty = context.options[0].minLineOfMultilineProperty
|
||||
}
|
||||
|
||||
/** @type {CallExpression[]} */
|
||||
const callStack = []
|
||||
const sourceCode = context.getSourceCode()
|
||||
return Object.assign(
|
||||
utils.defineVueVisitor(context, {
|
||||
CallExpression(node) {
|
||||
callStack.push(node)
|
||||
},
|
||||
'CallExpression:exit'() {
|
||||
callStack.pop()
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {ObjectExpression} node
|
||||
*/
|
||||
ObjectExpression(node) {
|
||||
if (callStack.length) {
|
||||
return
|
||||
}
|
||||
const properties = node.properties
|
||||
for (let i = 1; i < properties.length; i++) {
|
||||
const cur = properties[i]
|
||||
const pre = properties[i - 1]
|
||||
|
||||
const lineCountOfPreProperty =
|
||||
pre.loc.end.line - pre.loc.start.line + 1
|
||||
if (lineCountOfPreProperty < minLineOfMultilineProperty) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (hasEmptyLine(sourceCode, pre, cur)) {
|
||||
continue
|
||||
}
|
||||
|
||||
context.report({
|
||||
node: pre,
|
||||
loc: {
|
||||
start: pre.loc.end,
|
||||
end: cur.loc.start
|
||||
},
|
||||
message:
|
||||
'Enforce new lines between multi-line properties in Vue components.',
|
||||
fix(fixer) {
|
||||
/** @type {Token|null} */
|
||||
let preToken = null
|
||||
for (const token of iterateBetweenTokens(
|
||||
sourceCode,
|
||||
pre,
|
||||
cur
|
||||
)) {
|
||||
if (
|
||||
preToken &&
|
||||
preToken.loc.end.line < token.loc.start.line
|
||||
) {
|
||||
return fixer.insertTextAfter(preToken, '\n')
|
||||
}
|
||||
preToken = token
|
||||
}
|
||||
const commaToken = sourceCode.getTokenAfter(pre, isComma)
|
||||
return fixer.insertTextAfter(commaToken || pre, '\n\n')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
146
app_vue/node_modules/eslint-plugin-vue/lib/rules/next-tick-style.js
generated
vendored
Normal file
146
app_vue/node_modules/eslint-plugin-vue/lib/rules/next-tick-style.js
generated
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
/**
|
||||
* @fileoverview enforce Promise or callback style in `nextTick`
|
||||
* @author Flo Edelmann
|
||||
* @copyright 2020 Flo Edelmann. All rights reserved.
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
const { findVariable } = require('eslint-utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {Identifier} identifier
|
||||
* @param {RuleContext} context
|
||||
* @returns {CallExpression|undefined}
|
||||
*/
|
||||
function getVueNextTickCallExpression(identifier, context) {
|
||||
// Instance API: this.$nextTick()
|
||||
if (
|
||||
identifier.name === '$nextTick' &&
|
||||
identifier.parent.type === 'MemberExpression' &&
|
||||
utils.isThis(identifier.parent.object, context) &&
|
||||
identifier.parent.parent.type === 'CallExpression' &&
|
||||
identifier.parent.parent.callee === identifier.parent
|
||||
) {
|
||||
return identifier.parent.parent
|
||||
}
|
||||
|
||||
// Vue 2 Global API: Vue.nextTick()
|
||||
if (
|
||||
identifier.name === 'nextTick' &&
|
||||
identifier.parent.type === 'MemberExpression' &&
|
||||
identifier.parent.object.type === 'Identifier' &&
|
||||
identifier.parent.object.name === 'Vue' &&
|
||||
identifier.parent.parent.type === 'CallExpression' &&
|
||||
identifier.parent.parent.callee === identifier.parent
|
||||
) {
|
||||
return identifier.parent.parent
|
||||
}
|
||||
|
||||
// Vue 3 Global API: import { nextTick as nt } from 'vue'; nt()
|
||||
if (
|
||||
identifier.parent.type === 'CallExpression' &&
|
||||
identifier.parent.callee === identifier
|
||||
) {
|
||||
const variable = findVariable(context.getScope(), identifier)
|
||||
|
||||
if (variable != null && variable.defs.length === 1) {
|
||||
const def = variable.defs[0]
|
||||
if (
|
||||
def.type === 'ImportBinding' &&
|
||||
def.node.type === 'ImportSpecifier' &&
|
||||
def.node.imported.type === 'Identifier' &&
|
||||
def.node.imported.name === 'nextTick' &&
|
||||
def.node.parent.type === 'ImportDeclaration' &&
|
||||
def.node.parent.source.value === 'vue'
|
||||
) {
|
||||
return identifier.parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CallExpression} callExpression
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isAwaitedPromise(callExpression) {
|
||||
return (
|
||||
callExpression.parent.type === 'AwaitExpression' ||
|
||||
(callExpression.parent.type === 'MemberExpression' &&
|
||||
callExpression.parent.property.type === 'Identifier' &&
|
||||
callExpression.parent.property.name === 'then')
|
||||
)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'enforce Promise or callback style in `nextTick`',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/next-tick-style.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [{ enum: ['promise', 'callback'] }]
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const preferredStyle =
|
||||
/** @type {string|undefined} */ (context.options[0]) || 'promise'
|
||||
|
||||
return utils.defineVueVisitor(context, {
|
||||
/** @param {Identifier} node */
|
||||
Identifier(node) {
|
||||
const callExpression = getVueNextTickCallExpression(node, context)
|
||||
if (!callExpression) {
|
||||
return
|
||||
}
|
||||
|
||||
if (preferredStyle === 'callback') {
|
||||
if (
|
||||
callExpression.arguments.length !== 1 ||
|
||||
isAwaitedPromise(callExpression)
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
message:
|
||||
'Pass a callback function to `nextTick` instead of using the returned Promise.'
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
callExpression.arguments.length !== 0 ||
|
||||
!isAwaitedPromise(callExpression)
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
message:
|
||||
'Use the Promise returned by `nextTick` instead of passing a callback function.',
|
||||
fix(fixer) {
|
||||
return fixer.insertTextAfter(node, '().then')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
47
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-arrow-functions-in-watch.js
generated
vendored
Normal file
47
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-arrow-functions-in-watch.js
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @author Sosuke Suzuki
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'disallow using arrow functions to define watcher',
|
||||
categories: ['vue3-essential', 'essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-arrow-functions-in-watch.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: []
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
return utils.executeOnVue(context, (obj) => {
|
||||
const watchNode = utils.findProperty(obj, 'watch')
|
||||
if (watchNode == null) {
|
||||
return
|
||||
}
|
||||
const watchValue = watchNode.value
|
||||
if (watchValue.type !== 'ObjectExpression') {
|
||||
return
|
||||
}
|
||||
for (const property of watchValue.properties) {
|
||||
if (property.type !== 'Property') {
|
||||
continue
|
||||
}
|
||||
|
||||
for (const handler of utils.iterateWatchHandlerValues(property)) {
|
||||
if (handler.type === 'ArrowFunctionExpression') {
|
||||
context.report({
|
||||
node: handler,
|
||||
message:
|
||||
'You should not use an arrow function to define a watcher.'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
293
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-async-in-computed-properties.js
generated
vendored
Normal file
293
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-async-in-computed-properties.js
generated
vendored
Normal file
@ -0,0 +1,293 @@
|
||||
/**
|
||||
* @fileoverview Check if there are no asynchronous actions inside computed properties.
|
||||
* @author Armano
|
||||
*/
|
||||
'use strict'
|
||||
const { ReferenceTracker } = require('eslint-utils')
|
||||
const utils = require('../utils')
|
||||
|
||||
/**
|
||||
* @typedef {import('../utils').VueObjectData} VueObjectData
|
||||
* @typedef {import('../utils').VueVisitor} VueVisitor
|
||||
* @typedef {import('../utils').ComponentComputedProperty} ComponentComputedProperty
|
||||
*/
|
||||
|
||||
const PROMISE_FUNCTIONS = new Set(['then', 'catch', 'finally'])
|
||||
|
||||
const PROMISE_METHODS = new Set(['all', 'race', 'reject', 'resolve'])
|
||||
|
||||
const TIMED_FUNCTIONS = new Set([
|
||||
'setTimeout',
|
||||
'setInterval',
|
||||
'setImmediate',
|
||||
'requestAnimationFrame'
|
||||
])
|
||||
|
||||
/**
|
||||
* @param {CallExpression} node
|
||||
*/
|
||||
function isTimedFunction(node) {
|
||||
const callee = utils.skipChainExpression(node.callee)
|
||||
return (
|
||||
((callee.type === 'Identifier' && TIMED_FUNCTIONS.has(callee.name)) ||
|
||||
(callee.type === 'MemberExpression' &&
|
||||
callee.object.type === 'Identifier' &&
|
||||
callee.object.name === 'window' &&
|
||||
TIMED_FUNCTIONS.has(utils.getStaticPropertyName(callee) || ''))) &&
|
||||
node.arguments.length > 0
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CallExpression} node
|
||||
*/
|
||||
function isPromise(node) {
|
||||
const callee = utils.skipChainExpression(node.callee)
|
||||
if (callee.type === 'MemberExpression') {
|
||||
const name = utils.getStaticPropertyName(callee)
|
||||
return (
|
||||
name &&
|
||||
// hello.PROMISE_FUNCTION()
|
||||
(PROMISE_FUNCTIONS.has(name) ||
|
||||
// Promise.PROMISE_METHOD()
|
||||
(callee.object.type === 'Identifier' &&
|
||||
callee.object.name === 'Promise' &&
|
||||
PROMISE_METHODS.has(name)))
|
||||
)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CallExpression} node
|
||||
* @param {RuleContext} context
|
||||
*/
|
||||
function isNextTick(node, context) {
|
||||
const callee = utils.skipChainExpression(node.callee)
|
||||
if (callee.type === 'MemberExpression') {
|
||||
const name = utils.getStaticPropertyName(callee)
|
||||
return (
|
||||
(utils.isThis(callee.object, context) && name === '$nextTick') ||
|
||||
(callee.object.type === 'Identifier' &&
|
||||
callee.object.name === 'Vue' &&
|
||||
name === 'nextTick')
|
||||
)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'disallow asynchronous actions in computed properties',
|
||||
categories: ['vue3-essential', 'essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-async-in-computed-properties.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: []
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
/** @type {Map<ObjectExpression, ComponentComputedProperty[]>} */
|
||||
const computedPropertiesMap = new Map()
|
||||
/** @type {(FunctionExpression | ArrowFunctionExpression)[]} */
|
||||
const computedFunctionNodes = []
|
||||
|
||||
/**
|
||||
* @typedef {object} ScopeStack
|
||||
* @property {ScopeStack | null} upper
|
||||
* @property {BlockStatement | Expression} body
|
||||
*/
|
||||
/** @type {ScopeStack | null} */
|
||||
let scopeStack = null
|
||||
|
||||
const expressionTypes = {
|
||||
promise: 'asynchronous action',
|
||||
nextTick: 'asynchronous action',
|
||||
await: 'await operator',
|
||||
async: 'async function declaration',
|
||||
new: 'Promise object',
|
||||
timed: 'timed function'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node
|
||||
* @param {VueObjectData|undefined} [info]
|
||||
*/
|
||||
function onFunctionEnter(node, info) {
|
||||
if (node.async) {
|
||||
verify(
|
||||
node,
|
||||
node.body,
|
||||
'async',
|
||||
info ? computedPropertiesMap.get(info.node) : null
|
||||
)
|
||||
}
|
||||
|
||||
scopeStack = {
|
||||
upper: scopeStack,
|
||||
body: node.body
|
||||
}
|
||||
}
|
||||
|
||||
function onFunctionExit() {
|
||||
scopeStack = scopeStack && scopeStack.upper
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ESNode} node
|
||||
* @param {BlockStatement | Expression} targetBody
|
||||
* @param {keyof expressionTypes} type
|
||||
* @param {ComponentComputedProperty[]|undefined|null} computedProperties
|
||||
*/
|
||||
function verify(node, targetBody, type, computedProperties) {
|
||||
for (const cp of computedProperties || []) {
|
||||
if (
|
||||
cp.value &&
|
||||
node.loc.start.line >= cp.value.loc.start.line &&
|
||||
node.loc.end.line <= cp.value.loc.end.line &&
|
||||
targetBody === cp.value
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
message:
|
||||
'Unexpected {{expressionName}} in "{{propertyName}}" computed property.',
|
||||
data: {
|
||||
expressionName: expressionTypes[type],
|
||||
propertyName: cp.key || 'unknown'
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for (const cf of computedFunctionNodes) {
|
||||
if (
|
||||
node.loc.start.line >= cf.body.loc.start.line &&
|
||||
node.loc.end.line <= cf.body.loc.end.line &&
|
||||
targetBody === cf.body
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
message: 'Unexpected {{expressionName}} in computed function.',
|
||||
data: {
|
||||
expressionName: expressionTypes[type]
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
const nodeVisitor = {
|
||||
':function': onFunctionEnter,
|
||||
':function:exit': onFunctionExit,
|
||||
|
||||
/**
|
||||
* @param {NewExpression} node
|
||||
* @param {VueObjectData|undefined} [info]
|
||||
*/
|
||||
NewExpression(node, info) {
|
||||
if (!scopeStack) {
|
||||
return
|
||||
}
|
||||
if (
|
||||
node.callee.type === 'Identifier' &&
|
||||
node.callee.name === 'Promise'
|
||||
) {
|
||||
verify(
|
||||
node,
|
||||
scopeStack.body,
|
||||
'new',
|
||||
info ? computedPropertiesMap.get(info.node) : null
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {CallExpression} node
|
||||
* @param {VueObjectData|undefined} [info]
|
||||
*/
|
||||
CallExpression(node, info) {
|
||||
if (!scopeStack) {
|
||||
return
|
||||
}
|
||||
if (isPromise(node)) {
|
||||
verify(
|
||||
node,
|
||||
scopeStack.body,
|
||||
'promise',
|
||||
info ? computedPropertiesMap.get(info.node) : null
|
||||
)
|
||||
} else if (isTimedFunction(node)) {
|
||||
verify(
|
||||
node,
|
||||
scopeStack.body,
|
||||
'timed',
|
||||
info ? computedPropertiesMap.get(info.node) : null
|
||||
)
|
||||
} else if (isNextTick(node, context)) {
|
||||
verify(
|
||||
node,
|
||||
scopeStack.body,
|
||||
'nextTick',
|
||||
info ? computedPropertiesMap.get(info.node) : null
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {AwaitExpression} node
|
||||
* @param {VueObjectData|undefined} [info]
|
||||
*/
|
||||
AwaitExpression(node, info) {
|
||||
if (!scopeStack) {
|
||||
return
|
||||
}
|
||||
verify(
|
||||
node,
|
||||
scopeStack.body,
|
||||
'await',
|
||||
info ? computedPropertiesMap.get(info.node) : null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return utils.compositingVisitors(
|
||||
{
|
||||
Program() {
|
||||
const tracker = new ReferenceTracker(context.getScope())
|
||||
const traceMap = utils.createCompositionApiTraceMap({
|
||||
[ReferenceTracker.ESM]: true,
|
||||
computed: {
|
||||
[ReferenceTracker.CALL]: true
|
||||
}
|
||||
})
|
||||
|
||||
for (const { node } of tracker.iterateEsmReferences(traceMap)) {
|
||||
if (node.type !== 'CallExpression') {
|
||||
continue
|
||||
}
|
||||
|
||||
const getter = utils.getGetterBodyFromComputedFunction(node)
|
||||
if (getter) {
|
||||
computedFunctionNodes.push(getter)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
utils.isScriptSetup(context)
|
||||
? utils.defineScriptSetupVisitor(context, nodeVisitor)
|
||||
: utils.defineVueVisitor(context, {
|
||||
onVueObjectEnter(node) {
|
||||
computedPropertiesMap.set(node, utils.getComputedProperties(node))
|
||||
},
|
||||
...nodeVisitor
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
276
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-bare-strings-in-template.js
generated
vendored
Normal file
276
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-bare-strings-in-template.js
generated
vendored
Normal file
@ -0,0 +1,276 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
const regexp = require('../utils/regexp')
|
||||
const casing = require('../utils/casing')
|
||||
|
||||
/**
|
||||
* @typedef { { names: { [tagName in string]: Set<string> }, regexps: { name: RegExp, attrs: Set<string> }[], cache: { [tagName in string]: Set<string> } } } TargetAttrs
|
||||
*/
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
// https://dev.w3.org/html5/html-author/charref
|
||||
const DEFAULT_ALLOWLIST = [
|
||||
'(',
|
||||
')',
|
||||
',',
|
||||
'.',
|
||||
'&',
|
||||
'+',
|
||||
'-',
|
||||
'=',
|
||||
'*',
|
||||
'/',
|
||||
'#',
|
||||
'%',
|
||||
'!',
|
||||
'?',
|
||||
':',
|
||||
'[',
|
||||
']',
|
||||
'{',
|
||||
'}',
|
||||
'<',
|
||||
'>',
|
||||
'\u00b7', // "·"
|
||||
'\u2022', // "•"
|
||||
'\u2010', // "‐"
|
||||
'\u2013', // "–"
|
||||
'\u2014', // "—"
|
||||
'\u2212', // "−"
|
||||
'|'
|
||||
]
|
||||
|
||||
const DEFAULT_ATTRIBUTES = {
|
||||
'/.+/': [
|
||||
'title',
|
||||
'aria-label',
|
||||
'aria-placeholder',
|
||||
'aria-roledescription',
|
||||
'aria-valuetext'
|
||||
],
|
||||
input: ['placeholder'],
|
||||
img: ['alt']
|
||||
}
|
||||
|
||||
const DEFAULT_DIRECTIVES = ['v-text']
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse attributes option
|
||||
* @param {any} options
|
||||
* @returns {TargetAttrs}
|
||||
*/
|
||||
function parseTargetAttrs(options) {
|
||||
/** @type {TargetAttrs} */
|
||||
const result = { names: {}, regexps: [], cache: {} }
|
||||
for (const tagName of Object.keys(options)) {
|
||||
/** @type { Set<string> } */
|
||||
const attrs = new Set(options[tagName])
|
||||
if (regexp.isRegExp(tagName)) {
|
||||
result.regexps.push({
|
||||
name: regexp.toRegExp(tagName),
|
||||
attrs
|
||||
})
|
||||
} else {
|
||||
result.names[tagName] = attrs
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string from given expression container node
|
||||
* @param {VExpressionContainer} value
|
||||
* @returns { string | null }
|
||||
*/
|
||||
function getStringValue(value) {
|
||||
const expression = value.expression
|
||||
if (!expression) {
|
||||
return null
|
||||
}
|
||||
if (expression.type !== 'Literal') {
|
||||
return null
|
||||
}
|
||||
if (typeof expression.value === 'string') {
|
||||
return expression.value
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'disallow the use of bare strings in `<template>`',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/no-bare-strings-in-template.html'
|
||||
},
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
allowlist: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
uniqueItems: true
|
||||
},
|
||||
attributes: {
|
||||
type: 'object',
|
||||
patternProperties: {
|
||||
'^(?:\\S+|/.*/[a-z]*)$': {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
uniqueItems: true
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
},
|
||||
directives: {
|
||||
type: 'array',
|
||||
items: { type: 'string', pattern: '^v-' },
|
||||
uniqueItems: true
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
unexpected: 'Unexpected non-translated string used.',
|
||||
unexpectedInAttr: 'Unexpected non-translated string used in `{{attr}}`.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
/**
|
||||
* @typedef { { upper: ElementStack | null, name: string, attrs: Set<string> } } ElementStack
|
||||
*/
|
||||
const opts = context.options[0] || {}
|
||||
/** @type {string[]} */
|
||||
const allowlist = opts.allowlist || DEFAULT_ALLOWLIST
|
||||
const attributes = parseTargetAttrs(opts.attributes || DEFAULT_ATTRIBUTES)
|
||||
const directives = opts.directives || DEFAULT_DIRECTIVES
|
||||
|
||||
const allowlistRe = new RegExp(
|
||||
allowlist.map((w) => regexp.escape(w)).join('|'),
|
||||
'gu'
|
||||
)
|
||||
|
||||
/** @type {ElementStack | null} */
|
||||
let elementStack = null
|
||||
/**
|
||||
* Gets the bare string from given string
|
||||
* @param {string} str
|
||||
*/
|
||||
function getBareString(str) {
|
||||
return str.trim().replace(allowlistRe, '').trim()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attribute to be verified from the element name.
|
||||
* @param {string} tagName
|
||||
* @returns {Set<string>}
|
||||
*/
|
||||
function getTargetAttrs(tagName) {
|
||||
if (attributes.cache[tagName]) {
|
||||
return attributes.cache[tagName]
|
||||
}
|
||||
/** @type {string[]} */
|
||||
const result = []
|
||||
if (attributes.names[tagName]) {
|
||||
result.push(...attributes.names[tagName])
|
||||
}
|
||||
for (const { name, attrs } of attributes.regexps) {
|
||||
name.lastIndex = 0
|
||||
if (name.test(tagName)) {
|
||||
result.push(...attrs)
|
||||
}
|
||||
}
|
||||
if (casing.isKebabCase(tagName)) {
|
||||
result.push(...getTargetAttrs(casing.pascalCase(tagName)))
|
||||
}
|
||||
|
||||
return (attributes.cache[tagName] = new Set(result))
|
||||
}
|
||||
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
/** @param {VText} node */
|
||||
VText(node) {
|
||||
if (getBareString(node.value)) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'unexpected'
|
||||
})
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {VElement} node
|
||||
*/
|
||||
VElement(node) {
|
||||
elementStack = {
|
||||
upper: elementStack,
|
||||
name: node.rawName,
|
||||
attrs: getTargetAttrs(node.rawName)
|
||||
}
|
||||
},
|
||||
'VElement:exit'() {
|
||||
elementStack = elementStack && elementStack.upper
|
||||
},
|
||||
/** @param {VAttribute|VDirective} node */
|
||||
VAttribute(node) {
|
||||
if (!node.value || !elementStack) {
|
||||
return
|
||||
}
|
||||
if (node.directive === false) {
|
||||
const attrs = elementStack.attrs
|
||||
if (!attrs.has(node.key.rawName)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (getBareString(node.value.value)) {
|
||||
context.report({
|
||||
node: node.value,
|
||||
messageId: 'unexpectedInAttr',
|
||||
data: {
|
||||
attr: node.key.rawName
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
const directive = `v-${node.key.name.name}`
|
||||
if (!directives.includes(directive)) {
|
||||
return
|
||||
}
|
||||
const str = getStringValue(node.value)
|
||||
if (str && getBareString(str)) {
|
||||
context.report({
|
||||
node: node.value,
|
||||
messageId: 'unexpectedInAttr',
|
||||
data: {
|
||||
attr: directive
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
128
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-boolean-default.js
generated
vendored
Normal file
128
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-boolean-default.js
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
/**
|
||||
* @fileoverview Prevents boolean defaults from being set
|
||||
* @author Hiroki Osame
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
/**
|
||||
* @typedef {import('../utils').ComponentProp} ComponentProp
|
||||
*/
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {Property | SpreadElement} prop
|
||||
*/
|
||||
function isBooleanProp(prop) {
|
||||
return (
|
||||
prop.type === 'Property' &&
|
||||
prop.key.type === 'Identifier' &&
|
||||
prop.key.name === 'type' &&
|
||||
prop.value.type === 'Identifier' &&
|
||||
prop.value.name === 'Boolean'
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectExpression} propDefValue
|
||||
*/
|
||||
function getDefaultNode(propDefValue) {
|
||||
return utils.findProperty(propDefValue, 'default')
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'disallow boolean defaults',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/no-boolean-default.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [
|
||||
{
|
||||
enum: ['default-false', 'no-default']
|
||||
}
|
||||
]
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const booleanType = context.options[0] || 'no-default'
|
||||
/**
|
||||
* @param {ComponentProp} prop
|
||||
* @param { { [key: string]: Expression | undefined } } [withDefaultsExpressions]
|
||||
*/
|
||||
function processProp(prop, withDefaultsExpressions) {
|
||||
if (prop.type === 'object') {
|
||||
if (prop.value.type !== 'ObjectExpression') {
|
||||
return
|
||||
}
|
||||
if (!prop.value.properties.some(isBooleanProp)) {
|
||||
return
|
||||
}
|
||||
const defaultNode = getDefaultNode(prop.value)
|
||||
if (!defaultNode) {
|
||||
return
|
||||
}
|
||||
verifyDefaultExpression(defaultNode.value)
|
||||
} else if (prop.type === 'type') {
|
||||
if (prop.types.length !== 1 || prop.types[0] !== 'Boolean') {
|
||||
return
|
||||
}
|
||||
const defaultNode =
|
||||
withDefaultsExpressions && withDefaultsExpressions[prop.propName]
|
||||
if (!defaultNode) {
|
||||
return
|
||||
}
|
||||
verifyDefaultExpression(defaultNode)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {ComponentProp[]} props
|
||||
* @param { { [key: string]: Expression | undefined } } [withDefaultsExpressions]
|
||||
*/
|
||||
function processProps(props, withDefaultsExpressions) {
|
||||
for (const prop of props) {
|
||||
processProp(prop, withDefaultsExpressions)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Expression} defaultNode
|
||||
*/
|
||||
function verifyDefaultExpression(defaultNode) {
|
||||
switch (booleanType) {
|
||||
case 'no-default':
|
||||
context.report({
|
||||
node: defaultNode,
|
||||
message:
|
||||
'Boolean prop should not set a default (Vue defaults it to false).'
|
||||
})
|
||||
break
|
||||
|
||||
case 'default-false':
|
||||
if (defaultNode.type !== 'Literal' || defaultNode.value !== false) {
|
||||
context.report({
|
||||
node: defaultNode,
|
||||
message: 'Boolean prop should only be defaulted to false.'
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return utils.compositingVisitors(
|
||||
utils.executeOnVueComponent(context, (obj) => {
|
||||
processProps(utils.getComponentPropsFromOptions(obj))
|
||||
}),
|
||||
utils.defineScriptSetupVisitor(context, {
|
||||
onDefinePropsEnter(node, props) {
|
||||
processProps(props, utils.getWithDefaultsPropExpressions(node))
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
164
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-child-content.js
generated
vendored
Normal file
164
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-child-content.js
generated
vendored
Normal file
@ -0,0 +1,164 @@
|
||||
/**
|
||||
* @author Flo Edelmann
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
const { defineTemplateBodyVisitor } = require('../utils')
|
||||
|
||||
/**
|
||||
* @typedef {object} RuleOption
|
||||
* @property {string[]} additionalDirectives
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {VNode | Token} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isWhiteSpaceTextNode(node) {
|
||||
return node.type === 'VText' && node.value.trim() === ''
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Position} pos1
|
||||
* @param {Position} pos2
|
||||
* @returns {'less' | 'equal' | 'greater'}
|
||||
*/
|
||||
function comparePositions(pos1, pos2) {
|
||||
if (
|
||||
pos1.line < pos2.line ||
|
||||
(pos1.line === pos2.line && pos1.column < pos2.column)
|
||||
) {
|
||||
return 'less'
|
||||
}
|
||||
|
||||
if (
|
||||
pos1.line > pos2.line ||
|
||||
(pos1.line === pos2.line && pos1.column > pos2.column)
|
||||
) {
|
||||
return 'greater'
|
||||
}
|
||||
|
||||
return 'equal'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {(VNode | Token)[]} nodes
|
||||
* @returns {SourceLocation | undefined}
|
||||
*/
|
||||
function getLocationRange(nodes) {
|
||||
/** @type {Position | undefined} */
|
||||
let start
|
||||
/** @type {Position | undefined} */
|
||||
let end
|
||||
|
||||
for (const node of nodes) {
|
||||
if (!start || comparePositions(node.loc.start, start) === 'less') {
|
||||
start = node.loc.start
|
||||
}
|
||||
|
||||
if (!end || comparePositions(node.loc.end, end) === 'greater') {
|
||||
end = node.loc.end
|
||||
}
|
||||
}
|
||||
|
||||
if (start === undefined || end === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return { start, end }
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
hasSuggestions: true,
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
"disallow element's child contents which would be overwritten by a directive like `v-html` or `v-text`",
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/no-child-content.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
additionalDirectives: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
minItems: 1,
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ['additionalDirectives']
|
||||
}
|
||||
]
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const directives = new Set(['html', 'text'])
|
||||
|
||||
/** @type {RuleOption | undefined} */
|
||||
const option = context.options[0]
|
||||
if (option !== undefined) {
|
||||
for (const directive of option.additionalDirectives) {
|
||||
directives.add(directive)
|
||||
}
|
||||
}
|
||||
|
||||
return defineTemplateBodyVisitor(context, {
|
||||
/** @param {VDirective} directiveNode */
|
||||
'VAttribute[directive=true]'(directiveNode) {
|
||||
const directiveName = directiveNode.key.name.name
|
||||
const elementNode = directiveNode.parent.parent
|
||||
|
||||
if (elementNode.endTag === null) {
|
||||
return
|
||||
}
|
||||
|
||||
const tokenStore = context.parserServices.getTemplateBodyTokenStore()
|
||||
const elementComments = tokenStore.getTokensBetween(
|
||||
elementNode.startTag,
|
||||
elementNode.endTag,
|
||||
{
|
||||
includeComments: true,
|
||||
filter: (token) => token.type === 'HTMLComment'
|
||||
}
|
||||
)
|
||||
|
||||
const childNodes = [...elementNode.children, ...elementComments]
|
||||
|
||||
if (
|
||||
directives.has(directiveName) &&
|
||||
childNodes.length > 0 &&
|
||||
childNodes.some((childNode) => !isWhiteSpaceTextNode(childNode))
|
||||
) {
|
||||
context.report({
|
||||
node: elementNode,
|
||||
loc: getLocationRange(childNodes),
|
||||
message:
|
||||
'Child content is disallowed because it will be overwritten by the v-{{ directiveName }} directive.',
|
||||
data: { directiveName },
|
||||
suggest: [
|
||||
{
|
||||
desc: 'Remove child content.',
|
||||
*fix(fixer) {
|
||||
for (const childNode of childNodes) {
|
||||
yield fixer.remove(childNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
108
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-computed-properties-in-data.js
generated
vendored
Normal file
108
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-computed-properties-in-data.js
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
/**
|
||||
* @typedef {import('../utils').VueObjectData} VueObjectData
|
||||
*/
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'disallow accessing computed properties in `data`.',
|
||||
categories: ['vue3-essential', 'essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-computed-properties-in-data.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
cannotBeUsed:
|
||||
'The computed property cannot be used in `data()` because it is before initialization.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
/** @type {Map<ObjectExpression, {data: FunctionExpression | ArrowFunctionExpression, computedNames:Set<string>}>} */
|
||||
const contextMap = new Map()
|
||||
|
||||
/**
|
||||
* @typedef {object} ScopeStack
|
||||
* @property {ScopeStack | null} upper
|
||||
* @property {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node
|
||||
*/
|
||||
/** @type {ScopeStack | null} */
|
||||
let scopeStack = null
|
||||
|
||||
return utils.compositingVisitors(
|
||||
{
|
||||
/**
|
||||
* @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node
|
||||
*/
|
||||
':function'(node) {
|
||||
scopeStack = {
|
||||
upper: scopeStack,
|
||||
node
|
||||
}
|
||||
},
|
||||
':function:exit'() {
|
||||
scopeStack = scopeStack && scopeStack.upper
|
||||
}
|
||||
},
|
||||
utils.defineVueVisitor(context, {
|
||||
onVueObjectEnter(node) {
|
||||
const dataProperty = utils.findProperty(node, 'data')
|
||||
if (
|
||||
!dataProperty ||
|
||||
(dataProperty.value.type !== 'FunctionExpression' &&
|
||||
dataProperty.value.type !== 'ArrowFunctionExpression')
|
||||
) {
|
||||
return
|
||||
}
|
||||
const computedNames = new Set()
|
||||
for (const computed of utils.iterateProperties(
|
||||
node,
|
||||
new Set(['computed'])
|
||||
)) {
|
||||
computedNames.add(computed.name)
|
||||
}
|
||||
|
||||
contextMap.set(node, { data: dataProperty.value, computedNames })
|
||||
},
|
||||
/**
|
||||
* @param {MemberExpression} node
|
||||
* @param {VueObjectData} vueData
|
||||
*/
|
||||
MemberExpression(node, vueData) {
|
||||
if (!scopeStack || !utils.isThis(node.object, context)) {
|
||||
return
|
||||
}
|
||||
const ctx = contextMap.get(vueData.node)
|
||||
if (!ctx || ctx.data !== scopeStack.node) {
|
||||
return
|
||||
}
|
||||
const name = utils.getStaticPropertyName(node)
|
||||
if (!name || !ctx.computedNames.has(name)) {
|
||||
return
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'cannotBeUsed'
|
||||
})
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
69
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-confusing-v-for-v-if.js
generated
vendored
Normal file
69
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-confusing-v-for-v-if.js
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @author Toru Nagashima
|
||||
* @copyright 2017 Toru Nagashima. All rights reserved.
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Check whether the given `v-if` node is using the variable which is defined by the `v-for` directive.
|
||||
* @param {VDirective} vIf The `v-if` attribute node to check.
|
||||
* @returns {boolean} `true` if the `v-if` is using the variable which is defined by the `v-for` directive.
|
||||
*/
|
||||
function isUsingIterationVar(vIf) {
|
||||
const element = vIf.parent.parent
|
||||
return Boolean(
|
||||
vIf.value &&
|
||||
vIf.value.references.some((reference) =>
|
||||
element.variables.some(
|
||||
(variable) =>
|
||||
variable.id.name === reference.id.name && variable.kind === 'v-for'
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'disallow confusing `v-for` and `v-if` on the same element',
|
||||
categories: ['vue3-recommended', 'recommended'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-confusing-v-for-v-if.html'
|
||||
},
|
||||
deprecated: true,
|
||||
replacedBy: ['no-use-v-if-with-v-for'],
|
||||
fixable: null,
|
||||
schema: []
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
"VAttribute[directive=true][key.name.name='if']"(node) {
|
||||
const element = node.parent.parent
|
||||
|
||||
if (utils.hasDirective(element, 'for') && !isUsingIterationVar(node)) {
|
||||
context.report({
|
||||
node,
|
||||
loc: node.loc,
|
||||
message: "This 'v-if' should be moved to the wrapper element."
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
29
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-constant-condition.js
generated
vendored
Normal file
29
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-constant-condition.js
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @author Flo Edelmann
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
const conditionalDirectiveNames = new Set(['v-show', 'v-if', 'v-else-if'])
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('no-constant-condition', {
|
||||
create(_context, { coreHandlers }) {
|
||||
return {
|
||||
VDirectiveKey(node) {
|
||||
if (
|
||||
conditionalDirectiveNames.has(`v-${node.name.name}`) &&
|
||||
node.parent.value &&
|
||||
node.parent.value.expression &&
|
||||
coreHandlers.IfStatement
|
||||
) {
|
||||
coreHandlers.IfStatement({
|
||||
// @ts-expect-error -- Process expression of VExpressionContainer as IfStatement.
|
||||
test: node.parent.value.expression
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
59
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-custom-modifiers-on-v-model.js
generated
vendored
Normal file
59
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-custom-modifiers-on-v-model.js
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @author Przemyslaw Falowski (@przemkow)
|
||||
* @fileoverview This rule checks whether v-model used on the component do not have custom modifiers
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const VALID_MODIFIERS = new Set(['lazy', 'number', 'trim'])
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'disallow custom modifiers on v-model used on the component',
|
||||
categories: ['essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-custom-modifiers-on-v-model.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
notSupportedModifier:
|
||||
"'v-model' directives don't support the modifier '{{name}}'."
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
"VAttribute[directive=true][key.name.name='model']"(node) {
|
||||
const element = node.parent.parent
|
||||
|
||||
if (utils.isCustomComponent(element)) {
|
||||
for (const modifier of node.key.modifiers) {
|
||||
if (!VALID_MODIFIERS.has(modifier.name)) {
|
||||
context.report({
|
||||
node,
|
||||
loc: node.loc,
|
||||
messageId: 'notSupportedModifier',
|
||||
data: { name: modifier.name }
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
94
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-data-object-declaration.js
generated
vendored
Normal file
94
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-data-object-declaration.js
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* @fileoverview disallow using deprecated object declaration on data
|
||||
* @author yoyo930021
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
/** @param {Token} token */
|
||||
function isOpenParen(token) {
|
||||
return token.type === 'Punctuator' && token.value === '('
|
||||
}
|
||||
|
||||
/** @param {Token} token */
|
||||
function isCloseParen(token) {
|
||||
return token.type === 'Punctuator' && token.value === ')'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Expression} node
|
||||
* @param {SourceCode} sourceCode
|
||||
*/
|
||||
function getFirstAndLastTokens(node, sourceCode) {
|
||||
let first = sourceCode.getFirstToken(node)
|
||||
let last = sourceCode.getLastToken(node)
|
||||
|
||||
// If the value enclosed by parentheses, update the 'first' and 'last' by the parentheses.
|
||||
while (true) {
|
||||
const prev = sourceCode.getTokenBefore(first)
|
||||
const next = sourceCode.getTokenAfter(last)
|
||||
if (isOpenParen(prev) && isCloseParen(next)) {
|
||||
first = prev
|
||||
last = next
|
||||
} else {
|
||||
return { first, last }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'disallow using deprecated object declaration on data (in Vue.js 3.0.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-data-object-declaration.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
messages: {
|
||||
objectDeclarationIsDeprecated:
|
||||
"Object declaration on 'data' property is deprecated. Using function declaration instead."
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const sourceCode = context.getSourceCode()
|
||||
|
||||
return utils.executeOnVue(context, (obj) => {
|
||||
const invalidData = utils.findProperty(
|
||||
obj,
|
||||
'data',
|
||||
(p) =>
|
||||
p.value.type !== 'FunctionExpression' &&
|
||||
p.value.type !== 'ArrowFunctionExpression' &&
|
||||
p.value.type !== 'Identifier'
|
||||
)
|
||||
|
||||
if (invalidData) {
|
||||
context.report({
|
||||
node: invalidData,
|
||||
messageId: 'objectDeclarationIsDeprecated',
|
||||
fix(fixer) {
|
||||
const tokens = getFirstAndLastTokens(invalidData.value, sourceCode)
|
||||
|
||||
return [
|
||||
fixer.insertTextBefore(tokens.first, 'function() {\nreturn '),
|
||||
fixer.insertTextAfter(tokens.last, ';\n}')
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
86
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-destroyed-lifecycle.js
generated
vendored
Normal file
86
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-destroyed-lifecycle.js
generated
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'disallow using deprecated `destroyed` and `beforeDestroy` lifecycle hooks (in Vue.js 3.0.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-destroyed-lifecycle.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
messages: {
|
||||
deprecatedDestroyed:
|
||||
'The `destroyed` lifecycle hook is deprecated. Use `unmounted` instead.',
|
||||
deprecatedBeforeDestroy:
|
||||
'The `beforeDestroy` lifecycle hook is deprecated. Use `beforeUnmount` instead.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
return utils.executeOnVue(context, (obj) => {
|
||||
const destroyed = utils.findProperty(obj, 'destroyed')
|
||||
|
||||
if (destroyed) {
|
||||
context.report({
|
||||
node: destroyed.key,
|
||||
messageId: 'deprecatedDestroyed',
|
||||
fix(fixer) {
|
||||
return fix(fixer, destroyed, 'unmounted')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const beforeDestroy = utils.findProperty(obj, 'beforeDestroy')
|
||||
if (beforeDestroy) {
|
||||
context.report({
|
||||
node: beforeDestroy.key,
|
||||
messageId: 'deprecatedBeforeDestroy',
|
||||
fix(fixer) {
|
||||
return fix(fixer, beforeDestroy, 'beforeUnmount')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {RuleFixer} fixer
|
||||
* @param {Property} property
|
||||
* @param {string} newName
|
||||
*/
|
||||
function fix(fixer, property, newName) {
|
||||
if (property.computed) {
|
||||
if (
|
||||
property.key.type === 'Literal' ||
|
||||
property.key.type === 'TemplateLiteral'
|
||||
) {
|
||||
return fixer.replaceTextRange(
|
||||
[property.key.range[0] + 1, property.key.range[1] - 1],
|
||||
newName
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
if (property.shorthand) {
|
||||
return fixer.insertTextBefore(property.key, `${newName}:`)
|
||||
}
|
||||
return fixer.replaceText(property.key, newName)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
71
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-dollar-listeners-api.js
generated
vendored
Normal file
71
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-dollar-listeners-api.js
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'disallow using deprecated `$listeners` (in Vue.js 3.0.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-dollar-listeners-api.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
deprecated: 'The `$listeners` is deprecated.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
return utils.defineTemplateBodyVisitor(
|
||||
context,
|
||||
{
|
||||
VExpressionContainer(node) {
|
||||
for (const reference of node.references) {
|
||||
if (reference.variable != null) {
|
||||
// Not vm reference
|
||||
continue
|
||||
}
|
||||
if (reference.id.name === '$listeners') {
|
||||
context.report({
|
||||
node: reference.id,
|
||||
messageId: 'deprecated'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
utils.defineVueVisitor(context, {
|
||||
MemberExpression(node) {
|
||||
if (
|
||||
node.property.type !== 'Identifier' ||
|
||||
node.property.name !== '$listeners'
|
||||
) {
|
||||
return
|
||||
}
|
||||
if (!utils.isThis(node.object, context)) {
|
||||
return
|
||||
}
|
||||
|
||||
context.report({
|
||||
node: node.property,
|
||||
messageId: 'deprecated'
|
||||
})
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
78
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-dollar-scopedslots-api.js
generated
vendored
Normal file
78
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-dollar-scopedslots-api.js
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'disallow using deprecated `$scopedSlots` (in Vue.js 3.0.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-dollar-scopedslots-api.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
messages: {
|
||||
deprecated: 'The `$scopedSlots` is deprecated.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
return utils.defineTemplateBodyVisitor(
|
||||
context,
|
||||
{
|
||||
VExpressionContainer(node) {
|
||||
for (const reference of node.references) {
|
||||
if (reference.variable != null) {
|
||||
// Not vm reference
|
||||
continue
|
||||
}
|
||||
if (reference.id.name === '$scopedSlots') {
|
||||
context.report({
|
||||
node: reference.id,
|
||||
messageId: 'deprecated',
|
||||
fix(fixer) {
|
||||
return fixer.replaceText(reference.id, '$slots')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
utils.defineVueVisitor(context, {
|
||||
MemberExpression(node) {
|
||||
if (
|
||||
node.property.type !== 'Identifier' ||
|
||||
node.property.name !== '$scopedSlots'
|
||||
) {
|
||||
return
|
||||
}
|
||||
if (!utils.isThis(node.object, context)) {
|
||||
return
|
||||
}
|
||||
|
||||
context.report({
|
||||
node: node.property,
|
||||
messageId: 'deprecated',
|
||||
fix(fixer) {
|
||||
return fixer.replaceText(node.property, '$slots')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
69
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-events-api.js
generated
vendored
Normal file
69
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-events-api.js
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @fileoverview disallow using deprecated events api
|
||||
* @author yoyo930021
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'disallow using deprecated events api (in Vue.js 3.0.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-events-api.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
noDeprecatedEventsApi:
|
||||
'The Events api `$on`, `$off` `$once` is deprecated. Using external library instead, for example mitt.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
return utils.defineVueVisitor(context, {
|
||||
/** @param {MemberExpression & ({parent: CallExpression} | {parent: ChainExpression & {parent: CallExpression}})} node */
|
||||
'CallExpression > MemberExpression, CallExpression > ChainExpression > MemberExpression'(
|
||||
node
|
||||
) {
|
||||
const call =
|
||||
node.parent.type === 'ChainExpression'
|
||||
? node.parent.parent
|
||||
: node.parent
|
||||
|
||||
if (call.optional) {
|
||||
// It is OK because checking whether it is deprecated.
|
||||
// e.g. `this.$on?.()`
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
utils.skipChainExpression(call.callee) !== node ||
|
||||
!['$on', '$off', '$once'].includes(
|
||||
utils.getStaticPropertyName(node) || ''
|
||||
)
|
||||
) {
|
||||
return
|
||||
}
|
||||
if (!utils.isThis(node.object, context)) {
|
||||
return
|
||||
}
|
||||
|
||||
context.report({
|
||||
node: node.property,
|
||||
messageId: 'noDeprecatedEventsApi'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
44
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-filter.js
generated
vendored
Normal file
44
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-filter.js
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @author Przemyslaw Falowski (@przemkow)
|
||||
* @fileoverview disallow using deprecated filters syntax
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'disallow using deprecated filters syntax (in Vue.js 3.0.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-filter.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
noDeprecatedFilter: 'Filters are deprecated.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
VFilterSequenceExpression(node) {
|
||||
context.report({
|
||||
node,
|
||||
loc: node.loc,
|
||||
messageId: 'noDeprecatedFilter'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
55
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-functional-template.js
generated
vendored
Normal file
55
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-functional-template.js
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'disallow using deprecated the `functional` template (in Vue.js 3.0.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-functional-template.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
unexpected: 'The `functional` template are deprecated.'
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {RuleContext} context - The rule context.
|
||||
* @returns {RuleListener} AST event handlers.
|
||||
*/
|
||||
create(context) {
|
||||
return {
|
||||
Program(program) {
|
||||
const element = program.templateBody
|
||||
if (element == null) {
|
||||
return
|
||||
}
|
||||
|
||||
const functional = utils.getAttribute(element, 'functional')
|
||||
|
||||
if (functional) {
|
||||
context.report({
|
||||
node: functional,
|
||||
messageId: 'unexpected'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
72
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-html-element-is.js
generated
vendored
Normal file
72
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-html-element-is.js
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'disallow using deprecated the `is` attribute on HTML elements (in Vue.js 3.0.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-html-element-is.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
unexpected: 'The `is` attribute on HTML element are deprecated.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
/** @param {VElement} node */
|
||||
function isValidElement(node) {
|
||||
return (
|
||||
!utils.isHtmlWellKnownElementName(node.rawName) &&
|
||||
!utils.isSvgWellKnownElementName(node.rawName)
|
||||
)
|
||||
}
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
/** @param {VDirective} node */
|
||||
"VAttribute[directive=true][key.name.name='bind'][key.argument.name='is']"(
|
||||
node
|
||||
) {
|
||||
if (isValidElement(node.parent.parent)) {
|
||||
return
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
loc: node.loc,
|
||||
messageId: 'unexpected'
|
||||
})
|
||||
},
|
||||
/** @param {VAttribute} node */
|
||||
"VAttribute[directive=false][key.name='is']"(node) {
|
||||
if (isValidElement(node.parent.parent)) {
|
||||
return
|
||||
}
|
||||
if (node.value && node.value.value.startsWith('vue:')) {
|
||||
// Usage on native elements 3.1+
|
||||
return
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
loc: node.loc,
|
||||
messageId: 'unexpected'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
47
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-inline-template.js
generated
vendored
Normal file
47
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-inline-template.js
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'disallow using deprecated `inline-template` attribute (in Vue.js 3.0.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-inline-template.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
unexpected: '`inline-template` are deprecated.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
/** @param {VIdentifier} node */
|
||||
"VAttribute[directive=false] > VIdentifier[rawName='inline-template']"(
|
||||
node
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
loc: node.loc,
|
||||
messageId: 'unexpected'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
133
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-props-default-this.js
generated
vendored
Normal file
133
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-props-default-this.js
generated
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'disallow deprecated `this` access in props default function (in Vue.js 3.0.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-props-default-this.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
deprecated:
|
||||
'Props default value factory functions no longer have access to `this`.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
/**
|
||||
* @typedef {object} ScopeStack
|
||||
* @property {ScopeStack | null} upper
|
||||
* @property {FunctionExpression | FunctionDeclaration} node
|
||||
* @property {boolean} propDefault
|
||||
*/
|
||||
/** @type {Set<FunctionExpression>} */
|
||||
const propsDefault = new Set()
|
||||
/** @type {ScopeStack | null} */
|
||||
let scopeStack = null
|
||||
|
||||
/**
|
||||
* @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node
|
||||
*/
|
||||
function onFunctionEnter(node) {
|
||||
if (node.type === 'ArrowFunctionExpression') {
|
||||
return
|
||||
}
|
||||
if (scopeStack) {
|
||||
scopeStack = {
|
||||
upper: scopeStack,
|
||||
node,
|
||||
propDefault: false
|
||||
}
|
||||
} else if (node.type === 'FunctionExpression' && propsDefault.has(node)) {
|
||||
scopeStack = {
|
||||
upper: scopeStack,
|
||||
node,
|
||||
propDefault: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node
|
||||
*/
|
||||
function onFunctionExit(node) {
|
||||
if (scopeStack && scopeStack.node === node) {
|
||||
scopeStack = scopeStack.upper
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Expression|SpreadElement|null} node
|
||||
*/
|
||||
function isFunctionIdentifier(node) {
|
||||
return node && node.type === 'Identifier' && node.name === 'Function'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Expression} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasFunctionType(node) {
|
||||
if (isFunctionIdentifier(node)) {
|
||||
return true
|
||||
}
|
||||
if (node.type === 'ArrayExpression') {
|
||||
return node.elements.some(isFunctionIdentifier)
|
||||
}
|
||||
return false
|
||||
}
|
||||
return utils.defineVueVisitor(context, {
|
||||
onVueObjectEnter(node) {
|
||||
for (const prop of utils.getComponentPropsFromOptions(node)) {
|
||||
if (prop.type !== 'object') {
|
||||
continue
|
||||
}
|
||||
if (prop.value.type !== 'ObjectExpression') {
|
||||
continue
|
||||
}
|
||||
const def = utils.findProperty(prop.value, 'default')
|
||||
if (!def) {
|
||||
continue
|
||||
}
|
||||
const type = utils.findProperty(prop.value, 'type')
|
||||
if (type && hasFunctionType(type.value)) {
|
||||
// ignore function type
|
||||
continue
|
||||
}
|
||||
if (def.value.type !== 'FunctionExpression') {
|
||||
continue
|
||||
}
|
||||
propsDefault.add(def.value)
|
||||
}
|
||||
},
|
||||
':function': onFunctionEnter,
|
||||
':function:exit': onFunctionExit,
|
||||
ThisExpression(node) {
|
||||
if (scopeStack && scopeStack.propDefault) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'deprecated'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
103
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-router-link-tag-prop.js
generated
vendored
Normal file
103
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-router-link-tag-prop.js
generated
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @author Marton Csordas
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
const casing = require('../utils/casing')
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/** @param {RuleContext} context */
|
||||
function getComponentNames(context) {
|
||||
let components = ['RouterLink']
|
||||
|
||||
if (context.options[0] && context.options[0].components) {
|
||||
components = context.options[0].components
|
||||
}
|
||||
|
||||
return components.reduce((prev, curr) => {
|
||||
prev.add(casing.kebabCase(curr))
|
||||
prev.add(casing.pascalCase(curr))
|
||||
return prev
|
||||
}, new Set())
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'disallow using deprecated `tag` property on `RouterLink` (in Vue.js 3.0.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-router-link-tag-prop.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
components: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
},
|
||||
uniqueItems: true,
|
||||
minItems: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
deprecated:
|
||||
"'tag' property on '{{element}}' component is deprecated. Use scoped slots instead."
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const components = getComponentNames(context)
|
||||
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
VElement(node) {
|
||||
if (!components.has(node.rawName)) return
|
||||
|
||||
/** @type VIdentifier | null */
|
||||
let tagKey = null
|
||||
|
||||
const tagAttr = utils.getAttribute(node, 'tag')
|
||||
if (tagAttr) {
|
||||
tagKey = tagAttr.key
|
||||
} else {
|
||||
const directive = utils.getDirective(node, 'bind', 'tag')
|
||||
if (directive) {
|
||||
const arg = directive.key.argument
|
||||
if (arg && arg.type === 'VIdentifier') {
|
||||
tagKey = arg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tagKey) {
|
||||
context.report({
|
||||
node: tagKey,
|
||||
messageId: 'deprecated',
|
||||
data: {
|
||||
element: node.rawName
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
30
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-scope-attribute.js
generated
vendored
Normal file
30
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-scope-attribute.js
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
const scopeAttribute = require('./syntaxes/scope-attribute')
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'disallow deprecated `scope` attribute (in Vue.js 2.5.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-scope-attribute.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
messages: {
|
||||
forbiddenScopeAttribute: '`scope` attributes are deprecated.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const templateBodyVisitor =
|
||||
scopeAttribute.createTemplateBodyVisitor(context)
|
||||
return utils.defineTemplateBodyVisitor(context, templateBodyVisitor)
|
||||
}
|
||||
}
|
29
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-slot-attribute.js
generated
vendored
Normal file
29
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-slot-attribute.js
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
const slotAttribute = require('./syntaxes/slot-attribute')
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'disallow deprecated `slot` attribute (in Vue.js 2.6.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-slot-attribute.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
messages: {
|
||||
forbiddenSlotAttribute: '`slot` attributes are deprecated.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const templateBodyVisitor = slotAttribute.createTemplateBodyVisitor(context)
|
||||
return utils.defineTemplateBodyVisitor(context, templateBodyVisitor)
|
||||
}
|
||||
}
|
33
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-slot-scope-attribute.js
generated
vendored
Normal file
33
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-slot-scope-attribute.js
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
const slotScopeAttribute = require('./syntaxes/slot-scope-attribute')
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description:
|
||||
'disallow deprecated `slot-scope` attribute (in Vue.js 2.6.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-slot-scope-attribute.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
messages: {
|
||||
forbiddenSlotScopeAttribute: '`slot-scope` are deprecated.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const templateBodyVisitor = slotScopeAttribute.createTemplateBodyVisitor(
|
||||
context,
|
||||
{ fixToUpgrade: true }
|
||||
)
|
||||
return utils.defineTemplateBodyVisitor(context, templateBodyVisitor)
|
||||
}
|
||||
}
|
62
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-v-bind-sync.js
generated
vendored
Normal file
62
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-v-bind-sync.js
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @author Przemyslaw Falowski (@przemkow)
|
||||
* @fileoverview Disallow use of deprecated `.sync` modifier on `v-bind` directive (in Vue.js 3.0.0+)
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'disallow use of deprecated `.sync` modifier on `v-bind` directive (in Vue.js 3.0.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-v-bind-sync.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
messages: {
|
||||
syncModifierIsDeprecated:
|
||||
"'.sync' modifier on 'v-bind' directive is deprecated. Use 'v-model:propName' instead."
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
"VAttribute[directive=true][key.name.name='bind']"(node) {
|
||||
if (node.key.modifiers.map((mod) => mod.name).includes('sync')) {
|
||||
context.report({
|
||||
node,
|
||||
loc: node.loc,
|
||||
messageId: 'syncModifierIsDeprecated',
|
||||
fix(fixer) {
|
||||
if (node.key.argument == null) {
|
||||
// is using spread syntax
|
||||
return null
|
||||
}
|
||||
if (node.key.modifiers.length > 1) {
|
||||
// has multiple modifiers
|
||||
return null
|
||||
}
|
||||
|
||||
const bindArgument = context
|
||||
.getSourceCode()
|
||||
.getText(node.key.argument)
|
||||
return fixer.replaceText(node.key, `v-model:${bindArgument}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
29
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-v-is.js
generated
vendored
Normal file
29
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-v-is.js
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
const vIs = require('./syntaxes/v-is')
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'disallow deprecated `v-is` directive (in Vue.js 3.1.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-v-is.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
messages: {
|
||||
forbiddenVIs: '`v-is` directive is deprecated.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const templateBodyVisitor = vIs.createTemplateBodyVisitor(context)
|
||||
return utils.defineTemplateBodyVisitor(context, templateBodyVisitor)
|
||||
}
|
||||
}
|
49
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-v-on-native-modifier.js
generated
vendored
Normal file
49
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-v-on-native-modifier.js
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'disallow using deprecated `.native` modifiers (in Vue.js 3.0.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-v-on-native-modifier.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
deprecated: "'.native' modifier on 'v-on' directive is deprecated."
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
/** @param {VIdentifier & {parent:VDirectiveKey} } node */
|
||||
"VAttribute[directive=true][key.name.name='on'] > VDirectiveKey > VIdentifier[name='native']"(
|
||||
node
|
||||
) {
|
||||
const key = node.parent
|
||||
if (!key.modifiers.includes(node)) return
|
||||
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'deprecated'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
60
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-v-on-number-modifiers.js
generated
vendored
Normal file
60
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-v-on-number-modifiers.js
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @fileoverview disallow using deprecated number (keycode) modifiers
|
||||
* @author yoyo930021
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
const keyCodeToKey = require('../utils/keycode-to-key')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'disallow using deprecated number (keycode) modifiers (in Vue.js 3.0.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-v-on-number-modifiers.html'
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
messages: {
|
||||
numberModifierIsDeprecated:
|
||||
"'KeyboardEvent.keyCode' modifier on 'v-on' directive is deprecated. Using 'KeyboardEvent.key' instead."
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
/** @param {VDirectiveKey} node */
|
||||
"VAttribute[directive=true][key.name.name='on'] > VDirectiveKey"(node) {
|
||||
const modifier = node.modifiers.find((mod) =>
|
||||
Number.isInteger(parseInt(mod.name, 10))
|
||||
)
|
||||
if (!modifier) return
|
||||
|
||||
const keyCodes = parseInt(modifier.name, 10)
|
||||
if (keyCodes > 9 || keyCodes < 0) {
|
||||
context.report({
|
||||
node: modifier,
|
||||
messageId: 'numberModifierIsDeprecated',
|
||||
fix(fixer) {
|
||||
const key = keyCodeToKey[keyCodes]
|
||||
if (!key) return null
|
||||
|
||||
return fixer.replaceText(modifier, `${key}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
52
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-vue-config-keycodes.js
generated
vendored
Normal file
52
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-deprecated-vue-config-keycodes.js
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'disallow using deprecated `Vue.config.keyCodes` (in Vue.js 3.0.0+)',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-deprecated-vue-config-keycodes.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
unexpected: '`Vue.config.keyCodes` are deprecated.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
return {
|
||||
/** @param {MemberExpression} node */
|
||||
"MemberExpression[property.type='Identifier'][property.name='keyCodes']"(
|
||||
node
|
||||
) {
|
||||
const config = utils.skipChainExpression(node.object)
|
||||
if (
|
||||
config.type !== 'MemberExpression' ||
|
||||
config.property.type !== 'Identifier' ||
|
||||
config.property.name !== 'config' ||
|
||||
config.object.type !== 'Identifier' ||
|
||||
config.object.name !== 'Vue'
|
||||
) {
|
||||
return
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'unexpected'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
68
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-dupe-keys.js
generated
vendored
Normal file
68
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-dupe-keys.js
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* @fileoverview Prevents duplication of field names.
|
||||
* @author Armano
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
/**
|
||||
* @typedef {import('../utils').GroupName} GroupName
|
||||
*/
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
/** @type {GroupName[]} */
|
||||
const GROUP_NAMES = ['props', 'computed', 'data', 'methods', 'setup']
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'disallow duplication of field names',
|
||||
categories: ['vue3-essential', 'essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-dupe-keys.html'
|
||||
},
|
||||
fixable: null, // or "code" or "whitespace"
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
groups: {
|
||||
type: 'array'
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const options = context.options[0] || {}
|
||||
const groups = new Set(GROUP_NAMES.concat(options.groups || []))
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
return utils.executeOnVue(context, (obj) => {
|
||||
const usedNames = []
|
||||
const properties = utils.iterateProperties(obj, groups)
|
||||
|
||||
for (const o of properties) {
|
||||
if (usedNames.indexOf(o.name) !== -1) {
|
||||
context.report({
|
||||
node: o.node,
|
||||
message: "Duplicated key '{{name}}'.",
|
||||
data: {
|
||||
name: o.name
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
usedNames.push(o.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
193
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-dupe-v-else-if.js
generated
vendored
Normal file
193
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-dupe-v-else-if.js
generated
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @typedef {NonNullable<VExpressionContainer['expression']>} VExpression
|
||||
*/
|
||||
/**
|
||||
* @typedef {object} OrOperands
|
||||
* @property {VExpression} OrOperands.node
|
||||
* @property {AndOperands[]} OrOperands.operands
|
||||
*
|
||||
* @typedef {object} AndOperands
|
||||
* @property {VExpression} AndOperands.node
|
||||
* @property {VExpression[]} AndOperands.operands
|
||||
*/
|
||||
/**
|
||||
* Splits the given node by the given logical operator.
|
||||
* @param {string} operator Logical operator `||` or `&&`.
|
||||
* @param {VExpression} node The node to split.
|
||||
* @returns {VExpression[]} Array of conditions that makes the node when joined by the operator.
|
||||
*/
|
||||
function splitByLogicalOperator(operator, node) {
|
||||
if (node.type === 'LogicalExpression' && node.operator === operator) {
|
||||
return [
|
||||
...splitByLogicalOperator(operator, node.left),
|
||||
...splitByLogicalOperator(operator, node.right)
|
||||
]
|
||||
}
|
||||
return [node]
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VExpression} node
|
||||
*/
|
||||
function splitByOr(node) {
|
||||
return splitByLogicalOperator('||', node)
|
||||
}
|
||||
/**
|
||||
* @param {VExpression} node
|
||||
*/
|
||||
function splitByAnd(node) {
|
||||
return splitByLogicalOperator('&&', node)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VExpression} node
|
||||
* @returns {OrOperands}
|
||||
*/
|
||||
function buildOrOperands(node) {
|
||||
const orOperands = splitByOr(node)
|
||||
return {
|
||||
node,
|
||||
operands: orOperands.map((orOperand) => {
|
||||
const andOperands = splitByAnd(orOperand)
|
||||
return {
|
||||
node: orOperand,
|
||||
operands: andOperands
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'disallow duplicate conditions in `v-if` / `v-else-if` chains',
|
||||
categories: ['vue3-essential', 'essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-dupe-v-else-if.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
unexpected:
|
||||
'This branch can never execute. Its condition is a duplicate or covered by previous conditions in the `v-if` / `v-else-if` chain.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const tokenStore =
|
||||
context.parserServices.getTemplateBodyTokenStore &&
|
||||
context.parserServices.getTemplateBodyTokenStore()
|
||||
/**
|
||||
* Determines whether the two given nodes are considered to be equal. In particular, given that the nodes
|
||||
* represent expressions in a boolean context, `||` and `&&` can be considered as commutative operators.
|
||||
* @param {VExpression} a First node.
|
||||
* @param {VExpression} b Second node.
|
||||
* @returns {boolean} `true` if the nodes are considered to be equal.
|
||||
*/
|
||||
function equal(a, b) {
|
||||
if (a.type !== b.type) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (
|
||||
a.type === 'LogicalExpression' &&
|
||||
b.type === 'LogicalExpression' &&
|
||||
(a.operator === '||' || a.operator === '&&') &&
|
||||
a.operator === b.operator
|
||||
) {
|
||||
return (
|
||||
(equal(a.left, b.left) && equal(a.right, b.right)) ||
|
||||
(equal(a.left, b.right) && equal(a.right, b.left))
|
||||
)
|
||||
}
|
||||
|
||||
return utils.equalTokens(a, b, tokenStore)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the first given AndOperands is a subset of the second given AndOperands.
|
||||
*
|
||||
* e.g. A: (a && b), B: (a && b && c): B is a subset of A.
|
||||
*
|
||||
* @param {AndOperands} operandsA The AndOperands to compare from.
|
||||
* @param {AndOperands} operandsB The AndOperands to compare against.
|
||||
* @returns {boolean} `true` if the `andOperandsA` is a subset of the `andOperandsB`.
|
||||
*/
|
||||
function isSubset(operandsA, operandsB) {
|
||||
return operandsA.operands.every((operandA) =>
|
||||
operandsB.operands.some((operandB) => equal(operandA, operandB))
|
||||
)
|
||||
}
|
||||
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
"VAttribute[directive=true][key.name.name='else-if']"(node) {
|
||||
if (!node.value || !node.value.expression) {
|
||||
return
|
||||
}
|
||||
const test = node.value.expression
|
||||
const conditionsToCheck =
|
||||
test.type === 'LogicalExpression' && test.operator === '&&'
|
||||
? [...splitByAnd(test), test]
|
||||
: [test]
|
||||
const listToCheck = conditionsToCheck.map(buildOrOperands)
|
||||
|
||||
/** @type {VElement | null} */
|
||||
let current = node.parent.parent
|
||||
while (current && (current = utils.prevSibling(current))) {
|
||||
const vIf = utils.getDirective(current, 'if')
|
||||
const currentTestDir = vIf || utils.getDirective(current, 'else-if')
|
||||
if (!currentTestDir) {
|
||||
return
|
||||
}
|
||||
if (currentTestDir.value && currentTestDir.value.expression) {
|
||||
const currentOrOperands = buildOrOperands(
|
||||
currentTestDir.value.expression
|
||||
)
|
||||
|
||||
for (const condition of listToCheck) {
|
||||
const operands = (condition.operands = condition.operands.filter(
|
||||
(orOperand) => {
|
||||
return !currentOrOperands.operands.some((currentOrOperand) =>
|
||||
isSubset(currentOrOperand, orOperand)
|
||||
)
|
||||
}
|
||||
))
|
||||
if (!operands.length) {
|
||||
context.report({
|
||||
node: condition.node,
|
||||
messageId: 'unexpected'
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vIf) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
67
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-duplicate-attr-inheritance.js
generated
vendored
Normal file
67
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-duplicate-attr-inheritance.js
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @fileoverview Disable inheritAttrs when using v-bind="$attrs"
|
||||
* @author Hiroki Osame
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description:
|
||||
'enforce `inheritAttrs` to be set to `false` when using `v-bind="$attrs"`',
|
||||
categories: undefined,
|
||||
recommended: false,
|
||||
url: 'https://eslint.vuejs.org/rules/no-duplicate-attr-inheritance.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [
|
||||
// fill in your schema
|
||||
]
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
/** @type {string | number | boolean | RegExp | BigInt | null} */
|
||||
let inheritsAttrs = true
|
||||
|
||||
return Object.assign(
|
||||
utils.executeOnVue(context, (node) => {
|
||||
const inheritAttrsProp = utils.findProperty(node, 'inheritAttrs')
|
||||
|
||||
if (inheritAttrsProp && inheritAttrsProp.value.type === 'Literal') {
|
||||
inheritsAttrs = inheritAttrsProp.value.value
|
||||
}
|
||||
}),
|
||||
utils.defineTemplateBodyVisitor(context, {
|
||||
/** @param {VExpressionContainer} node */
|
||||
"VAttribute[directive=true][key.name.name='bind'][key.argument=null] > VExpressionContainer"(
|
||||
node
|
||||
) {
|
||||
if (!inheritsAttrs) {
|
||||
return
|
||||
}
|
||||
const attrsRef = node.references.find((reference) => {
|
||||
if (reference.variable != null) {
|
||||
// Not vm reference
|
||||
return false
|
||||
}
|
||||
return reference.id.name === '$attrs'
|
||||
})
|
||||
|
||||
if (attrsRef) {
|
||||
context.report({
|
||||
node: attrsRef.id,
|
||||
message: 'Set "inheritAttrs" to false.'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
120
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-duplicate-attributes.js
generated
vendored
Normal file
120
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-duplicate-attributes.js
generated
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
/**
|
||||
* @author Toru Nagashima
|
||||
* @copyright 2017 Toru Nagashima. All rights reserved.
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the name of the given attribute node.
|
||||
* @param {VAttribute | VDirective} attribute The attribute node to get.
|
||||
* @returns {string | null} The name of the attribute.
|
||||
*/
|
||||
function getName(attribute) {
|
||||
if (!attribute.directive) {
|
||||
return attribute.key.name
|
||||
}
|
||||
if (attribute.key.name.name === 'bind') {
|
||||
return (
|
||||
(attribute.key.argument &&
|
||||
attribute.key.argument.type === 'VIdentifier' &&
|
||||
attribute.key.argument.name) ||
|
||||
null
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'disallow duplication of attributes',
|
||||
categories: ['vue3-essential', 'essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-duplicate-attributes.html'
|
||||
},
|
||||
fixable: null,
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
allowCoexistClass: {
|
||||
type: 'boolean'
|
||||
},
|
||||
allowCoexistStyle: {
|
||||
type: 'boolean'
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
const options = context.options[0] || {}
|
||||
const allowCoexistStyle = options.allowCoexistStyle !== false
|
||||
const allowCoexistClass = options.allowCoexistClass !== false
|
||||
|
||||
/** @type {Set<string>} */
|
||||
const directiveNames = new Set()
|
||||
/** @type {Set<string>} */
|
||||
const attributeNames = new Set()
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {boolean} isDirective
|
||||
*/
|
||||
function isDuplicate(name, isDirective) {
|
||||
if (
|
||||
(allowCoexistStyle && name === 'style') ||
|
||||
(allowCoexistClass && name === 'class')
|
||||
) {
|
||||
return isDirective ? directiveNames.has(name) : attributeNames.has(name)
|
||||
}
|
||||
return directiveNames.has(name) || attributeNames.has(name)
|
||||
}
|
||||
|
||||
return utils.defineTemplateBodyVisitor(context, {
|
||||
VStartTag() {
|
||||
directiveNames.clear()
|
||||
attributeNames.clear()
|
||||
},
|
||||
VAttribute(node) {
|
||||
const name = getName(node)
|
||||
if (name == null) {
|
||||
return
|
||||
}
|
||||
|
||||
if (isDuplicate(name, node.directive)) {
|
||||
context.report({
|
||||
node,
|
||||
loc: node.loc,
|
||||
message: "Duplicate attribute '{{name}}'.",
|
||||
data: { name }
|
||||
})
|
||||
}
|
||||
|
||||
if (node.directive) {
|
||||
directiveNames.add(name)
|
||||
} else {
|
||||
attributeNames.add(name)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
109
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-empty-component-block.js
generated
vendored
Normal file
109
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-empty-component-block.js
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
/**
|
||||
* @author tyankatsu <https://github.com/tyankatsu0105>
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const { isVElement } = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* check whether has attribute `src`
|
||||
* @param {VElement} componentBlock
|
||||
*/
|
||||
function hasAttributeSrc(componentBlock) {
|
||||
const hasAttribute = componentBlock.startTag.attributes.length > 0
|
||||
|
||||
const hasSrc =
|
||||
componentBlock.startTag.attributes.filter(
|
||||
(attribute) =>
|
||||
!attribute.directive &&
|
||||
attribute.key.name === 'src' &&
|
||||
attribute.value &&
|
||||
attribute.value.value !== ''
|
||||
).length > 0
|
||||
|
||||
return hasAttribute && hasSrc
|
||||
}
|
||||
|
||||
/**
|
||||
* check whether value under the component block is only whitespaces or break lines
|
||||
* @param {VElement} componentBlock
|
||||
*/
|
||||
function isValueOnlyWhiteSpacesOrLineBreaks(componentBlock) {
|
||||
return (
|
||||
componentBlock.children.length === 1 &&
|
||||
componentBlock.children[0].type === 'VText' &&
|
||||
!componentBlock.children[0].value.trim()
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description:
|
||||
'disallow the `<template>` `<script>` `<style>` block to be empty',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/no-empty-component-block.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
unexpected: '`<{{ blockName }}>` is empty. Empty block is not allowed.'
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {RuleContext} context - The rule context.
|
||||
* @returns {RuleListener} AST event handlers.
|
||||
*/
|
||||
create(context) {
|
||||
if (!context.parserServices.getDocumentFragment) {
|
||||
return {}
|
||||
}
|
||||
const documentFragment = context.parserServices.getDocumentFragment()
|
||||
if (!documentFragment) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const componentBlocks = documentFragment.children.filter(isVElement)
|
||||
|
||||
return {
|
||||
Program() {
|
||||
for (const componentBlock of componentBlocks) {
|
||||
if (
|
||||
componentBlock.name !== 'template' &&
|
||||
componentBlock.name !== 'script' &&
|
||||
componentBlock.name !== 'style'
|
||||
)
|
||||
continue
|
||||
|
||||
// https://vue-loader.vuejs.org/spec.html#src-imports
|
||||
if (hasAttributeSrc(componentBlock)) continue
|
||||
|
||||
if (
|
||||
isValueOnlyWhiteSpacesOrLineBreaks(componentBlock) ||
|
||||
componentBlock.children.length === 0
|
||||
) {
|
||||
context.report({
|
||||
node: componentBlock,
|
||||
loc: componentBlock.loc,
|
||||
messageId: 'unexpected',
|
||||
data: {
|
||||
blockName: componentBlock.name
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-empty-pattern.js
generated
vendored
Normal file
9
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-empty-pattern.js
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('no-empty-pattern')
|
60
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-export-in-script-setup.js
generated
vendored
Normal file
60
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-export-in-script-setup.js
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
/**
|
||||
* @typedef {import('@typescript-eslint/types').TSESTree.ExportAllDeclaration} TSESTreeExportAllDeclaration
|
||||
* @typedef {import('@typescript-eslint/types').TSESTree.ExportDefaultDeclaration} TSESTreeExportDefaultDeclaration
|
||||
* @typedef {import('@typescript-eslint/types').TSESTree.ExportNamedDeclaration} TSESTreeExportNamedDeclaration
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'disallow `export` in `<script setup>`',
|
||||
categories: ['vue3-essential'],
|
||||
url: 'https://eslint.vuejs.org/rules/no-export-in-script-setup.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
forbidden: '`<script setup>` cannot contain ES module exports.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
/** @param {ExportAllDeclaration | ExportDefaultDeclaration | ExportNamedDeclaration} node */
|
||||
function verify(node) {
|
||||
const tsNode =
|
||||
/** @type {TSESTreeExportAllDeclaration | TSESTreeExportDefaultDeclaration | TSESTreeExportNamedDeclaration} */ (
|
||||
node
|
||||
)
|
||||
if (tsNode.exportKind === 'type') {
|
||||
return
|
||||
}
|
||||
if (tsNode.type === 'ExportNamedDeclaration') {
|
||||
if (
|
||||
tsNode.specifiers.length > 0 &&
|
||||
tsNode.specifiers.every((spec) => spec.exportKind === 'type')
|
||||
) {
|
||||
return
|
||||
}
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'forbidden'
|
||||
})
|
||||
}
|
||||
|
||||
return utils.defineScriptSetupVisitor(context, {
|
||||
ExportAllDeclaration: verify,
|
||||
ExportDefaultDeclaration: verify,
|
||||
ExportNamedDeclaration: verify
|
||||
})
|
||||
}
|
||||
}
|
202
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-expose-after-await.js
generated
vendored
Normal file
202
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-expose-after-await.js
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const { findVariable } = require('eslint-utils')
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the callee member node from the given CallExpression
|
||||
* @param {CallExpression} node CallExpression
|
||||
*/
|
||||
function getCalleeMemberNode(node) {
|
||||
const callee = utils.skipChainExpression(node.callee)
|
||||
|
||||
if (callee.type === 'MemberExpression') {
|
||||
const name = utils.getStaticPropertyName(callee)
|
||||
if (name) {
|
||||
return { name, member: callee }
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'disallow asynchronously registered `expose`',
|
||||
categories: undefined,
|
||||
// categories: ['vue3-essential'], TODO Change with the major version
|
||||
url: 'https://eslint.vuejs.org/rules/no-expose-after-await.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
forbidden: 'The `expose` after `await` expression are forbidden.'
|
||||
}
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
/**
|
||||
* @typedef {object} SetupScopeData
|
||||
* @property {boolean} afterAwait
|
||||
* @property {[number,number]} range
|
||||
* @property {Set<Identifier>} exposeReferenceIds
|
||||
* @property {Set<Identifier>} contextReferenceIds
|
||||
*/
|
||||
/**
|
||||
* @typedef {object} ScopeStack
|
||||
* @property {ScopeStack | null} upper
|
||||
* @property {FunctionDeclaration | FunctionExpression | ArrowFunctionExpression} scopeNode
|
||||
*/
|
||||
/** @type {Map<FunctionDeclaration | FunctionExpression | ArrowFunctionExpression, SetupScopeData>} */
|
||||
const setupScopes = new Map()
|
||||
|
||||
/** @type {ScopeStack | null} */
|
||||
let scopeStack = null
|
||||
|
||||
return utils.defineVueVisitor(context, {
|
||||
onSetupFunctionEnter(node) {
|
||||
const contextParam = node.params[1]
|
||||
if (!contextParam) {
|
||||
// no arguments
|
||||
return
|
||||
}
|
||||
if (contextParam.type === 'RestElement') {
|
||||
// cannot check
|
||||
return
|
||||
}
|
||||
if (contextParam.type === 'ArrayPattern') {
|
||||
// cannot check
|
||||
return
|
||||
}
|
||||
/** @type {Set<Identifier>} */
|
||||
const contextReferenceIds = new Set()
|
||||
/** @type {Set<Identifier>} */
|
||||
const exposeReferenceIds = new Set()
|
||||
if (contextParam.type === 'ObjectPattern') {
|
||||
const exposeProperty = utils.findAssignmentProperty(
|
||||
contextParam,
|
||||
'expose'
|
||||
)
|
||||
if (!exposeProperty) {
|
||||
return
|
||||
}
|
||||
const exposeParam = exposeProperty.value
|
||||
// `setup(props, {emit})`
|
||||
const variable =
|
||||
exposeParam.type === 'Identifier'
|
||||
? findVariable(context.getScope(), exposeParam)
|
||||
: null
|
||||
if (!variable) {
|
||||
return
|
||||
}
|
||||
for (const reference of variable.references) {
|
||||
if (!reference.isRead()) {
|
||||
continue
|
||||
}
|
||||
exposeReferenceIds.add(reference.identifier)
|
||||
}
|
||||
} else if (contextParam.type === 'Identifier') {
|
||||
// `setup(props, context)`
|
||||
const variable = findVariable(context.getScope(), contextParam)
|
||||
if (!variable) {
|
||||
return
|
||||
}
|
||||
for (const reference of variable.references) {
|
||||
if (!reference.isRead()) {
|
||||
continue
|
||||
}
|
||||
contextReferenceIds.add(reference.identifier)
|
||||
}
|
||||
}
|
||||
setupScopes.set(node, {
|
||||
afterAwait: false,
|
||||
range: node.range,
|
||||
exposeReferenceIds,
|
||||
contextReferenceIds
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node
|
||||
*/
|
||||
':function'(node) {
|
||||
scopeStack = {
|
||||
upper: scopeStack,
|
||||
scopeNode: node
|
||||
}
|
||||
},
|
||||
':function:exit'() {
|
||||
scopeStack = scopeStack && scopeStack.upper
|
||||
},
|
||||
/** @param {AwaitExpression} node */
|
||||
AwaitExpression(node) {
|
||||
if (!scopeStack) {
|
||||
return
|
||||
}
|
||||
const setupScope = setupScopes.get(scopeStack.scopeNode)
|
||||
if (!setupScope || !utils.inRange(setupScope.range, node)) {
|
||||
return
|
||||
}
|
||||
setupScope.afterAwait = true
|
||||
},
|
||||
/** @param {CallExpression} node */
|
||||
CallExpression(node) {
|
||||
if (!scopeStack) {
|
||||
return
|
||||
}
|
||||
const setupScope = setupScopes.get(scopeStack.scopeNode)
|
||||
if (
|
||||
!setupScope ||
|
||||
!setupScope.afterAwait ||
|
||||
!utils.inRange(setupScope.range, node)
|
||||
) {
|
||||
return
|
||||
}
|
||||
const { contextReferenceIds, exposeReferenceIds } = setupScope
|
||||
if (
|
||||
node.callee.type === 'Identifier' &&
|
||||
exposeReferenceIds.has(node.callee)
|
||||
) {
|
||||
// setup(props,{expose}) {expose()}
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'forbidden'
|
||||
})
|
||||
} else {
|
||||
const expose = getCalleeMemberNode(node)
|
||||
if (
|
||||
expose &&
|
||||
expose.name === 'expose' &&
|
||||
expose.member.object.type === 'Identifier' &&
|
||||
contextReferenceIds.has(expose.member.object)
|
||||
) {
|
||||
// setup(props,context) {context.emit()}
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'forbidden'
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
onSetupFunctionExit(node) {
|
||||
setupScopes.delete(node)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
204
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-extra-parens.js
generated
vendored
Normal file
204
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-extra-parens.js
generated
vendored
Normal file
@ -0,0 +1,204 @@
|
||||
/**
|
||||
* @author Yosuke Ota
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const { isParenthesized } = require('eslint-utils')
|
||||
const { wrapCoreRule } = require('../utils')
|
||||
const { getStyleVariablesContext } = require('../utils/style-variables')
|
||||
|
||||
// eslint-disable-next-line no-invalid-meta, no-invalid-meta-docs-categories
|
||||
module.exports = wrapCoreRule('no-extra-parens', {
|
||||
skipDynamicArguments: true,
|
||||
applyDocument: true,
|
||||
create: createForVueSyntax
|
||||
})
|
||||
|
||||
/**
|
||||
* Check whether the given token is a left parenthesis.
|
||||
* @param {Token} token The token to check.
|
||||
* @returns {boolean} `true` if the token is a left parenthesis.
|
||||
*/
|
||||
function isLeftParen(token) {
|
||||
return token.type === 'Punctuator' && token.value === '('
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given token is a right parenthesis.
|
||||
* @param {Token} token The token to check.
|
||||
* @returns {boolean} `true` if the token is a right parenthesis.
|
||||
*/
|
||||
function isRightParen(token) {
|
||||
return token.type === 'Punctuator' && token.value === ')'
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given token is a left brace.
|
||||
* @param {Token} token The token to check.
|
||||
* @returns {boolean} `true` if the token is a left brace.
|
||||
*/
|
||||
function isLeftBrace(token) {
|
||||
return token.type === 'Punctuator' && token.value === '{'
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given token is a right brace.
|
||||
* @param {Token} token The token to check.
|
||||
* @returns {boolean} `true` if the token is a right brace.
|
||||
*/
|
||||
function isRightBrace(token) {
|
||||
return token.type === 'Punctuator' && token.value === '}'
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given token is a left bracket.
|
||||
* @param {Token} token The token to check.
|
||||
* @returns {boolean} `true` if the token is a left bracket.
|
||||
*/
|
||||
function isLeftBracket(token) {
|
||||
return token.type === 'Punctuator' && token.value === '['
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given token is a right bracket.
|
||||
* @param {Token} token The token to check.
|
||||
* @returns {boolean} `true` if the token is a right bracket.
|
||||
*/
|
||||
function isRightBracket(token) {
|
||||
return token.type === 'Punctuator' && token.value === ']'
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a given expression node is an IIFE
|
||||
* @param {Expression} node The node to check
|
||||
* @returns {node is CallExpression & { callee: FunctionExpression } } `true` if the given node is an IIFE
|
||||
*/
|
||||
function isIIFE(node) {
|
||||
return (
|
||||
node.type === 'CallExpression' && node.callee.type === 'FunctionExpression'
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {RuleContext} context - The rule context.
|
||||
* @returns {TemplateListener} AST event handlers.
|
||||
*/
|
||||
function createForVueSyntax(context) {
|
||||
if (!context.parserServices.getTemplateBodyTokenStore) {
|
||||
return {}
|
||||
}
|
||||
const tokenStore = context.parserServices.getTemplateBodyTokenStore()
|
||||
|
||||
/**
|
||||
* Checks if the given node turns into a filter when unwraped.
|
||||
* @param {Expression} expression node to evaluate
|
||||
* @returns {boolean} `true` if the given node turns into a filter when unwraped.
|
||||
*/
|
||||
function isUnwrapChangeToFilter(expression) {
|
||||
let parenStack = null
|
||||
for (const token of tokenStore.getTokens(expression)) {
|
||||
if (!parenStack) {
|
||||
if (token.value === '|') {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
if (parenStack.isUpToken(token)) {
|
||||
parenStack = parenStack.upper
|
||||
continue
|
||||
}
|
||||
}
|
||||
if (isLeftParen(token)) {
|
||||
parenStack = { isUpToken: isRightParen, upper: parenStack }
|
||||
} else if (isLeftBracket(token)) {
|
||||
parenStack = { isUpToken: isRightBracket, upper: parenStack }
|
||||
} else if (isLeftBrace(token)) {
|
||||
parenStack = { isUpToken: isRightBrace, upper: parenStack }
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
/**
|
||||
* Checks if the given node is CSS v-bind() without quote.
|
||||
* @param {VExpressionContainer} node
|
||||
* @param {Expression} expression
|
||||
*/
|
||||
function isStyleVariableWithoutQuote(node, expression) {
|
||||
const styleVars = getStyleVariablesContext(context)
|
||||
if (!styleVars || !styleVars.vBinds.includes(node)) {
|
||||
return false
|
||||
}
|
||||
|
||||
const vBindToken = tokenStore.getFirstToken(node)
|
||||
const tokens = tokenStore.getTokensBetween(vBindToken, expression)
|
||||
|
||||
return tokens.every(isLeftParen)
|
||||
}
|
||||
/**
|
||||
* @param {VExpressionContainer & { expression: Expression | VFilterSequenceExpression | null }} node
|
||||
*/
|
||||
function verify(node) {
|
||||
if (!node.expression) {
|
||||
return
|
||||
}
|
||||
|
||||
const expression =
|
||||
node.expression.type === 'VFilterSequenceExpression'
|
||||
? node.expression.expression
|
||||
: node.expression
|
||||
|
||||
if (!isParenthesized(expression, tokenStore)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isParenthesized(2, expression, tokenStore)) {
|
||||
if (
|
||||
isIIFE(expression) &&
|
||||
!isParenthesized(expression.callee, tokenStore)
|
||||
) {
|
||||
return
|
||||
}
|
||||
if (isUnwrapChangeToFilter(expression)) {
|
||||
return
|
||||
}
|
||||
if (isStyleVariableWithoutQuote(node, expression)) {
|
||||
return
|
||||
}
|
||||
}
|
||||
report(expression)
|
||||
}
|
||||
|
||||
/**
|
||||
* Report the node
|
||||
* @param {Expression} node node to evaluate
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function report(node) {
|
||||
const sourceCode = context.getSourceCode()
|
||||
const leftParenToken = tokenStore.getTokenBefore(node)
|
||||
const rightParenToken = tokenStore.getTokenAfter(node)
|
||||
|
||||
context.report({
|
||||
node,
|
||||
loc: leftParenToken.loc,
|
||||
messageId: 'unexpected',
|
||||
fix(fixer) {
|
||||
const parenthesizedSource = sourceCode.text.slice(
|
||||
leftParenToken.range[1],
|
||||
rightParenToken.range[0]
|
||||
)
|
||||
|
||||
return fixer.replaceTextRange(
|
||||
[leftParenToken.range[0], rightParenToken.range[1]],
|
||||
parenthesizedSource
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
"VAttribute[directive=true][key.name.name='bind'] > VExpressionContainer":
|
||||
verify,
|
||||
'VElement > VExpressionContainer': verify
|
||||
}
|
||||
}
|
57
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-invalid-model-keys.js
generated
vendored
Normal file
57
app_vue/node_modules/eslint-plugin-vue/lib/rules/no-invalid-model-keys.js
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @fileoverview Requires valid keys in model option.
|
||||
* @author Alex Sokolov
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
const utils = require('../utils')
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
const VALID_MODEL_KEYS = ['prop', 'event']
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'require valid keys in model option',
|
||||
categories: undefined,
|
||||
url: 'https://eslint.vuejs.org/rules/no-invalid-model-keys.html'
|
||||
},
|
||||
fixable: null,
|
||||
schema: []
|
||||
},
|
||||
/** @param {RuleContext} context */
|
||||
create(context) {
|
||||
// ----------------------------------------------------------------------
|
||||
// Public
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
return utils.executeOnVue(context, (obj) => {
|
||||
const modelProperty = utils.findProperty(obj, 'model')
|
||||
if (!modelProperty || modelProperty.value.type !== 'ObjectExpression') {
|
||||
return
|
||||
}
|
||||
|
||||
for (const p of modelProperty.value.properties) {
|
||||
if (p.type !== 'Property') {
|
||||
continue
|
||||
}
|
||||
const name = utils.getStaticPropertyName(p)
|
||||
if (!name) {
|
||||
continue
|
||||
}
|
||||
if (VALID_MODEL_KEYS.indexOf(name) === -1) {
|
||||
context.report({
|
||||
node: p,
|
||||
message: "Invalid key '{{name}}' in model option.",
|
||||
data: {
|
||||
name
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user