test: compiler integration tests
This commit is contained in:
@@ -150,6 +150,7 @@ export function generate(
|
||||
const context = createCodegenContext(ast, options)
|
||||
const { mode, push, prefixIdentifiers, indent, deindent, newline } = context
|
||||
const hasImports = ast.imports.length
|
||||
const useWithBlock = !prefixIdentifiers && mode !== 'module'
|
||||
|
||||
// preambles
|
||||
if (mode === 'function') {
|
||||
@@ -170,7 +171,7 @@ export function generate(
|
||||
} else {
|
||||
// generate import statements for helpers
|
||||
if (hasImports) {
|
||||
push(`import { ${ast.imports.join(', ')} } from 'vue'\n`)
|
||||
push(`import { ${ast.imports.join(', ')} } from "vue"\n`)
|
||||
}
|
||||
genHoists(ast.hoists, context)
|
||||
push(`export default `)
|
||||
@@ -180,12 +181,12 @@ export function generate(
|
||||
push(`function render() {`)
|
||||
indent()
|
||||
|
||||
if (!prefixIdentifiers) {
|
||||
if (useWithBlock) {
|
||||
push(`with (this) {`)
|
||||
indent()
|
||||
// function mode const declarations should be inside with block
|
||||
// also they should be renamed to avoid collision with user properties
|
||||
if (mode === 'function' && hasImports) {
|
||||
if (hasImports) {
|
||||
push(`const { ${ast.imports.map(n => `${n}: _${n}`).join(', ')} } = _Vue`)
|
||||
newline()
|
||||
}
|
||||
@@ -206,10 +207,12 @@ export function generate(
|
||||
// generate the VNode tree expression
|
||||
push(`return `)
|
||||
genChildren(ast.children, context, true)
|
||||
if (!prefixIdentifiers) {
|
||||
|
||||
if (useWithBlock) {
|
||||
deindent()
|
||||
push(`}`)
|
||||
}
|
||||
|
||||
deindent()
|
||||
push(`}`)
|
||||
return {
|
||||
|
||||
@@ -70,7 +70,8 @@ export const enum ErrorCodes {
|
||||
X_V_ON_NO_EXPRESSION,
|
||||
|
||||
// generic errors
|
||||
X_PREFIX_ID_NOT_SUPPORTED
|
||||
X_PREFIX_ID_NOT_SUPPORTED,
|
||||
X_MODULE_MODE_NOT_SUPPORTED
|
||||
}
|
||||
|
||||
export const errorMessages: { [code: number]: string } = {
|
||||
@@ -138,5 +139,6 @@ export const errorMessages: { [code: number]: string } = {
|
||||
[ErrorCodes.X_V_ON_NO_EXPRESSION]: `v-on is missing expression`,
|
||||
|
||||
// generic errors
|
||||
[ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED]: `"prefixIdentifiers" option is not supported in this build of compiler because it is optimized for payload size.`
|
||||
[ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED]: `"prefixIdentifiers" option is not supported in this build of compiler.`,
|
||||
[ErrorCodes.X_MODULE_MODE_NOT_SUPPORTED]: `ES module mode is not supported in this build of compiler.`
|
||||
}
|
||||
|
||||
@@ -18,15 +18,21 @@ export function compile(
|
||||
template: string | RootNode,
|
||||
options: CompilerOptions = {}
|
||||
): CodegenResult {
|
||||
if (__BROWSER__ && options.prefixIdentifiers === false) {
|
||||
;(options.onError || defaultOnError)(
|
||||
createCompilerError(ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED)
|
||||
)
|
||||
if (__BROWSER__) {
|
||||
const onError = options.onError || defaultOnError
|
||||
if (options.prefixIdentifiers === true) {
|
||||
onError(createCompilerError(ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED))
|
||||
} else if (options.mode === 'module') {
|
||||
onError(createCompilerError(ErrorCodes.X_MODULE_MODE_NOT_SUPPORTED))
|
||||
}
|
||||
}
|
||||
|
||||
const ast = isString(template) ? parse(template, options) : template
|
||||
|
||||
const prefixIdentifiers = !__BROWSER__ && options.prefixIdentifiers === true
|
||||
const prefixIdentifiers =
|
||||
!__BROWSER__ &&
|
||||
(options.prefixIdentifiers === true || options.mode === 'module')
|
||||
|
||||
transform(ast, {
|
||||
...options,
|
||||
prefixIdentifiers,
|
||||
|
||||
@@ -12,7 +12,7 @@ import { parseScript } from 'meriyah'
|
||||
import { walk } from 'estree-walker'
|
||||
import { NodeTransform, TransformContext } from '../transform'
|
||||
import { NodeTypes, createExpression, ExpressionNode } from '../ast'
|
||||
import { Node, Function, Identifier } from 'estree'
|
||||
import { Node, Function, Identifier, Property } from 'estree'
|
||||
import { advancePositionWithClone } from '../utils'
|
||||
export const transformExpression: NodeTransform = (node, context) => {
|
||||
if (node.type === NodeTypes.EXPRESSION && !node.isStatic) {
|
||||
@@ -43,12 +43,15 @@ const simpleIdRE = /^[a-zA-Z$_][\w$]*$/
|
||||
const isFunction = (node: Node): node is Function =>
|
||||
/Function(Expression|Declaration)$/.test(node.type)
|
||||
|
||||
const isPropertyKey = (node: Node, parent: Node) =>
|
||||
parent.type === 'Property' && parent.key === node && !parent.computed
|
||||
|
||||
// cache node requires
|
||||
let _parseScript: typeof parseScript
|
||||
let _walk: typeof walk
|
||||
|
||||
interface PrefixMeta {
|
||||
prefix: string
|
||||
prefix?: string
|
||||
start: number
|
||||
end: number
|
||||
}
|
||||
@@ -72,7 +75,7 @@ export function processExpression(
|
||||
// fast path if expression is a simple identifier.
|
||||
if (simpleIdRE.test(node.content)) {
|
||||
if (!context.identifiers[node.content]) {
|
||||
node.children = [`_ctx.`, createExpression(node.content, false, node.loc)]
|
||||
node.content = `_ctx.${node.content}`
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -92,23 +95,23 @@ export function processExpression(
|
||||
walk(ast, {
|
||||
enter(node: Node & PrefixMeta, parent) {
|
||||
if (node.type === 'Identifier') {
|
||||
if (
|
||||
!ids.includes(node) &&
|
||||
!knownIds[node.name] &&
|
||||
shouldPrefix(node, parent)
|
||||
) {
|
||||
if (
|
||||
parent.type === 'Property' &&
|
||||
parent.value === node &&
|
||||
parent.key === node
|
||||
) {
|
||||
// property shorthand like { foo }, we need to add the key since we
|
||||
// rewrite the value
|
||||
node.prefix = `${node.name}: _ctx.`
|
||||
} else {
|
||||
node.prefix = `_ctx.`
|
||||
if (!ids.includes(node)) {
|
||||
if (!knownIds[node.name] && shouldPrefix(node, parent)) {
|
||||
if (
|
||||
isPropertyKey(node, parent) &&
|
||||
(parent as Property).value === node
|
||||
) {
|
||||
// property shorthand like { foo }, we need to add the key since we
|
||||
// rewrite the value
|
||||
node.prefix = `${node.name}: `
|
||||
}
|
||||
node.name = `_ctx.${node.name}`
|
||||
ids.push(node)
|
||||
} else if (!isPropertyKey(node, parent)) {
|
||||
// also generate sub-expressioms for other identifiers for better
|
||||
// source map support. (except for property keys which are static)
|
||||
ids.push(node)
|
||||
}
|
||||
ids.push(node)
|
||||
}
|
||||
} else if (isFunction(node)) {
|
||||
// walk function expressions and add its arguments to known identifiers
|
||||
@@ -147,7 +150,9 @@ export function processExpression(
|
||||
ids.forEach((id, i) => {
|
||||
const last = ids[i - 1] as any
|
||||
const leadingText = full.slice(last ? last.end - 1 : 0, id.start - 1)
|
||||
children.push(leadingText + id.prefix)
|
||||
if (leadingText.length || id.prefix) {
|
||||
children.push(leadingText + (id.prefix || ``))
|
||||
}
|
||||
const source = full.slice(id.start - 1, id.end - 1)
|
||||
children.push(
|
||||
createExpression(id.name, false, {
|
||||
@@ -191,12 +196,9 @@ function shouldPrefix(identifier: Identifier, parent: Node) {
|
||||
) &&
|
||||
// not a key of Property
|
||||
!(
|
||||
parent.type === 'Property' &&
|
||||
parent.key === identifier &&
|
||||
// computed keys should be prefixed
|
||||
!parent.computed &&
|
||||
isPropertyKey(identifier, parent) &&
|
||||
// shorthand keys should be prefixed
|
||||
!(parent.value === identifier)
|
||||
!((parent as Property).value === identifier)
|
||||
) &&
|
||||
// not a property of a MemberExpression
|
||||
!(
|
||||
|
||||
@@ -2,7 +2,6 @@ import { DirectiveTransform } from '../transform'
|
||||
import { createObjectProperty, createExpression, ExpressionNode } from '../ast'
|
||||
import { capitalize } from '@vue/shared'
|
||||
import { createCompilerError, ErrorCodes } from '../errors'
|
||||
import { isSimpleIdentifier } from '../utils'
|
||||
|
||||
// v-on without arg is handled directly in ./element.ts due to it affecting
|
||||
// codegen for the entire props object. This transform here is only for v-on
|
||||
@@ -14,22 +13,18 @@ export const transformOn: DirectiveTransform = (
|
||||
if (!exp && !modifiers.length) {
|
||||
context.onError(createCompilerError(ErrorCodes.X_V_ON_NO_EXPRESSION, loc))
|
||||
}
|
||||
const { content, children, isStatic, loc: argLoc } = arg!
|
||||
const { content, isStatic, loc: argLoc } = arg!
|
||||
let eventName: ExpressionNode
|
||||
if (isStatic) {
|
||||
// static arg
|
||||
eventName = createExpression(`on${capitalize(content)}`, true, argLoc)
|
||||
} else if (!children) {
|
||||
// dynamic arg with no rewrite
|
||||
eventName = createExpression(
|
||||
`"on" + ${isSimpleIdentifier(content) ? content : `(${content})`}`,
|
||||
false,
|
||||
argLoc
|
||||
)
|
||||
} else {
|
||||
// dynamic arg with ctx prefixing
|
||||
// dynamic arg. turn it into a compound expression.
|
||||
eventName = arg!
|
||||
children.unshift(`"on" + `)
|
||||
;(
|
||||
eventName.children ||
|
||||
(eventName.children = [{ ...eventName, children: undefined }])
|
||||
).unshift(`"on" + `)
|
||||
}
|
||||
// TODO .once modifier handling since it is platform agnostic
|
||||
// other modifiers are handled in compiler-dom
|
||||
|
||||
Reference in New Issue
Block a user