wip: support resolving directives from setup scope variables by naming convention
v-my-dir can be resovled from setup scope variable named "vMyDir".
This commit is contained in:
parent
2f32e4a077
commit
ae2caad740
@ -29,8 +29,7 @@ import {
|
|||||||
isObject,
|
isObject,
|
||||||
isReservedProp,
|
isReservedProp,
|
||||||
capitalize,
|
capitalize,
|
||||||
camelize,
|
camelize
|
||||||
EMPTY_OBJ
|
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import { createCompilerError, ErrorCodes } from '../errors'
|
import { createCompilerError, ErrorCodes } from '../errors'
|
||||||
import {
|
import {
|
||||||
@ -255,34 +254,16 @@ export function resolveComponentType(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3. user component (from setup bindings)
|
// 3. user component (from setup bindings)
|
||||||
const bindings = context.bindingMetadata
|
// this is skipped in browser build since browser builds do not perform
|
||||||
if (bindings !== EMPTY_OBJ) {
|
// binding analysis.
|
||||||
const checkType = (type: BindingTypes) => {
|
if (!__BROWSER__) {
|
||||||
let resolvedTag = tag
|
const fromSetup = resolveSetupReference(
|
||||||
if (
|
tag,
|
||||||
bindings[resolvedTag] === type ||
|
capitalize(camelize(tag)),
|
||||||
bindings[(resolvedTag = camelize(tag))] === type ||
|
context
|
||||||
bindings[(resolvedTag = capitalize(camelize(tag)))] === type
|
)
|
||||||
) {
|
if (fromSetup) {
|
||||||
return resolvedTag
|
return fromSetup
|
||||||
}
|
|
||||||
}
|
|
||||||
const tagFromConst = checkType(BindingTypes.SETUP_CONST)
|
|
||||||
if (tagFromConst) {
|
|
||||||
return context.inline
|
|
||||||
? // in inline mode, const setup bindings (e.g. imports) can be used as-is
|
|
||||||
tagFromConst
|
|
||||||
: `$setup[${JSON.stringify(tagFromConst)}]`
|
|
||||||
}
|
|
||||||
const tagFromSetup =
|
|
||||||
checkType(BindingTypes.SETUP_LET) ||
|
|
||||||
checkType(BindingTypes.SETUP_REF) ||
|
|
||||||
checkType(BindingTypes.SETUP_MAYBE_REF)
|
|
||||||
if (tagFromSetup) {
|
|
||||||
return context.inline
|
|
||||||
? // setup scope bindings that may be refs need to be unrefed
|
|
||||||
`${context.helperString(UNREF)}(${tagFromSetup})`
|
|
||||||
: `$setup[${JSON.stringify(tagFromSetup)}]`
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,6 +273,45 @@ export function resolveComponentType(
|
|||||||
return toValidAssetId(tag, `component`)
|
return toValidAssetId(tag, `component`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveSetupReference(
|
||||||
|
name: string,
|
||||||
|
interopName: string,
|
||||||
|
context: TransformContext
|
||||||
|
) {
|
||||||
|
const bindings = context.bindingMetadata
|
||||||
|
if (!bindings) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkType = (type: BindingTypes) => {
|
||||||
|
if (bindings[name] === type) {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
if (bindings[interopName] === type) {
|
||||||
|
return interopName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fromConst = checkType(BindingTypes.SETUP_CONST)
|
||||||
|
if (fromConst) {
|
||||||
|
return context.inline
|
||||||
|
? // in inline mode, const setup bindings (e.g. imports) can be used as-is
|
||||||
|
fromConst
|
||||||
|
: `$setup[${JSON.stringify(fromConst)}]`
|
||||||
|
}
|
||||||
|
|
||||||
|
const fromMaybeRef =
|
||||||
|
checkType(BindingTypes.SETUP_LET) ||
|
||||||
|
checkType(BindingTypes.SETUP_REF) ||
|
||||||
|
checkType(BindingTypes.SETUP_MAYBE_REF)
|
||||||
|
if (fromMaybeRef) {
|
||||||
|
return context.inline
|
||||||
|
? // setup scope bindings that may be refs need to be unrefed
|
||||||
|
`${context.helperString(UNREF)}(${fromMaybeRef})`
|
||||||
|
: `$setup[${JSON.stringify(fromMaybeRef)}]`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type PropsExpression = ObjectExpression | CallExpression | ExpressionNode
|
export type PropsExpression = ObjectExpression | CallExpression | ExpressionNode
|
||||||
|
|
||||||
export function buildProps(
|
export function buildProps(
|
||||||
@ -590,12 +610,28 @@ function buildDirectiveArgs(
|
|||||||
const dirArgs: ArrayExpression['elements'] = []
|
const dirArgs: ArrayExpression['elements'] = []
|
||||||
const runtime = directiveImportMap.get(dir)
|
const runtime = directiveImportMap.get(dir)
|
||||||
if (runtime) {
|
if (runtime) {
|
||||||
|
// built-in directive with runtime
|
||||||
dirArgs.push(context.helperString(runtime))
|
dirArgs.push(context.helperString(runtime))
|
||||||
} else {
|
} else {
|
||||||
// inject statement for resolving directive
|
// user directive.
|
||||||
context.helper(RESOLVE_DIRECTIVE)
|
// see if we have directives exposed via <script setup>
|
||||||
context.directives.add(dir.name)
|
const fromSetup =
|
||||||
dirArgs.push(toValidAssetId(dir.name, `directive`))
|
!__BROWSER__ &&
|
||||||
|
resolveSetupReference(
|
||||||
|
dir.name,
|
||||||
|
// v-my-dir -> vMyDir
|
||||||
|
'v' + capitalize(camelize(dir.name)),
|
||||||
|
context
|
||||||
|
)
|
||||||
|
|
||||||
|
if (fromSetup) {
|
||||||
|
dirArgs.push(fromSetup)
|
||||||
|
} else {
|
||||||
|
// inject statement for resolving directive
|
||||||
|
context.helper(RESOLVE_DIRECTIVE)
|
||||||
|
context.directives.add(dir.name)
|
||||||
|
dirArgs.push(toValidAssetId(dir.name, `directive`))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const { loc } = dir
|
const { loc } = dir
|
||||||
if (dir.exp) dirArgs.push(dir.exp)
|
if (dir.exp) dirArgs.push(dir.exp)
|
||||||
|
@ -177,6 +177,32 @@ return (_ctx, _cache) => {
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`SFC compile <script setup> inlineTemplate mode referencing scope components and directives 1`] = `
|
||||||
|
"import { unref as _unref, createVNode as _createVNode, withDirectives as _withDirectives, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock } from \\"vue\\"
|
||||||
|
|
||||||
|
import ChildComp from './Child.vue'
|
||||||
|
import SomeOtherComp from './Other.vue'
|
||||||
|
import vMyDir from './my-dir'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
expose: [],
|
||||||
|
setup(__props) {
|
||||||
|
|
||||||
|
|
||||||
|
return (_ctx, _cache) => {
|
||||||
|
return (_openBlock(), _createBlock(_Fragment, null, [
|
||||||
|
_withDirectives(_createVNode(\\"div\\", null, null, 512 /* NEED_PATCH */), [
|
||||||
|
[_unref(vMyDir)]
|
||||||
|
]),
|
||||||
|
_createVNode(ChildComp),
|
||||||
|
_createVNode(SomeOtherComp)
|
||||||
|
], 64 /* STABLE_FRAGMENT */))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> inlineTemplate mode should work 1`] = `
|
exports[`SFC compile <script setup> inlineTemplate mode should work 1`] = `
|
||||||
"import { toDisplayString as _toDisplayString, createVNode as _createVNode, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock } from \\"vue\\"
|
"import { toDisplayString as _toDisplayString, createVNode as _createVNode, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock } from \\"vue\\"
|
||||||
|
|
||||||
|
@ -147,6 +147,29 @@ const bar = 1
|
|||||||
assertCode(content)
|
assertCode(content)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('referencing scope components and directives', () => {
|
||||||
|
const { content } = compile(
|
||||||
|
`
|
||||||
|
<script setup>
|
||||||
|
import ChildComp from './Child.vue'
|
||||||
|
import SomeOtherComp from './Other.vue'
|
||||||
|
import vMyDir from './my-dir'
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div v-my-dir></div>
|
||||||
|
<ChildComp/>
|
||||||
|
<some-other-comp/>
|
||||||
|
</template>
|
||||||
|
`,
|
||||||
|
{ inlineTemplate: true }
|
||||||
|
)
|
||||||
|
expect(content).toMatch('[_unref(vMyDir)]')
|
||||||
|
expect(content).toMatch('_createVNode(ChildComp)')
|
||||||
|
// kebab-case component support
|
||||||
|
expect(content).toMatch('_createVNode(SomeOtherComp)')
|
||||||
|
assertCode(content)
|
||||||
|
})
|
||||||
|
|
||||||
test('avoid unref() when necessary', () => {
|
test('avoid unref() when necessary', () => {
|
||||||
// function, const, component import
|
// function, const, component import
|
||||||
const { content } = compile(
|
const { content } = compile(
|
||||||
|
@ -19,7 +19,8 @@ export const compilerOptions: CompilerOptions = reactive({
|
|||||||
setupConst: BindingTypes.SETUP_CONST,
|
setupConst: BindingTypes.SETUP_CONST,
|
||||||
setupLet: BindingTypes.SETUP_LET,
|
setupLet: BindingTypes.SETUP_LET,
|
||||||
setupMaybeRef: BindingTypes.SETUP_MAYBE_REF,
|
setupMaybeRef: BindingTypes.SETUP_MAYBE_REF,
|
||||||
setupProp: BindingTypes.PROPS
|
setupProp: BindingTypes.PROPS,
|
||||||
|
vMySetupDir: BindingTypes.SETUP_CONST
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user