2021-04-12 23:42:09 +00:00
|
|
|
import { SourceLocation } from '../ast'
|
|
|
|
import { CompilerError } from '../errors'
|
|
|
|
import { ParserContext } from '../parse'
|
|
|
|
import { TransformContext } from '../transform'
|
|
|
|
|
|
|
|
export type CompilerCompatConfig = Partial<
|
|
|
|
Record<CompilerDeprecationTypes, boolean | 'suppress-warning'>
|
|
|
|
> & {
|
|
|
|
MODE?: 2 | 3
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface CompilerCompatOptions {
|
|
|
|
compatConfig?: CompilerCompatConfig
|
|
|
|
}
|
|
|
|
|
|
|
|
export const enum CompilerDeprecationTypes {
|
2021-04-16 16:19:12 +00:00
|
|
|
COMPILER_IS_ON_ELEMENT = 'COMPILER_IS_ON_ELEMENT',
|
|
|
|
COMPILER_V_BIND_SYNC = 'COMPILER_V_BIND_SYNC',
|
2021-04-16 21:11:44 +00:00
|
|
|
COMPILER_V_BIND_PROP = 'COMPILER_V_BIND_PROP',
|
2021-04-16 16:19:12 +00:00
|
|
|
COMPILER_V_BIND_OBJECT_ORDER = 'COMPILER_V_BIND_OBJECT_ORDER',
|
2021-04-16 21:11:44 +00:00
|
|
|
COMPILER_V_ON_NATIVE = 'COMPILER_V_ON_NATIVE',
|
2021-04-16 16:19:12 +00:00
|
|
|
COMPILER_V_IF_V_FOR_PRECEDENCE = 'COMPILER_V_IF_V_FOR_PRECEDENCE',
|
2021-04-18 03:19:40 +00:00
|
|
|
COMPILER_NATIVE_TEMPLATE = 'COMPILER_NATIVE_TEMPLATE',
|
|
|
|
COMPILER_INLINE_TEMPLATE = 'COMPILER_INLINE_TEMPLATE',
|
2021-04-19 16:08:26 +00:00
|
|
|
COMPILER_FILTERS = 'COMPILER_FILTER'
|
2021-04-12 23:42:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type DeprecationData = {
|
|
|
|
message: string | ((...args: any[]) => string)
|
|
|
|
link?: string
|
|
|
|
}
|
|
|
|
|
|
|
|
const deprecationData: Record<CompilerDeprecationTypes, DeprecationData> = {
|
2021-04-16 16:19:12 +00:00
|
|
|
[CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT]: {
|
2021-04-16 15:43:05 +00:00
|
|
|
message:
|
|
|
|
`Platform-native elements with "is" prop will no longer be ` +
|
|
|
|
`treated as components in Vue 3 unless the "is" value is explicitly ` +
|
|
|
|
`prefixed with "vue:".`,
|
2021-04-12 23:42:09 +00:00
|
|
|
link: `https://v3.vuejs.org/guide/migration/custom-elements-interop.html`
|
|
|
|
},
|
|
|
|
|
2021-04-16 16:19:12 +00:00
|
|
|
[CompilerDeprecationTypes.COMPILER_V_BIND_SYNC]: {
|
2021-04-12 23:42:09 +00:00
|
|
|
message: key =>
|
|
|
|
`.sync modifier for v-bind has been removed. Use v-model with ` +
|
|
|
|
`argument instead. \`v-bind:${key}.sync\` should be changed to ` +
|
|
|
|
`\`v-model:${key}\`.`,
|
|
|
|
link: `https://v3.vuejs.org/guide/migration/v-model.html`
|
|
|
|
},
|
|
|
|
|
2021-04-16 21:11:44 +00:00
|
|
|
[CompilerDeprecationTypes.COMPILER_V_BIND_PROP]: {
|
|
|
|
message:
|
|
|
|
`.prop modifier for v-bind has been removed and no longer necessary. ` +
|
|
|
|
`Vue 3 will automatically set a binding as DOM property when appropriate.`
|
|
|
|
},
|
|
|
|
|
2021-04-16 16:19:12 +00:00
|
|
|
[CompilerDeprecationTypes.COMPILER_V_BIND_OBJECT_ORDER]: {
|
2021-04-12 23:42:09 +00:00
|
|
|
message:
|
|
|
|
`v-bind="obj" usage is now order sensitive and behaves like JavaScript ` +
|
2021-04-17 20:26:13 +00:00
|
|
|
`object spread: it will now overwrite an existing non-mergeable attribute ` +
|
|
|
|
`that appears before v-bind in the case of conflict. ` +
|
|
|
|
`To retain 2.x behavior, move v-bind to make it the first attribute. ` +
|
|
|
|
`You can also suppress this warning if the usage is intended.`,
|
2021-04-12 23:42:09 +00:00
|
|
|
link: `https://v3.vuejs.org/guide/migration/v-bind.html`
|
|
|
|
},
|
|
|
|
|
2021-04-16 21:11:44 +00:00
|
|
|
[CompilerDeprecationTypes.COMPILER_V_ON_NATIVE]: {
|
2021-04-12 23:42:09 +00:00
|
|
|
message: `.native modifier for v-on has been removed as is no longer necessary.`,
|
|
|
|
link: `https://v3.vuejs.org/guide/migration/v-on-native-modifier-removed.html`
|
|
|
|
},
|
|
|
|
|
2021-04-16 16:19:12 +00:00
|
|
|
[CompilerDeprecationTypes.COMPILER_V_IF_V_FOR_PRECEDENCE]: {
|
2021-04-12 23:42:09 +00:00
|
|
|
message:
|
|
|
|
`v-if / v-for precedence when used on the same element has changed ` +
|
2021-04-17 18:38:30 +00:00
|
|
|
`in Vue 3: v-if now takes higher precedence and will no longer have ` +
|
|
|
|
`access to v-for scope variables. It is best to avoid the ambiguity ` +
|
|
|
|
`with <template> tags or use a computed property that filters v-for ` +
|
|
|
|
`data source.`,
|
2021-04-12 23:42:09 +00:00
|
|
|
link: `https://v3.vuejs.org/guide/migration/v-if-v-for.html`
|
|
|
|
},
|
|
|
|
|
2021-04-16 16:19:12 +00:00
|
|
|
[CompilerDeprecationTypes.COMPILER_NATIVE_TEMPLATE]: {
|
2021-04-12 23:42:09 +00:00
|
|
|
message:
|
2021-04-18 02:16:48 +00:00
|
|
|
`<template> with no special directives will render as a native template ` +
|
2021-04-12 23:42:09 +00:00
|
|
|
`element instead of its inner content in Vue 3.`
|
2021-04-18 03:19:40 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
[CompilerDeprecationTypes.COMPILER_INLINE_TEMPLATE]: {
|
|
|
|
message: `"inline-template" has been removed in Vue 3.`,
|
|
|
|
link: `https://v3.vuejs.org/guide/migration/inline-template-attribute.html`
|
|
|
|
},
|
|
|
|
|
2021-04-19 16:08:26 +00:00
|
|
|
[CompilerDeprecationTypes.COMPILER_FILTERS]: {
|
|
|
|
message:
|
|
|
|
`filters have been removed in Vue 3. ` +
|
|
|
|
`The "|" symbol will be treated as native JavaScript bitwise OR operator. ` +
|
|
|
|
`Use method calls or computed properties instead.`,
|
2021-04-18 03:19:40 +00:00
|
|
|
link: `https://v3.vuejs.org/guide/migration/filters.html`
|
2021-04-12 23:42:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function getCompatValue(
|
2021-04-17 19:55:14 +00:00
|
|
|
key: CompilerDeprecationTypes | 'MODE',
|
2021-04-12 23:42:09 +00:00
|
|
|
context: ParserContext | TransformContext
|
|
|
|
) {
|
|
|
|
const config = (context as ParserContext).options
|
|
|
|
? (context as ParserContext).options.compatConfig
|
|
|
|
: (context as TransformContext).compatConfig
|
2021-04-17 19:55:14 +00:00
|
|
|
const value = config && config[key]
|
|
|
|
if (key === 'MODE') {
|
|
|
|
return value || 3 // compiler defaults to v3 behavior
|
|
|
|
} else {
|
|
|
|
return value
|
|
|
|
}
|
2021-04-12 23:42:09 +00:00
|
|
|
}
|
|
|
|
|
2021-04-17 20:26:13 +00:00
|
|
|
export function isCompatEnabled(
|
|
|
|
key: CompilerDeprecationTypes,
|
|
|
|
context: ParserContext | TransformContext
|
|
|
|
) {
|
|
|
|
const mode = getCompatValue('MODE', context)
|
|
|
|
const value = getCompatValue(key, context)
|
|
|
|
// in v3 mode, only enable if explicitly set to true
|
|
|
|
// otherwise enable for any non-false value
|
|
|
|
return mode === 3 ? value === true : value !== false
|
|
|
|
}
|
|
|
|
|
2021-04-12 23:42:09 +00:00
|
|
|
export function checkCompatEnabled(
|
|
|
|
key: CompilerDeprecationTypes,
|
|
|
|
context: ParserContext | TransformContext,
|
|
|
|
loc: SourceLocation | null,
|
|
|
|
...args: any[]
|
|
|
|
): boolean {
|
2021-04-17 20:26:13 +00:00
|
|
|
const enabled = isCompatEnabled(key, context)
|
2021-04-12 23:42:09 +00:00
|
|
|
if (__DEV__ && enabled) {
|
|
|
|
warnDeprecation(key, context, loc, ...args)
|
|
|
|
}
|
|
|
|
return enabled
|
|
|
|
}
|
|
|
|
|
|
|
|
export function warnDeprecation(
|
|
|
|
key: CompilerDeprecationTypes,
|
|
|
|
context: ParserContext | TransformContext,
|
|
|
|
loc: SourceLocation | null,
|
|
|
|
...args: any[]
|
|
|
|
) {
|
|
|
|
const val = getCompatValue(key, context)
|
|
|
|
if (val === 'suppress-warning') {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
const { message, link } = deprecationData[key]
|
|
|
|
const msg = `(deprecation ${key}) ${
|
|
|
|
typeof message === 'function' ? message(...args) : message
|
|
|
|
}${link ? `\n Details: ${link}` : ``}`
|
|
|
|
|
2021-04-16 15:51:47 +00:00
|
|
|
const err = new SyntaxError(msg) as CompilerError
|
|
|
|
err.code = key
|
|
|
|
if (loc) err.loc = loc
|
|
|
|
context.onWarn(err)
|
2021-04-12 23:42:09 +00:00
|
|
|
}
|