export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [
- { onBar: () => $event => (_ctx.handleBar($event)) }
- ], null, true)
+ const n0 = _createComponent(_component_Foo, { onBar: () => $event => (_ctx.handleBar($event)) }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [
- {
- id: () => ("foo"),
- class: () => ("bar")
- }
- ], null, true)
+ const n0 = _createComponent(_component_Foo, {
+ id: () => ("foo"),
+ class: () => ("bar")
+ }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [
+ const n0 = _createComponent(_component_Foo, { $: [
() => (_ctx.obj)
- ], null, true)
+ ] }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [
- { id: () => ("foo") },
- () => (_ctx.obj)
- ], null, true)
+ const n0 = _createComponent(_component_Foo, {
+ id: () => ("foo"),
+ $: [
+ () => (_ctx.obj)
+ ]
+ }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [
+ const n0 = _createComponent(_component_Foo, { $: [
() => (_ctx.obj),
{ id: () => ("foo") }
- ], null, true)
+ ] }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [
- { id: () => ("foo") },
- () => (_ctx.obj),
- { class: () => ("bar") }
- ], null, true)
+ const n0 = _createComponent(_component_Foo, {
+ id: () => ("foo"),
+ $: [
+ () => (_ctx.obj),
+ { class: () => ("bar") }
+ ]
+ }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [
+ const n0 = _createComponent(_component_Foo, { $: [
() => (_toHandlers(_ctx.obj))
- ], null, true)
+ ] }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [
+ const n0 = _createComponent(_component_Foo, { $: [
() => ({ [_toHandlerKey(_ctx.foo-_ctx.bar)]: () => _ctx.bar }),
() => ({ [_toHandlerKey(_ctx.baz)]: () => _ctx.qux })
- ], null, true)
+ ] }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [
+ const n0 = _createComponent(_component_Foo, { $: [
() => ({ [_ctx.foo-_ctx.bar]: _ctx.bar }),
() => ({ [_ctx.baz]: _ctx.qux })
- ], null, true)
+ ] }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_custom_input = _resolveComponent("custom-input")
- const n0 = _createComponent(_component_custom_input, [
- { is: () => ("foo") }
- ], null, true)
+ const n0 = _createComponent(_component_custom_input, { is: () => ("foo") }, null, true)
return n0
}"
`;
const t0 = _template("<div></div>")
export function render(_ctx) {
- const n0 = _createSlot("default", [
- { foo: () => (_ctx.bar) }
- ], () => {
+ const n0 = _createSlot("default", { foo: () => (_ctx.bar) }, () => {
const n2 = t0()
return n2
})
"import { createSlot as _createSlot } from 'vue/vapor';
export function render(_ctx) {
- const n0 = _createSlot("default", [
- {
- foo: () => ("bar"),
- baz: () => (_ctx.qux),
- fooBar: () => (_ctx.foo-_ctx.bar)
- }
- ])
+ const n0 = _createSlot("default", {
+ foo: () => ("bar"),
+ baz: () => (_ctx.qux),
+ fooBar: () => (_ctx.foo-_ctx.bar)
+ })
return n0
}"
`;
const t0 = _template("<div></div>")
export function render(_ctx) {
- const n0 = _createSlot("foo", [
- { foo: () => (_ctx.bar) }
- ], () => {
+ const n0 = _createSlot("foo", { foo: () => (_ctx.bar) }, () => {
const n2 = t0()
return n2
})
"import { createSlot as _createSlot } from 'vue/vapor';
export function render(_ctx) {
- const n0 = _createSlot("foo", [
- {
- foo: () => ("bar"),
- baz: () => (_ctx.qux)
- }
- ])
+ const n0 = _createSlot("foo", {
+ foo: () => ("bar"),
+ baz: () => (_ctx.qux)
+ })
return n0
}"
`;
"import { createSlot as _createSlot } from 'vue/vapor';
export function render(_ctx) {
- const n0 = _createSlot("foo", [
- { foo: () => ("bar") },
- () => (_ctx.obj),
- { baz: () => (_ctx.qux) }
- ])
+ const n0 = _createSlot("foo", {
+ foo: () => ("bar"),
+ $: [
+ () => (_ctx.obj),
+ { baz: () => (_ctx.qux) }
+ ]
+ })
return n0
}"
`;
"import { createSlot as _createSlot, toHandlers as _toHandlers } from 'vue/vapor';
export function render(_ctx) {
- const n0 = _createSlot("default", [
- { onClick: () => _ctx.foo },
- () => (_toHandlers(_ctx.bar)),
- { baz: () => (_ctx.qux) }
- ])
+ const n0 = _createSlot("default", {
+ onClick: () => _ctx.foo,
+ $: [
+ () => (_toHandlers(_ctx.bar)),
+ { baz: () => (_ctx.qux) }
+ ]
+ })
return n0
}"
`;
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponent(_component_Comp, [
- { depth: () => (0) }
- ], null, true)
+ const n0 = _createComponent(_component_Comp, { depth: () => (0) }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponent(_component_Comp, [
- { modelValue: () => (_ctx.foo),
- "onUpdate:modelValue": () => $event => (_ctx.foo = $event),
- modelModifiers: () => ({ trim: true, "bar-baz": true }) }
- ], null, true)
+ const n0 = _createComponent(_component_Comp, { modelValue: () => (_ctx.foo),
+ "onUpdate:modelValue": () => $event => (_ctx.foo = $event),
+ modelModifiers: () => ({ trim: true, "bar-baz": true }) }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponent(_component_Comp, [
- { modelValue: () => (_ctx.foo),
- "onUpdate:modelValue": () => $event => (_ctx.foo = $event) }
- ], null, true)
+ const n0 = _createComponent(_component_Comp, { modelValue: () => (_ctx.foo),
+ "onUpdate:modelValue": () => $event => (_ctx.foo = $event) }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponent(_component_Comp, [
- {
- foo: () => (_ctx.foo),
- "onUpdate:foo": () => $event => (_ctx.foo = $event),
- fooModifiers: () => ({ trim: true }),
- bar: () => (_ctx.bar),
- "onUpdate:bar": () => $event => (_ctx.bar = $event),
- barModifiers: () => ({ number: true })
- }
- ], null, true)
+ const n0 = _createComponent(_component_Comp, {
+ foo: () => (_ctx.foo),
+ "onUpdate:foo": () => $event => (_ctx.foo = $event),
+ fooModifiers: () => ({ trim: true }),
+ bar: () => (_ctx.bar),
+ "onUpdate:bar": () => $event => (_ctx.bar = $event),
+ barModifiers: () => ({ number: true })
+ }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponent(_component_Comp, [
- { bar: () => (_ctx.foo),
- "onUpdate:bar": () => $event => (_ctx.foo = $event) }
- ], null, true)
+ const n0 = _createComponent(_component_Comp, { bar: () => (_ctx.foo),
+ "onUpdate:bar": () => $event => (_ctx.foo = $event) }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponent(_component_Comp, [
+ const n0 = _createComponent(_component_Comp, { $: [
() => ({ [_ctx.foo]: _ctx.foo,
["onUpdate:" + _ctx.foo]: () => $event => (_ctx.foo = $event),
[_ctx.foo + "Modifiers"]: () => ({ trim: true }) }),
() => ({ [_ctx.bar]: _ctx.bar,
["onUpdate:" + _ctx.bar]: () => $event => (_ctx.bar = $event),
[_ctx.bar + "Modifiers"]: () => ({ number: true }) })
- ], null, true)
+ ] }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponent(_component_Comp, [
+ const n0 = _createComponent(_component_Comp, { $: [
() => ({ [_ctx.arg]: _ctx.foo,
["onUpdate:" + _ctx.arg]: () => $event => (_ctx.foo = $event) })
- ], null, true)
+ ] }, null, true)
return n0
}"
`;
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
const n1 = t0()
- const n0 = _createComponent(_component_Comp, [
- { id: () => (_ctx.foo) }
- ], null, null, true)
+ const n0 = _createComponent(_component_Comp, { id: () => (_ctx.foo) }, null, null, true)
_insert(n0, n1)
return n1
}"
)
expect(code).toMatchSnapshot()
- expect(code).contains(`[
- {
- id: () => ("foo"),
- class: () => ("bar")
- }
- ]`)
+ expect(code).contains(`{
+ id: () => ("foo"),
+ class: () => ("bar")
+ }`)
expect(ir.block.operation).toMatchObject([
{
`<Foo id="foo" v-bind="obj" />`,
)
expect(code).toMatchSnapshot()
- expect(code).contains(`[
- { id: () => ("foo") },
- () => (_ctx.obj)
- ]`)
+ expect(code).contains(`{
+ id: () => ("foo"),
+ $: [
+ () => (_ctx.obj)
+ ]
+ }`)
expect(ir.block.operation).toMatchObject([
{
type: IRNodeTypes.CREATE_COMPONENT_NODE,
`<Foo id="foo" v-bind="obj" class="bar" />`,
)
expect(code).toMatchSnapshot()
- expect(code).contains(`[
- { id: () => ("foo") },
- () => (_ctx.obj),
- { class: () => ("bar") }
- ]`)
+ expect(code).contains(`{
+ id: () => ("foo"),
+ $: [
+ () => (_ctx.obj),
+ { class: () => ("bar") }
+ ]
+ }`)
expect(ir.block.operation).toMatchObject([
{
type: IRNodeTypes.CREATE_COMPONENT_NODE,
test('v-model for component should work', () => {
const { code, ir } = compileWithVModel('<Comp v-model="foo" />')
expect(code).toMatchSnapshot()
+ expect(code).contains(`modelValue: () => (_ctx.foo),`)
expect(code).contains(
- `modelValue: () => (_ctx.foo),
- "onUpdate:modelValue": () => $event => (_ctx.foo = $event)`,
+ `"onUpdate:modelValue": () => $event => (_ctx.foo = $event)`,
)
expect(ir.block.operation).toMatchObject([
{
test('v-model with arguments for component should work', () => {
const { code, ir } = compileWithVModel('<Comp v-model:bar="foo" />')
expect(code).toMatchSnapshot()
+ expect(code).contains(`bar: () => (_ctx.foo),`)
expect(code).contains(
- `bar: () => (_ctx.foo),
- "onUpdate:bar": () => $event => (_ctx.foo = $event)`,
+ `"onUpdate:bar": () => $event => (_ctx.foo = $event)`,
)
expect(ir.block.operation).toMatchObject([
{
import { genBlock } from './block'
export function genCreateComponent(
- oper: CreateComponentIRNode,
+ operation: CreateComponentIRNode,
context: CodegenContext,
): CodeFragment[] {
const { vaporHelper } = context
const tag = genTag()
- const { root, props, slots, once } = oper
+ const { root, props, slots, once } = operation
const rawProps = genRawProps(props, context)
const rawSlots = genRawSlots(slots, context)
return [
NEWLINE,
- `const n${oper.id} = `,
+ `const n${operation.id} = `,
...genCall(
vaporHelper('createComponent'),
tag,
root ? 'true' : false,
once && 'true',
),
- ...genDirectivesForElement(oper.id, context),
+ ...genDirectivesForElement(operation.id, context),
]
function genTag() {
- if (oper.dynamic) {
+ if (operation.dynamic) {
return genCall(
vaporHelper('resolveDynamicComponent'),
- genExpression(oper.dynamic, context),
+ genExpression(operation.dynamic, context),
)
- } else if (oper.asset) {
- return toValidAssetId(oper.tag, 'component')
+ } else if (operation.asset) {
+ return toValidAssetId(operation.tag, 'component')
} else {
return genExpression(
- extend(createSimpleExpression(oper.tag, false), { ast: null }),
+ extend(createSimpleExpression(operation.tag, false), { ast: null }),
context,
)
}
props: IRProps[],
context: CodegenContext,
): CodeFragment[] | undefined {
- const { vaporHelper } = context
- const frag = props
- .map(props => {
- if (isArray(props)) {
- if (!props.length) return
- return genStaticProps(props, context)
- } else {
- let expr: CodeFragment[]
- if (props.kind === IRDynamicPropsKind.ATTRIBUTE)
- expr = genMulti(DELIMITERS_OBJECT, genProp(props, context))
- else {
- expr = genExpression(props.value, context)
- if (props.handler) expr = genCall(vaporHelper('toHandlers'), expr)
- }
- return ['() => (', ...expr, ')']
- }
- })
- .filter(
- Boolean as any as (v: CodeFragment[] | undefined) => v is CodeFragment[],
+ const staticProps = props[0]
+ if (isArray(staticProps)) {
+ if (!staticProps.length && props.length === 1) {
+ return
+ }
+ return genStaticProps(
+ staticProps,
+ context,
+ genDynamicProps(props.slice(1), context),
)
- if (frag.length) {
- return genMulti(DELIMITERS_ARRAY_NEWLINE, ...frag)
+ } else if (props.length) {
+ // all dynamic
+ return genStaticProps([], context, genDynamicProps(props, context))
}
}
function genStaticProps(
props: IRPropsStatic,
context: CodegenContext,
+ dynamicProps?: CodeFragment[],
): CodeFragment[] {
+ const args = props.map(prop => genProp(prop, context, true))
+ if (dynamicProps) {
+ args.push([`$: `, ...dynamicProps])
+ }
return genMulti(
- props.length > 1 ? DELIMITERS_OBJECT_NEWLINE : DELIMITERS_OBJECT,
- ...props.map(prop => genProp(prop, context, true)),
+ args.length > 1 ? DELIMITERS_OBJECT_NEWLINE : DELIMITERS_OBJECT,
+ ...args,
)
}
+function genDynamicProps(
+ props: IRProps[],
+ context: CodegenContext,
+): CodeFragment[] | undefined {
+ const { vaporHelper } = context
+ const frags: CodeFragment[][] = []
+ for (const p of props) {
+ let expr: CodeFragment[]
+ if (isArray(p)) {
+ if (p.length) {
+ frags.push(genStaticProps(p, context))
+ }
+ continue
+ } else {
+ if (p.kind === IRDynamicPropsKind.ATTRIBUTE)
+ expr = genMulti(DELIMITERS_OBJECT, genProp(p, context))
+ else {
+ expr = genExpression(p.value, context)
+ if (p.handler) expr = genCall(vaporHelper('toHandlers'), expr)
+ }
+ }
+ frags.push(['() => (', ...expr, ')'])
+ }
+ if (frags.length) {
+ return genMulti(DELIMITERS_ARRAY_NEWLINE, ...frags)
+ }
+}
+
function genProp(prop: IRProp, context: CodegenContext, isStatic?: boolean) {
const values = genPropValue(prop.values, context)
return [
// check if we are the single root of the parent
// if yes, inject parent attrs as dynamic props source
if (isSingleRoot && currentInstance && currentInstance.hasFallthrough) {
+ const attrs = currentInstance.attrs
if (rawProps) {
- ;(rawProps.$ || (rawProps.$ = [])).push(currentInstance.attrs)
+ ;(rawProps.$ || (rawProps.$ = [])).push(() => attrs)
} else {
- rawProps = { $: [currentInstance.attrs] }
+ rawProps = { $: [() => attrs] } as RawProps
}
}
} from '@vue/runtime-dom'
import { normalizeEmitsOptions } from './componentEmits'
-export interface RawProps {
- [key: string]: PropSource
+export type RawProps = Record<string, () => unknown> & {
$?: DynamicPropsSource[]
}
-type PropSource<T = any> = T | (() => T)
-
-type DynamicPropsSource = PropSource<Record<string, any>>
+type DynamicPropsSource =
+ | (() => Record<string, unknown>)
+ | Record<string, () => unknown>
export function initStaticProps(
comp: VaporComponent,
const needCast = needCastKeys && needCastKeys.includes(normalizedKey)
const source = rawProps[key]
if (propsOptions && normalizedKey in propsOptions) {
- if (isFunction(source)) {
- Object.defineProperty(props, normalizedKey, {
- enumerable: true,
- get: needCast
- ? () =>
- resolvePropValue(
- propsOptions,
- normalizedKey,
- source(),
- instance,
- resolveDefault,
- )
- : source,
- })
- } else {
- props[normalizedKey] = needCast
- ? resolvePropValue(
- propsOptions,
- normalizedKey,
- source,
- instance,
- resolveDefault,
- )
- : source
- }
+ Object.defineProperty(props, normalizedKey, {
+ enumerable: true,
+ get: needCast
+ ? () =>
+ resolvePropValue(
+ propsOptions,
+ normalizedKey,
+ source(),
+ instance,
+ resolveDefault,
+ )
+ : source,
+ })
} else if (!isEmitListener(emitsOptions, key)) {
- if (isFunction(source)) {
- Object.defineProperty(attrs, key, {
- enumerable: true,
- get: source,
- })
- } else {
- attrs[normalizedKey] = source
- }
+ Object.defineProperty(attrs, key, {
+ enumerable: true,
+ get: source,
+ })
hasAttrs = true
}
}
}
// TODO optimization: maybe convert functions into computeds
-export function resolveSource(source: PropSource): Record<string, any> {
+export function resolveSource(
+ source: Record<string, any> | (() => Record<string, any>),
+): Record<string, any> {
return isFunction(source) ? source() : source
}
: passThrough
if (key in target) {
- return castProp(resolveSource(target[key as string]))
+ return castProp(target[key as string]())
}
- if (target.$) {
- let i = target.$.length
- let source
+ const dynamicSources = target.$
+ if (dynamicSources) {
+ let i = dynamicSources.length
+ let source, isDynamic
while (i--) {
- source = resolveSource(target.$[i])
+ source = dynamicSources[i]
+ isDynamic = isFunction(source)
+ source = isDynamic ? (source as Function)() : source
if (hasOwn(source, key)) {
- return castProp(source[key])
+ return castProp(isDynamic ? source[key] : source[key]())
}
}
}
: null
const hasAttr = (target: RawProps, key: string) => {
- if (key === '$' || isProp(key) || isEmitListener(emitsOptions, key))
+ if (key === '$' || isProp(key) || isEmitListener(emitsOptions, key)) {
return false
- if (target.$) {
- let i = target.$.length
+ }
+ const dynamicSources = target.$
+ if (dynamicSources) {
+ let i = dynamicSources.length
while (i--) {
- if (hasOwn(resolveSource(target.$[i]), key)) {
+ if (hasOwn(resolveSource(dynamicSources[i]), key)) {
return true
}
}
},
ownKeys(target) {
const keys = Object.keys(target)
- if (target.$) {
- let i = target.$.length
+ const dynamicSources = target.$
+ if (dynamicSources) {
+ let i = dynamicSources.length
while (i--) {
- keys.push(...Object.keys(resolveSource(target.$[i])))
+ keys.push(...Object.keys(resolveSource(dynamicSources[i])))
}
}
return keys.filter(key => hasAttr(target, key))