no-unsupported-features.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /**
  2. * @author Yosuke Ota
  3. * See LICENSE file in root directory for full license.
  4. */
  5. 'use strict'
  6. const semver = require('semver')
  7. const utils = require('../utils')
  8. /**
  9. * @typedef {object} SyntaxRule
  10. * @property {string} supported
  11. * @property { (context: RuleContext) => TemplateListener } [createTemplateBodyVisitor]
  12. * @property { (context: RuleContext) => RuleListener } [createScriptVisitor]
  13. */
  14. const FEATURES = {
  15. // Vue.js 2.5.0+
  16. 'slot-scope-attribute': require('./syntaxes/slot-scope-attribute'),
  17. // Vue.js 2.6.0+
  18. 'dynamic-directive-arguments': require('./syntaxes/dynamic-directive-arguments'),
  19. 'v-slot': require('./syntaxes/v-slot'),
  20. // Vue.js 2.7.0+
  21. 'script-setup': require('./syntaxes/script-setup'),
  22. 'style-css-vars-injection': require('./syntaxes/style-css-vars-injection'),
  23. // Vue.js 3.0.0+
  24. 'v-model-argument': require('./syntaxes/v-model-argument'),
  25. 'v-model-custom-modifiers': require('./syntaxes/v-model-custom-modifiers'),
  26. 'v-is': require('./syntaxes/v-is'),
  27. // Vue.js 3.1.0+
  28. 'is-attribute-with-vue-prefix': require('./syntaxes/is-attribute-with-vue-prefix'),
  29. // Vue.js 3.2.0+
  30. 'v-memo': require('./syntaxes/v-memo'),
  31. 'v-bind-prop-modifier-shorthand': require('./syntaxes/v-bind-prop-modifier-shorthand'),
  32. 'v-bind-attr-modifier': require('./syntaxes/v-bind-attr-modifier')
  33. }
  34. const SYNTAX_NAMES = /** @type {(keyof FEATURES)[]} */ (Object.keys(FEATURES))
  35. const cache = new Map()
  36. /**
  37. * Get the `semver.Range` object of a given range text.
  38. * @param {string} x The text expression for a semver range.
  39. * @returns {semver.Range} The range object of a given range text.
  40. * It's null if the `x` is not a valid range text.
  41. */
  42. function getSemverRange(x) {
  43. const s = String(x)
  44. let ret = cache.get(s) || null
  45. if (!ret) {
  46. try {
  47. ret = new semver.Range(s)
  48. } catch (_error) {
  49. // Ignore parsing error.
  50. }
  51. cache.set(s, ret)
  52. }
  53. return ret
  54. }
  55. module.exports = {
  56. meta: {
  57. type: 'suggestion',
  58. docs: {
  59. description:
  60. 'disallow unsupported Vue.js syntax on the specified version',
  61. categories: undefined,
  62. url: 'https://eslint.vuejs.org/rules/no-unsupported-features.html'
  63. },
  64. fixable: 'code',
  65. schema: [
  66. {
  67. type: 'object',
  68. properties: {
  69. version: {
  70. type: 'string'
  71. },
  72. ignores: {
  73. type: 'array',
  74. items: {
  75. enum: SYNTAX_NAMES
  76. },
  77. uniqueItems: true
  78. }
  79. },
  80. additionalProperties: false
  81. }
  82. ],
  83. messages: {
  84. // Vue.js 2.5.0+
  85. forbiddenSlotScopeAttribute:
  86. '`slot-scope` are not supported except Vue.js ">=2.5.0 <3.0.0".',
  87. // Vue.js 2.6.0+
  88. forbiddenDynamicDirectiveArguments:
  89. 'Dynamic arguments are not supported until Vue.js "2.6.0".',
  90. forbiddenVSlot: '`v-slot` are not supported until Vue.js "2.6.0".',
  91. // Vue.js 2.7.0+
  92. forbiddenScriptSetup:
  93. '`<script setup>` is not supported until Vue.js "2.7.0".',
  94. forbiddenStyleCssVarsInjection:
  95. 'SFC CSS variable injection is not supported until Vue.js ">=3.0.3 || >=2.7.0 <3.0.0".',
  96. // Vue.js 3.0.0+
  97. forbiddenVModelArgument:
  98. 'Argument on `v-model` is not supported until Vue.js "3.0.0".',
  99. forbiddenVModelCustomModifiers:
  100. 'Custom modifiers on `v-model` are not supported until Vue.js "3.0.0".',
  101. forbiddenVIs: '`v-is` are not supported until Vue.js "3.0.0".',
  102. // Vue.js 3.1.0+
  103. forbiddenIsAttributeWithVuePrefix:
  104. '`is="vue:"` are not supported until Vue.js "3.1.0".',
  105. // Vue.js 3.2.0+
  106. forbiddenVMemo: '`v-memo` are not supported until Vue.js "3.2.0".',
  107. forbiddenVBindPropModifierShorthand:
  108. '`.prop` shorthand are not supported until Vue.js "3.2.0".',
  109. forbiddenVBindAttrModifier:
  110. '`.attr` modifiers on `v-bind` are not supported until Vue.js "3.2.0".'
  111. }
  112. },
  113. /** @param {RuleContext} context */
  114. create(context) {
  115. const { version, ignores } = Object.assign(
  116. {
  117. version: null,
  118. ignores: []
  119. },
  120. context.options[0] || {}
  121. )
  122. if (!version) {
  123. // version is not set.
  124. return {}
  125. }
  126. const versionRange = getSemverRange(version)
  127. /**
  128. * Check whether a given case object is full-supported on the configured node version.
  129. * @param {SyntaxRule} aCase The case object to check.
  130. * @returns {boolean} `true` if it's supporting.
  131. */
  132. function isNotSupportingVersion(aCase) {
  133. return !semver.subset(versionRange, getSemverRange(aCase.supported))
  134. }
  135. /** @type {TemplateListener} */
  136. let templateBodyVisitor = {}
  137. /** @type {RuleListener} */
  138. let scriptVisitor = {}
  139. for (const syntaxName of SYNTAX_NAMES) {
  140. /** @type {SyntaxRule} */
  141. const syntax = FEATURES[syntaxName]
  142. if (ignores.includes(syntaxName) || !isNotSupportingVersion(syntax)) {
  143. continue
  144. }
  145. if (syntax.createTemplateBodyVisitor) {
  146. const visitor = syntax.createTemplateBodyVisitor(context)
  147. templateBodyVisitor = utils.compositingVisitors(
  148. templateBodyVisitor,
  149. visitor
  150. )
  151. }
  152. if (syntax.createScriptVisitor) {
  153. const visitor = syntax.createScriptVisitor(context)
  154. scriptVisitor = utils.compositingVisitors(scriptVisitor, visitor)
  155. }
  156. }
  157. return utils.defineTemplateBodyVisitor(
  158. context,
  159. templateBodyVisitor,
  160. scriptVisitor
  161. )
  162. }
  163. }