compatConfig.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import { SourceLocation } from '../ast'
  2. import { CompilerError } from '../errors'
  3. import { MergedParserOptions } from '../parser'
  4. import { TransformContext } from '../transform'
  5. export type CompilerCompatConfig = Partial<
  6. Record<CompilerDeprecationTypes, boolean | 'suppress-warning'>
  7. > & {
  8. MODE?: 2 | 3
  9. }
  10. export interface CompilerCompatOptions {
  11. compatConfig?: CompilerCompatConfig
  12. }
  13. export enum CompilerDeprecationTypes {
  14. COMPILER_IS_ON_ELEMENT = 'COMPILER_IS_ON_ELEMENT',
  15. COMPILER_V_BIND_SYNC = 'COMPILER_V_BIND_SYNC',
  16. COMPILER_V_BIND_OBJECT_ORDER = 'COMPILER_V_BIND_OBJECT_ORDER',
  17. COMPILER_V_ON_NATIVE = 'COMPILER_V_ON_NATIVE',
  18. COMPILER_V_IF_V_FOR_PRECEDENCE = 'COMPILER_V_IF_V_FOR_PRECEDENCE',
  19. COMPILER_NATIVE_TEMPLATE = 'COMPILER_NATIVE_TEMPLATE',
  20. COMPILER_INLINE_TEMPLATE = 'COMPILER_INLINE_TEMPLATE',
  21. COMPILER_FILTERS = 'COMPILER_FILTER'
  22. }
  23. type DeprecationData = {
  24. message: string | ((...args: any[]) => string)
  25. link?: string
  26. }
  27. const deprecationData: Record<CompilerDeprecationTypes, DeprecationData> = {
  28. [CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT]: {
  29. message:
  30. `Platform-native elements with "is" prop will no longer be ` +
  31. `treated as components in Vue 3 unless the "is" value is explicitly ` +
  32. `prefixed with "vue:".`,
  33. link: `https://v3-migration.vuejs.org/breaking-changes/custom-elements-interop.html`
  34. },
  35. [CompilerDeprecationTypes.COMPILER_V_BIND_SYNC]: {
  36. message: key =>
  37. `.sync modifier for v-bind has been removed. Use v-model with ` +
  38. `argument instead. \`v-bind:${key}.sync\` should be changed to ` +
  39. `\`v-model:${key}\`.`,
  40. link: `https://v3-migration.vuejs.org/breaking-changes/v-model.html`
  41. },
  42. [CompilerDeprecationTypes.COMPILER_V_BIND_OBJECT_ORDER]: {
  43. message:
  44. `v-bind="obj" usage is now order sensitive and behaves like JavaScript ` +
  45. `object spread: it will now overwrite an existing non-mergeable attribute ` +
  46. `that appears before v-bind in the case of conflict. ` +
  47. `To retain 2.x behavior, move v-bind to make it the first attribute. ` +
  48. `You can also suppress this warning if the usage is intended.`,
  49. link: `https://v3-migration.vuejs.org/breaking-changes/v-bind.html`
  50. },
  51. [CompilerDeprecationTypes.COMPILER_V_ON_NATIVE]: {
  52. message: `.native modifier for v-on has been removed as is no longer necessary.`,
  53. link: `https://v3-migration.vuejs.org/breaking-changes/v-on-native-modifier-removed.html`
  54. },
  55. [CompilerDeprecationTypes.COMPILER_V_IF_V_FOR_PRECEDENCE]: {
  56. message:
  57. `v-if / v-for precedence when used on the same element has changed ` +
  58. `in Vue 3: v-if now takes higher precedence and will no longer have ` +
  59. `access to v-for scope variables. It is best to avoid the ambiguity ` +
  60. `with <template> tags or use a computed property that filters v-for ` +
  61. `data source.`,
  62. link: `https://v3-migration.vuejs.org/breaking-changes/v-if-v-for.html`
  63. },
  64. [CompilerDeprecationTypes.COMPILER_NATIVE_TEMPLATE]: {
  65. message:
  66. `<template> with no special directives will render as a native template ` +
  67. `element instead of its inner content in Vue 3.`
  68. },
  69. [CompilerDeprecationTypes.COMPILER_INLINE_TEMPLATE]: {
  70. message: `"inline-template" has been removed in Vue 3.`,
  71. link: `https://v3-migration.vuejs.org/breaking-changes/inline-template-attribute.html`
  72. },
  73. [CompilerDeprecationTypes.COMPILER_FILTERS]: {
  74. message:
  75. `filters have been removed in Vue 3. ` +
  76. `The "|" symbol will be treated as native JavaScript bitwise OR operator. ` +
  77. `Use method calls or computed properties instead.`,
  78. link: `https://v3-migration.vuejs.org/breaking-changes/filters.html`
  79. }
  80. }
  81. function getCompatValue(
  82. key: CompilerDeprecationTypes | 'MODE',
  83. { compatConfig }: MergedParserOptions | TransformContext
  84. ) {
  85. const value = compatConfig && compatConfig[key]
  86. if (key === 'MODE') {
  87. return value || 3 // compiler defaults to v3 behavior
  88. } else {
  89. return value
  90. }
  91. }
  92. export function isCompatEnabled(
  93. key: CompilerDeprecationTypes,
  94. context: MergedParserOptions | TransformContext
  95. ) {
  96. const mode = getCompatValue('MODE', context)
  97. const value = getCompatValue(key, context)
  98. // in v3 mode, only enable if explicitly set to true
  99. // otherwise enable for any non-false value
  100. return mode === 3 ? value === true : value !== false
  101. }
  102. export function checkCompatEnabled(
  103. key: CompilerDeprecationTypes,
  104. context: MergedParserOptions | TransformContext,
  105. loc: SourceLocation | null,
  106. ...args: any[]
  107. ): boolean {
  108. const enabled = isCompatEnabled(key, context)
  109. if (__DEV__ && enabled) {
  110. warnDeprecation(key, context, loc, ...args)
  111. }
  112. return enabled
  113. }
  114. export function warnDeprecation(
  115. key: CompilerDeprecationTypes,
  116. context: MergedParserOptions | TransformContext,
  117. loc: SourceLocation | null,
  118. ...args: any[]
  119. ) {
  120. const val = getCompatValue(key, context)
  121. if (val === 'suppress-warning') {
  122. return
  123. }
  124. const { message, link } = deprecationData[key]
  125. const msg = `(deprecation ${key}) ${
  126. typeof message === 'function' ? message(...args) : message
  127. }${link ? `\n Details: ${link}` : ``}`
  128. const err = new SyntaxError(msg) as CompilerError
  129. err.code = key
  130. if (loc) err.loc = loc
  131. context.onWarn(err)
  132. }