提交 a29f277d 编写于 作者: fxy060608's avatar fxy060608

wip(mp): support renderDataSpread

上级 efea3e80
view,
label,
swiper-item,
scroll-view {
display: flex;
flex-direction: column;
flex-shrink: 0;
flex-grow: 0;
flex-basis: auto;
align-items: stretch;
align-content: flex-start;
}
view,
image,
input,
scroll-view,
swiper,
swiper-item,
text,
textarea,
video {
position: relative;
border: 0px solid #000000;
box-sizing: border-box;
}
swiper-item {
position: absolute;
}
button {
margin: 0;
}
label,scroll-view,swiper-item,view{display:flex;flex-direction:column;flex-shrink:0;flex-grow:0;flex-basis:auto;align-items:stretch;align-content:flex-start}image,input,scroll-view,swiper,swiper-item,text,textarea,video,view{position:relative;border:0 solid #000;box-sizing:border-box}swiper-item{position:absolute}button{margin:0}
\ No newline at end of file
......@@ -38,7 +38,7 @@ describe('compiler: scope', () => {
`<view v-for="item in items"><view v-if="true" :data-id="id"></view></view>`,
`<view wx:for="{{a}}" wx:for-item="item"><view wx:if="{{true}}" data-id="{{item.a}}"></view></view>`,
`(_ctx, _cache) => {
return { a: _vFor(_ctx.items, (item, k0, i0) => { return { ...(true ? { a: _ctx.id } : {}) }; }) }
return { a: _vFor(_ctx.items, (item, k0, i0) => { return true ? { a: _ctx.id } : {}; }) }
}`
)
})
......@@ -47,7 +47,7 @@ describe('compiler: scope', () => {
`<view v-if="ok">{{ok}}</view><view v-else-if="ok1">{{ok1}}</view><view v-else-if="ok2">{{ok2}}</view><view v-else>{{ok3}}</view>`,
`<view wx:if="{{a}}">{{b}}</view><view wx:elif="{{c}}">{{d}}</view><view wx:elif="{{e}}">{{f}}</view><view wx:else>{{g}}</view>`,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? { b: _toDisplayString(_ctx.ok) } : _ctx.ok1 ? { d: _toDisplayString(_ctx.ok1) } : _ctx.ok2 ? { f: _toDisplayString(_ctx.ok2) } : { g: _toDisplayString(_ctx.ok3) }), c: _ctx.ok1, e: _ctx.ok2 }
return _extend({ a: _ctx.ok }, _ctx.ok ? { b: _toDisplayString(_ctx.ok) } : _ctx.ok1 ? { d: _toDisplayString(_ctx.ok1) } : _ctx.ok2 ? { f: _toDisplayString(_ctx.ok2) } : { g: _toDisplayString(_ctx.ok3) }, { c: _ctx.ok1, e: _ctx.ok2 })
}`
)
})
......@@ -56,7 +56,7 @@ describe('compiler: scope', () => {
`<view v-if="ok"><view v-for="item in items" :key="item.id" :data-title="item.title" :data-foo="foo" @click="onClick"/></view><view v-else-if="ok1"><view v-for="item in items" :key="item.id" :data-title="item.title" :data-foo="foo" @click="onClick"/></view><view v-else><view v-for="item in items" :key="item.id" :data-title="item.title" :data-foo="foo" @click="onClick"/></view>`,
`<view wx:if="{{a}}"><view wx:for="{{b}}" wx:for-item="item" wx:key="a" data-title="{{item.b}}" data-foo="{{c}}" bindtap="{{d}}"/></view><view wx:elif="{{e}}"><view wx:for="{{f}}" wx:for-item="item" wx:key="a" data-title="{{item.b}}" data-foo="{{g}}" bindtap="{{h}}"/></view><view wx:else><view wx:for="{{i}}" wx:for-item="item" wx:key="a" data-title="{{item.b}}" data-foo="{{j}}" bindtap="{{k}}"/></view>`,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? { b: _vFor(_ctx.items, (item, k0, i0) => { return { a: item.id, b: item.title }; }), c: _ctx.foo, d: _vOn(_ctx.onClick) } : _ctx.ok1 ? { f: _vFor(_ctx.items, (item, k0, i0) => { return { a: item.id, b: item.title }; }), g: _ctx.foo, h: _vOn(_ctx.onClick) } : { i: _vFor(_ctx.items, (item, k0, i0) => { return { a: item.id, b: item.title }; }), j: _ctx.foo, k: _vOn(_ctx.onClick) }), e: _ctx.ok1 }
return _extend({ a: _ctx.ok }, _ctx.ok ? { b: _vFor(_ctx.items, (item, k0, i0) => { return { a: item.id, b: item.title }; }), c: _ctx.foo, d: _vOn(_ctx.onClick) } : _ctx.ok1 ? { f: _vFor(_ctx.items, (item, k0, i0) => { return { a: item.id, b: item.title }; }), g: _ctx.foo, h: _vOn(_ctx.onClick) } : { i: _vFor(_ctx.items, (item, k0, i0) => { return { a: item.id, b: item.title }; }), j: _ctx.foo, k: _vOn(_ctx.onClick) }, { e: _ctx.ok1 })
}`
)
})
......
......@@ -37,11 +37,14 @@ function assert(
describe('compiler', () => {
test('scope', () => {
assert(
`<view :class="{ red: isRed }"/>`,
`<view class="{{[a && 'red']}}"/>`,
`<view v-for="item in items"><view v-if="ok"></view></view>`,
`<view wx:if="{{a}}">{{b}}</view>`,
`(_ctx, _cache) => {
return { a: _ctx.isRed ? 1 : 0 }
}`
return { a: _vFor(_ctx.items, (item, k0, i0) => { return _ctx.ok ? {} : {}; }), b: _ctx.ok }
}`,
{
renderDataSpread: false,
}
)
})
})
......@@ -201,7 +201,7 @@ describe(`compiler: v-for`, () => {
`<view v-if="ok" v-for="i in list"/>`,
`<view wx:if="{{a}}" wx:for="{{b}}" wx:for-item="i"/>`,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? { b: _vFor(_ctx.list, (i, k0, i0) => { return {}; }) } : {}) }
return _extend({ a: _ctx.ok }, _ctx.ok ? { b: _vFor(_ctx.list, (i, k0, i0) => { return {}; }) } : {})
}`
)
})
......@@ -211,7 +211,7 @@ describe(`compiler: v-for`, () => {
`<template v-if="ok" v-for="i in list"/>`,
`<block wx:if="{{a}}" wx:for="{{b}}" wx:for-item="i"/>`,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? { b: _vFor(_ctx.list, (i, k0, i0) => { return {}; }) } : {}) }
return _extend({ a: _ctx.ok }, _ctx.ok ? { b: _vFor(_ctx.list, (i, k0, i0) => { return {}; }) } : {})
}`
)
})
......
......@@ -29,7 +29,7 @@ describe(`compiler: v-if`, () => {
`<view v-if="ok"/>`,
`<view wx:if="{{a}}"/>`,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? {} : {}) }
return _extend({ a: _ctx.ok }, _ctx.ok ? {} : {})
}`
)
})
......@@ -38,7 +38,7 @@ describe(`compiler: v-if`, () => {
`<template v-if="ok"><view/>hello<view/></template>`,
`<block wx:if="{{a}}"><view/>hello<view/></block>`,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? {} : {}) }
return _extend({ a: _ctx.ok }, _ctx.ok ? {} : {})
}`
)
})
......@@ -47,7 +47,7 @@ describe(`compiler: v-if`, () => {
`<template v-if="ok"><slot/></template>`,
`<block wx:if="{{a}}"><slot/></block>`,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? {} : {}) }
return _extend({ a: _ctx.ok }, _ctx.ok ? {} : {})
}`
)
})
......@@ -56,7 +56,7 @@ describe(`compiler: v-if`, () => {
`<slot v-if="ok"/>`,
`<slot wx:if="{{a}}"/>`,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? {} : {}) }
return _extend({ a: _ctx.ok }, _ctx.ok ? {} : {})
}`
)
})
......@@ -65,7 +65,7 @@ describe(`compiler: v-if`, () => {
// `<Component v-if="ok"></Component>`,
// `<Component wx:if="{{a}}"></Component>`,
// `(_ctx, _cache) => {
// return { a: _ctx.ok, ...(_ctx.ok ? {} : {}) }
// return _extend({ a: _ctx.ok }, _ctx.ok ? {} : {})
// }`
// )
})
......@@ -74,7 +74,7 @@ describe(`compiler: v-if`, () => {
`<view v-if="ok"/><view v-else/>`,
`<view wx:if="{{a}}"/><view wx:else/>`,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? {} : {}) }
return _extend({ a: _ctx.ok }, _ctx.ok ? {} : {})
}`
)
})
......@@ -83,7 +83,7 @@ describe(`compiler: v-if`, () => {
`<view v-if="ok"/><view v-else-if="orNot"/>`,
`<view wx:if="{{a}}"/><view wx:elif="{{b}}"/>`,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? {} : _ctx.orNot ? {} : {}), b: _ctx.orNot }
return _extend({ a: _ctx.ok }, _ctx.ok ? {} : _ctx.orNot ? {} : {}, { b: _ctx.orNot })
}`
)
})
......@@ -92,7 +92,7 @@ describe(`compiler: v-if`, () => {
`<view v-if="ok"/><view v-else-if="orNot"/><template v-else>fine</template>`,
`<view wx:if="{{a}}"/><view wx:elif="{{b}}"/><block wx:else>fine</block>`,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? {} : _ctx.orNot ? {} : {}), b: _ctx.orNot }
return _extend({ a: _ctx.ok }, _ctx.ok ? {} : _ctx.orNot ? {} : {}, { b: _ctx.orNot })
}`
)
})
......@@ -119,7 +119,7 @@ describe(`compiler: v-if`, () => {
`<view v-if="ok"/><view v-else-if="orNot"/><view v-else-if="3"/><template v-else>fine</template>`,
`<view wx:if="{{a}}"/><view wx:elif="{{b}}"/><view wx:elif="{{3}}"/><block wx:else>fine</block>`,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? {} : _ctx.orNot ? {} : 3 ? {} : {}), b: _ctx.orNot }
return _extend({ a: _ctx.ok }, _ctx.ok ? {} : _ctx.orNot ? {} : 3 ? {} : {}, { b: _ctx.orNot })
}`
)
})
......@@ -134,7 +134,7 @@ describe(`compiler: v-if`, () => {
`,
`<view wx:if="{{a}}"/><view wx:elif="{{b}}"/><block wx:else>fine</block>`,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? {} : _ctx.orNot ? {} : {}), b: _ctx.orNot }
return _extend({ a: _ctx.ok }, _ctx.ok ? {} : _ctx.orNot ? {} : {}, { b: _ctx.orNot })
}`
)
})
......@@ -143,7 +143,7 @@ describe(`compiler: v-if`, () => {
`<view v-if="ok"/> <view v-else-if="no"/> <view v-else/>`,
`<view wx:if="{{a}}"/><view wx:elif="{{b}}"/><view wx:else/>`,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? {} : _ctx.no ? {} : {}), b: _ctx.no }
return _extend({ a: _ctx.ok }, _ctx.ok ? {} : _ctx.no ? {} : {}, { b: _ctx.no })
}`
)
})
......@@ -163,7 +163,7 @@ describe(`compiler: v-if`, () => {
`,
`<block wx:if="{{a}}"><view wx:if="{{b}}"></view><view wx:else/><view/></block>`,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? { b: _ctx.ok2, ...(_ctx.ok2 ? {} : {}) } : {}) }
return _extend({ a: _ctx.ok }, _ctx.ok ? _extend({ b: _ctx.ok2 }, _ctx.ok2 ? {} : {}) : {})
}`
)
})
......
......@@ -14,7 +14,6 @@ import { Expression } from '@babel/types'
import { default as babelGenerate } from '@babel/generator'
import { addImportDeclaration, matchEasycom } from '@dcloudio/uni-cli-shared'
import { CodegenOptions, CodegenRootNode } from './options'
import { createObjectExpression } from './ast'
import {
BindingComponentTypes,
......@@ -22,7 +21,7 @@ import {
TransformContext,
} from './transform'
interface CodegenContext extends CodegenOptions {
interface CodegenContext extends Omit<CodegenOptions, 'renderDataExpr'> {
code: string
bindingComponents: TransformContext['bindingComponents']
indentLevel: number
......@@ -89,7 +88,7 @@ export function generate(
}
push(`return `)
push(genBabelExpr(createObjectExpression(ast.scope.properties)))
push(genBabelExpr(ast.renderData))
if (useWithBlock) {
deindent()
push(`}`)
......
......@@ -4,7 +4,12 @@ import { isString, extend } from '@vue/shared'
import { hash, parseFilterNames } from '@dcloudio/uni-cli-shared'
import { generate } from './codegen'
import { CompilerOptions } from './options'
import { DirectiveTransform, NodeTransform, transform } from './transform'
import {
DirectiveTransform,
NodeTransform,
transform,
TransformContext,
} from './transform'
import { transformExpression } from './transforms/transformExpression'
import { transformIdentifier } from './transforms/transformIdentifier'
import { transformIf } from './transforms/vIf'
......@@ -14,6 +19,27 @@ import { transformOn } from './transforms/vOn'
import { transformElement } from './transforms/transformElement'
import { transformBind } from './transforms/vBind'
import { transformComponent } from './transforms/transformComponent'
import {
ArrowFunctionExpression,
BlockStatement,
CallExpression,
callExpression,
ConditionalExpression,
identifier,
isCallExpression,
isConditionalExpression,
isIdentifier,
isObjectExpression,
isObjectProperty,
isSpreadElement,
objectExpression,
ObjectExpression,
ObjectProperty,
ReturnStatement,
SpreadElement,
} from '@babel/types'
import { createObjectExpression } from './ast'
import { EXTEND } from './runtimeHelpers'
export type TransformPreset = [
NodeTransform[],
......@@ -74,7 +100,7 @@ export function baseCompile(template: string, options: CompilerOptions = {}) {
const result = extend(
generate(
extend(ast, {
scope: context.scope,
renderData: createRenderDataExpr(context.scope.properties, context),
bindingComponents: context.bindingComponents,
}),
options
......@@ -114,3 +140,114 @@ function parseFilters(lang: string, filename: string) {
}
return []
}
function createRenderDataExpr(
properties: (ObjectProperty | SpreadElement)[],
context: TransformContext
) {
const objExpr = createObjectExpression(properties)
if (context.renderDataSpread || !hasSpreadElement(objExpr)) {
return objExpr
}
return transformObjectSpreadExpr(objExpr, context)
}
function hasSpreadElement(expr: ObjectExpression): boolean {
return expr.properties.some((prop) => {
if (isSpreadElement(prop)) {
return true
} else {
const objExpr = parseReturnObjExpr(prop as ObjectProperty)
if (objExpr) {
return hasSpreadElement(objExpr)
}
}
})
}
function parseReturnObjExpr(prop: ObjectProperty) {
if (
isObjectProperty(prop) &&
isCallExpression(prop.value) &&
isIdentifier(prop.value.callee) &&
prop.value.callee.name === '_vFor'
) {
// 目前硬编码
return (
(
(prop.value.arguments[1] as ArrowFunctionExpression)
.body as BlockStatement
).body[0] as ReturnStatement
).argument as ObjectExpression
}
}
function transformObjectPropertyExpr(
prop: ObjectProperty,
context: TransformContext
) {
// vFor
const objExpr = parseReturnObjExpr(prop)
if (objExpr) {
if (hasSpreadElement(objExpr)) {
;(
(
(
(prop.value as CallExpression)
.arguments[1] as ArrowFunctionExpression
).body as BlockStatement
).body[0] as ReturnStatement
).argument = transformObjectSpreadExpr(objExpr, context)
}
}
return prop
}
function transformObjectSpreadExpr(
objExpr: ObjectExpression,
context: TransformContext
) {
const properties = objExpr.properties as (ObjectProperty | SpreadElement)[]
const args: (ObjectExpression | ConditionalExpression)[] = []
let objExprProperties: ObjectProperty[] = []
properties.forEach((prop) => {
if (isObjectProperty(prop)) {
objExprProperties.push(transformObjectPropertyExpr(prop, context))
} else {
if (objExprProperties.length) {
args.push(objectExpression(objExprProperties))
}
args.push(
transformConditionalExpression(
prop.argument as ConditionalExpression,
context
)
)
objExprProperties = []
}
})
if (objExprProperties.length) {
args.push(objectExpression(objExprProperties))
}
if (args.length === 1) {
return args[0] as ObjectExpression
}
return callExpression(identifier(context.helperString(EXTEND)), args)
}
function transformConditionalExpression(
expr: ConditionalExpression,
context: TransformContext
) {
const { consequent, alternate } = expr
if (isObjectExpression(consequent) && hasSpreadElement(consequent)) {
expr.consequent = transformObjectSpreadExpr(consequent, context)
}
if (isObjectExpression(alternate)) {
if (hasSpreadElement(alternate)) {
expr.alternate = transformObjectSpreadExpr(alternate, context)
}
} else if (isConditionalExpression(alternate)) {
transformConditionalExpression(alternate, context)
}
return expr
}
import { ParserPlugin } from '@babel/parser'
import { Expression, ObjectProperty, SpreadElement } from '@babel/types'
import {
CallExpression,
Expression,
ObjectExpression,
ObjectProperty,
SpreadElement,
} from '@babel/types'
import { MiniProgramCompilerOptions } from '@dcloudio/uni-cli-shared'
import { BindingMetadata, CompilerError, RootNode } from '@vue/compiler-core'
import IdentifierGenerator from './identifier'
......@@ -11,7 +17,7 @@ import {
import { VForOptions } from './transforms/vFor'
export interface CodegenRootNode extends RootNode {
scope: CodegenScope
renderData: ObjectExpression | CallExpression
bindingComponents: TransformContext['bindingComponents']
}
......@@ -49,6 +55,7 @@ export interface TransformOptions
hashId?: string | null
scopeId?: string | null
filters?: string[]
renderDataSpread?: boolean
cacheHandlers?: boolean
nodeTransforms?: NodeTransform[]
directiveTransforms?: Record<string, DirectiveTransform | undefined>
......
......@@ -2,11 +2,13 @@ import { registerRuntimeHelpers } from '@vue/compiler-core'
export const V_ON = Symbol(`vOn`)
export const V_FOR = Symbol(`vFor`)
export const EXTEND = Symbol(`extend`)
export const HYPHENATE = Symbol(`hyphenate`)
export const STRINGIFY_STYLE = Symbol(`stringifyStyle`)
registerRuntimeHelpers({
[V_ON]: 'vOn',
[V_FOR]: 'vFor',
[EXTEND]: 'extend',
[HYPHENATE]: 'hyphenate',
[STRINGIFY_STYLE]: 'stringifyStyle',
})
......@@ -223,6 +223,7 @@ export function createTransformContext(
cacheHandlers = false,
prefixIdentifiers = false,
skipTransformIdentifier = false,
renderDataSpread = false,
nodeTransforms = [],
directiveTransforms = {},
isBuiltInComponent = NOOP,
......@@ -285,6 +286,7 @@ export function createTransformContext(
directiveTransforms,
expressionPlugins,
skipTransformIdentifier,
renderDataSpread,
isBuiltInComponent,
isCustomElement,
onError,
......
import { extend, isSymbol, isObject, toRawType, def, hasChanged, isArray, isFunction, NOOP, remove, toHandlerKey, camelize, capitalize, isString, normalizeClass, normalizeStyle, isOn, isPromise, EMPTY_OBJ, isSet, isMap, isPlainObject, invokeArrayFns, hasOwn, NO, isIntegerKey, toNumber, hyphenate, isReservedProp, EMPTY_ARR, makeMap, toTypeString, stringifyStyle as stringifyStyle$1 } from '@vue/shared';
export { camelize, hyphenate, normalizeClass, normalizeProps, normalizeStyle, toDisplayString, toHandlerKey } from '@vue/shared';
export { camelize, extend, hyphenate, normalizeClass, normalizeProps, normalizeStyle, toDisplayString, toHandlerKey } from '@vue/shared';
// lifecycle
// App and Page
......
......@@ -7,6 +7,6 @@ export function createApp(rootComponent: unknown, rootProps = null) {
}
export const createSSRApp = createApp
export * from './helpers'
export { hyphenate } from '@vue/shared'
export { extend, hyphenate } from '@vue/shared'
// @ts-ignore
export * from '../lib/vue.runtime.esm.js'
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册