You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
274 lines
11 KiB
274 lines
11 KiB
"use strict"; |
|
Object.defineProperty(exports, "__esModule", { value: true }); |
|
exports.createVSlotCallExpression = exports.rewriteScopedSlotVForScope = exports.findCurrentPath = exports.findSlotName = exports.rewriteVSlot = exports.transformSlot = void 0; |
|
const types_1 = require("@babel/types"); |
|
const shared_1 = require("@vue/shared"); |
|
const compiler_core_1 = require("@vue/compiler-core"); |
|
const uni_shared_1 = require("@dcloudio/uni-shared"); |
|
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared"); |
|
const runtimeHelpers_1 = require("../runtimeHelpers"); |
|
const ast_1 = require("../ast"); |
|
const codegen_1 = require("../codegen"); |
|
const transform_1 = require("../transform"); |
|
const utils_1 = require("./utils"); |
|
const vFor_1 = require("./vFor"); |
|
const runtimeHelpers_2 = require("../runtimeHelpers"); |
|
const transformSlot = (node, context) => { |
|
if (!(0, uni_cli_shared_1.isUserComponent)(node, context)) { |
|
return; |
|
} |
|
const { tag, children } = node; |
|
const slots = new Set(); |
|
const onComponentSlot = (0, compiler_core_1.findDir)(node, 'slot', true); |
|
const implicitDefaultChildren = []; |
|
const isMiniProgramComponent = context.isMiniProgramComponent(tag); |
|
for (let i = 0; i < children.length; i++) { |
|
const slotElement = children[i]; |
|
let slotDir; |
|
if (!(0, compiler_core_1.isTemplateNode)(slotElement) || |
|
!(slotDir = (0, compiler_core_1.findDir)(slotElement, 'slot', true))) { |
|
// not a <template v-slot>, skip. |
|
if (slotElement.type !== 3 /* NodeTypes.COMMENT */) { |
|
implicitDefaultChildren.push(slotElement); |
|
} |
|
continue; |
|
} |
|
if (onComponentSlot) { |
|
// already has on-component slot - this is incorrect usage. |
|
context.onError((0, compiler_core_1.createCompilerError)(37 /* ErrorCodes.X_V_SLOT_MIXED_SLOT_USAGE */, slotDir.loc)); |
|
break; |
|
} |
|
if (!slotDir.arg) { |
|
// v-slot => v-slot:default |
|
slotDir.arg = (0, compiler_core_1.createSimpleExpression)('default', true); |
|
} |
|
const slotName = transformTemplateSlotElement(slotDir, slotElement, node, context); |
|
// 小程序组件默认插槽,直接移除<template #default>节点 |
|
if (isMiniProgramComponent) { |
|
if (slotName === 'default' && slotElement.children.length === 1) { |
|
children.splice(i, 1, slotElement.children[0]); |
|
} |
|
continue; |
|
} |
|
if (slotName) { |
|
slots.add(slotName); |
|
} |
|
} |
|
if (isMiniProgramComponent) { |
|
return; |
|
} |
|
if (implicitDefaultChildren.length) { |
|
slots.add(uni_shared_1.SLOT_DEFAULT_NAME); |
|
} |
|
if (onComponentSlot) { |
|
// <unicloud-db v-slot:default="{data, loading, error, options}"/> |
|
// => <unicloud-db collection=""><template v-slot:default="{data, loading, error, options}"/></unicloud-db> |
|
slots.add(uni_shared_1.SLOT_DEFAULT_NAME); |
|
const templateNode = createTemplateNode(onComponentSlot, implicitDefaultChildren); |
|
transformTemplateSlotElement(onComponentSlot, templateNode, node, context); |
|
node.children = [templateNode]; |
|
} |
|
// 不支持 $slots, 则自动补充 props |
|
if (slots.size && !context.miniProgram.slot.$slots) { |
|
const slotsArr = [...slots]; |
|
const hasDynamic = slotsArr.find((name) => !(0, shared_1.isString)(name)); |
|
let value; |
|
if (hasDynamic) { |
|
const children = []; |
|
const len = slotsArr.length - 1; |
|
slotsArr.forEach((name, index) => { |
|
if ((0, shared_1.isString)(name)) { |
|
children.push(`'${(0, uni_shared_1.dynamicSlotName)(name)}'`); |
|
} |
|
else { |
|
children.push(name); |
|
} |
|
if (index < len) { |
|
children.push(','); |
|
} |
|
}); |
|
value = (0, compiler_core_1.createCompoundExpression)([ |
|
context.helperString(runtimeHelpers_2.DYNAMIC_SLOT) + '([', |
|
...children, |
|
'])', |
|
]); |
|
} |
|
else { |
|
value = `[${slotsArr |
|
.map((name) => `'${(0, uni_shared_1.dynamicSlotName)(name)}'`) |
|
.join(',')}]`; |
|
} |
|
node.props.unshift((0, uni_cli_shared_1.createBindDirectiveNode)(utils_1.ATTR_VUE_SLOTS, value)); |
|
} |
|
}; |
|
exports.transformSlot = transformSlot; |
|
function rewriteVSlot(dir, context) { |
|
dir.arg = (0, utils_1.rewriteExpression)((0, compiler_core_1.createCompoundExpression)([ |
|
context.helperString(runtimeHelpers_2.DYNAMIC_SLOT) + '(', |
|
dir.arg, |
|
')', |
|
]), context); |
|
} |
|
exports.rewriteVSlot = rewriteVSlot; |
|
function transformTemplateSlotElement(slotDir, slotTemplate, slotComponent, context) { |
|
const slotName = findSlotName(slotDir); |
|
if (!slotName) { |
|
return; |
|
} |
|
const { exp } = slotDir; |
|
// non scoped slots |
|
if (!exp) { |
|
return slotName; |
|
} |
|
// empty |
|
if (exp.type === 4 /* NodeTypes.SIMPLE_EXPRESSION */ && !exp.content.trim()) { |
|
return slotName; |
|
} |
|
// 使用vFor来简单处理scoped slot作用域问题 |
|
slotTemplate.children = [ |
|
createVForTemplate(slotTemplate, { name: slotName, value: (0, codegen_1.genExpr)(exp), slotComponent }, context), |
|
]; |
|
if (context.miniProgram.slot.dynamicSlotNames) { |
|
// 已经在 vFor 中补充 slot,故需要移除 slotTemplate 中的 |
|
const index = slotTemplate.props.indexOf(slotDir); |
|
if (index > -1) { |
|
slotTemplate.props.splice(index, 1); |
|
} |
|
} |
|
// v-slot="slotProps" => v-slot 避免 transformIdentifier 生成 slotProps 的变量声明 |
|
slotDir.exp = undefined; |
|
return slotName; |
|
} |
|
function createTemplateNode(slotDir, children) { |
|
return { |
|
type: 1 /* NodeTypes.ELEMENT */, |
|
tag: 'template', |
|
tagType: 3 /* ElementTypes.TEMPLATE */, |
|
loc: compiler_core_1.locStub, |
|
isSelfClosing: false, |
|
codegenNode: undefined, |
|
ns: 0, |
|
props: [slotDir], |
|
children, |
|
}; |
|
} |
|
function findSlotName(slotDir) { |
|
if (!slotDir.arg) { |
|
return uni_shared_1.SLOT_DEFAULT_NAME; |
|
} |
|
if ((0, compiler_core_1.isStaticExp)(slotDir.arg)) { |
|
return slotDir.arg.content; |
|
} |
|
return slotDir.arg; |
|
} |
|
exports.findSlotName = findSlotName; |
|
function findCurrentVForValueAlias(context) { |
|
let scope = context.currentScope; |
|
while (scope) { |
|
if ((0, transform_1.isVForScope)(scope)) { |
|
return scope.valueAlias; |
|
} |
|
scope = scope.parent; |
|
} |
|
return ''; |
|
} |
|
function createVForTemplate(slotElement, { name, value, slotComponent, }, context) { |
|
const slotName = 's' + context.scopes.vFor; |
|
const keyProp = (0, uni_cli_shared_1.createBindDirectiveNode)('key', 'i' + context.scopes.vFor); |
|
const source = (0, shared_1.isString)(name) ? `'${name}'` : (0, codegen_1.genExpr)(name); |
|
const vForProp = { |
|
type: 7 /* NodeTypes.DIRECTIVE */, |
|
name: 'for', |
|
loc: compiler_core_1.locStub, |
|
modifiers: [], |
|
arg: undefined, |
|
exp: (0, compiler_core_1.createSimpleExpression)(`(${value}, ${slotName}) in ${utils_1.SCOPED_SLOT_IDENTIFIER}(${source}, ${findCurrentVForValueAlias(context) || `''`})`), |
|
}; |
|
const props = [vForProp, keyProp]; |
|
if (context.miniProgram.slot.dynamicSlotNames) { |
|
props.push((0, uni_cli_shared_1.createBindDirectiveNode)('slot', slotName)); |
|
} |
|
return { |
|
loc: slotElement.loc, |
|
ns: 0, |
|
tag: 'template', |
|
type: 1 /* NodeTypes.ELEMENT */, |
|
tagType: 3 /* ElementTypes.TEMPLATE */, |
|
props, |
|
isSelfClosing: false, |
|
codegenNode: undefined, |
|
children: slotElement.children, |
|
slotComponent, |
|
}; |
|
} |
|
const slotNameRE = /\('(.*)',/; |
|
/** |
|
* ('default','') => default |
|
* @param source |
|
* @returns |
|
*/ |
|
function findCurrentSlotName(source) { |
|
return (0, types_1.stringLiteral)((0, uni_shared_1.dynamicSlotName)(source.children[1].match(slotNameRE)[1])); |
|
} |
|
function createPathBinaryExpr(scope, computed = true) { |
|
return (0, types_1.binaryExpression)('+', (0, types_1.binaryExpression)('+', (0, types_1.stringLiteral)(parseVForPath(scope.sourceAlias) + (computed ? '[' : '.')), (0, types_1.identifier)(scope.indexAlias)), (0, types_1.stringLiteral)(computed ? '].' : '.')); |
|
} |
|
function findCurrentPath(id, scope) { |
|
let parent = scope.parent; |
|
let binaryExpr = null; |
|
while (parent) { |
|
if ((0, transform_1.isVForScope)(parent)) { |
|
// const computed = !isScopedSlotVFor(parent) |
|
if (!binaryExpr) { |
|
binaryExpr = createPathBinaryExpr(parent); |
|
} |
|
else { |
|
binaryExpr = (0, types_1.binaryExpression)('+', createPathBinaryExpr(parent), binaryExpr); |
|
} |
|
} |
|
parent = parent.parent; |
|
} |
|
return ((binaryExpr && (0, types_1.binaryExpression)('+', binaryExpr, (0, types_1.stringLiteral)(id))) || |
|
(0, types_1.stringLiteral)(id)); |
|
} |
|
exports.findCurrentPath = findCurrentPath; |
|
function findCurrentVueIdExpr(node, context) { |
|
if (!node) { |
|
return (0, types_1.stringLiteral)(''); |
|
} |
|
const vueIdProp = (0, compiler_core_1.findProp)(node, utils_1.ATTR_VUE_ID); |
|
if (vueIdProp.type === 6 /* NodeTypes.ATTRIBUTE */) { |
|
return (0, types_1.stringLiteral)(vueIdProp.value.content); |
|
} |
|
return (0, ast_1.parseExpr)((0, codegen_1.genExpr)(vueIdProp.exp), context) || (0, types_1.stringLiteral)(''); |
|
} |
|
/** |
|
* 目前无用 |
|
* @param vForScope |
|
* @param parentScope |
|
* @param context |
|
*/ |
|
function rewriteScopedSlotVForScope(vForScope, parentScope, context) { |
|
// 生成一个新的sourceAlias,用于scopedSlots |
|
const { source, sourceExpr } = vForScope; |
|
vForScope.sourceAlias = (0, utils_1.rewriteExpressionWithoutProperty)(source, context, sourceExpr, parentScope).content; |
|
} |
|
exports.rewriteScopedSlotVForScope = rewriteScopedSlotVForScope; |
|
function parseVForPath(id) { |
|
return id.includes('.') ? id.split('.')[1] : id; |
|
} |
|
function createVSlotCallExpression(slotComponent, vForScope, context) { |
|
const { source, sourceAlias } = vForScope; |
|
const id = parseVForPath(sourceAlias); |
|
return (0, types_1.callExpression)((0, types_1.identifier)(context.helperString(runtimeHelpers_1.WITH_SCOPED_SLOT)), [ |
|
(0, vFor_1.createVForArrowFunctionExpression)(vForScope), |
|
(0, types_1.objectExpression)([ |
|
// 插槽名称,数据更新 path,vueId |
|
(0, types_1.objectProperty)((0, types_1.identifier)('name'), findCurrentSlotName(source)), |
|
// 暂不生成 path |
|
(0, types_1.objectProperty)((0, types_1.identifier)('path'), findCurrentPath(id, vForScope)), |
|
(0, types_1.objectProperty)((0, types_1.identifier)('vueId'), findCurrentVueIdExpr(slotComponent, context)), |
|
]), |
|
]); |
|
} |
|
exports.createVSlotCallExpression = createVSlotCallExpression;
|
|
|