2025/2/8第一次更新

This commit is contained in:
爱吃咸鱼小猫咪
2025-02-08 18:50:38 +08:00
commit d7af560866
26519 changed files with 5046029 additions and 0 deletions
@@ -0,0 +1,2 @@
import type { NodeTransform } from '../transform';
export declare const transformAttr: NodeTransform;
@@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformAttr = void 0;
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const shared_1 = require("@vue/shared");
const transformAttr = (node, _) => {
if (!(0, uni_cli_shared_1.isElementNode)(node)) {
return;
}
node.props.forEach((prop) => {
if ((0, uni_cli_shared_1.isAttributeNode)(prop) && prop.value) {
switch (prop.name) {
case 'style':
prop.value.content = (0, shared_1.stringifyStyle)((0, shared_1.parseStringStyle)(prop.value.content)).slice(0, -1); // 移除最后一个分号,省点大小吧
break;
}
}
});
};
exports.transformAttr = transformAttr;
@@ -0,0 +1,6 @@
import { type AttributeNode, type DirectiveNode } from '@vue/compiler-core';
import type { TransformContext } from '../transform';
export declare function isClassBinding({ arg }: DirectiveNode): boolean | undefined;
export declare function findStaticClassIndex(props: (AttributeNode | DirectiveNode)[]): number;
export declare function rewriteClass(index: number, classBindingProp: DirectiveNode, props: (AttributeNode | DirectiveNode)[], virtualHost: boolean, context: TransformContext): void;
export declare function createVirtualHostClass(props: (AttributeNode | DirectiveNode)[], context: TransformContext): DirectiveNode;
@@ -0,0 +1,181 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createVirtualHostClass = exports.rewriteClass = exports.findStaticClassIndex = exports.isClassBinding = void 0;
const types_1 = require("@babel/types");
const compiler_core_1 = require("@vue/compiler-core");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const ast_1 = require("../ast");
const codegen_1 = require("../codegen");
const runtimeHelpers_1 = require("../runtimeHelpers");
const utils_1 = require("./utils");
function isClassBinding({ arg }) {
return (arg && arg.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION && arg.content === 'class');
}
exports.isClassBinding = isClassBinding;
function findStaticClassIndex(props) {
return props.findIndex((prop) => prop.name === 'class');
}
exports.findStaticClassIndex = findStaticClassIndex;
function rewriteClass(index, classBindingProp, props, virtualHost, context) {
const expr = classBindingProp.exp
? (0, ast_1.parseExpr)(classBindingProp.exp, context)
: undefined;
let classBindingExpr;
if (expr) {
classBindingExpr = expr;
if ((0, types_1.isObjectExpression)(expr)) {
classBindingExpr = createClassBindingByObjectExpression(rewriteClassObjectExpression(expr, classBindingProp.loc, context));
}
else if ((0, types_1.isArrayExpression)(expr)) {
classBindingExpr = createClassBindingByArrayExpression(rewriteClassArrayExpression(expr, context));
}
else {
classBindingExpr = (0, ast_1.parseExpr)(rewriteClassExpression(classBindingProp.exp, context).content, context);
}
}
else if (virtualHost) {
classBindingExpr = (0, types_1.arrayExpression)([]);
}
else {
return;
}
const staticClassPropIndex = findStaticClassIndex(props);
if (staticClassPropIndex > -1) {
const staticClass = props[staticClassPropIndex].value
.content;
if (staticClass) {
if (!(0, types_1.isArrayExpression)(classBindingExpr)) {
classBindingExpr = (0, types_1.arrayExpression)([classBindingExpr]);
}
const staticClassLiterals = parseStaticClass(staticClass);
if (index > staticClassPropIndex) {
classBindingExpr.elements.unshift(...staticClassLiterals);
}
else {
classBindingExpr.elements.push(...staticClassLiterals);
}
}
}
if (virtualHost) {
if (!(0, types_1.isArrayExpression)(classBindingExpr)) {
classBindingExpr = (0, types_1.arrayExpression)([classBindingExpr]);
}
classBindingExpr.elements.push((0, types_1.identifier)(utils_1.VIRTUAL_HOST_CLASS));
}
if (!context.miniProgram.class.array) {
classBindingExpr = parseClassBindingArrayExpr(classBindingExpr);
}
classBindingProp.exp = (0, compiler_core_1.createSimpleExpression)((0, codegen_1.genBabelExpr)(classBindingExpr));
}
exports.rewriteClass = rewriteClass;
function createVirtualHostClass(props, context) {
const classBindingProp = (0, uni_cli_shared_1.createBindDirectiveNode)('class', '');
delete classBindingProp.exp;
rewriteClass(0, classBindingProp, props, true, context);
return classBindingProp;
}
exports.createVirtualHostClass = createVirtualHostClass;
/**
* 目前 mp-toutiao, mp-alipay, mp-lark 不支持数组绑定class,故统一转换为字符串相加
* @param classBindingExpr
* @returns
*/
function parseClassBindingArrayExpr(classBindingExpr) {
if (!(0, types_1.isArrayExpression)(classBindingExpr)) {
return classBindingExpr;
}
let binaryExpr;
classBindingExpr.elements.forEach((expr) => {
if ((0, types_1.isArrayExpression)(expr)) {
expr = parseClassBindingArrayExpr(expr);
}
if (!binaryExpr) {
binaryExpr = (0, types_1.parenthesizedExpression)(expr);
}
else {
binaryExpr = (0, types_1.binaryExpression)('+', (0, types_1.binaryExpression)('+', binaryExpr, (0, types_1.stringLiteral)(' ')), expr);
}
});
return binaryExpr;
}
function parseStaticClass(staticClass) {
// 已经在 parse 阶段格式化了多余空格等
return staticClass.split(' ').map((clazz) => (0, types_1.stringLiteral)(clazz));
}
function rewriteClassExpression(expr, context) {
return (0, utils_1.rewriteExpression)((0, compiler_core_1.createCompoundExpression)([
context.helperString(runtimeHelpers_1.NORMALIZE_CLASS) + '(',
expr,
')',
]), context);
}
function rewriteClassArrayExpression(expr, context) {
expr.elements.forEach((prop, index) => {
if (!(0, types_1.isStringLiteral)(prop)) {
const code = (0, codegen_1.genBabelExpr)((0, types_1.arrayExpression)([(0, types_1.isSpreadElement)(prop) ? prop.argument : prop]));
expr.elements[index] = (0, types_1.identifier)(rewriteClassExpression((0, compiler_core_1.createSimpleExpression)(code.slice(1, -1), false), context).content);
}
});
return expr;
}
function rewriteClassObjectExpression(expr, loc, context) {
expr.properties.forEach((prop, index) => {
if ((0, types_1.isSpreadElement)(prop)) {
// <view :class="{...obj}"/>
// <view class="{{[a]}}"/>
const newExpr = (0, utils_1.rewriteSpreadElement)(runtimeHelpers_1.NORMALIZE_CLASS, prop, loc, context);
if (newExpr) {
expr.properties[index] = (0, types_1.objectProperty)(newExpr, (0, types_1.booleanLiteral)(true), true);
}
}
else if ((0, types_1.isObjectProperty)(prop)) {
const { key, value, computed } = prop;
if (computed) {
// {[handle(computedKey)]:1} => {[a]:1}
prop.key = (0, utils_1.parseExprWithRewrite)((0, codegen_1.genBabelExpr)(key), loc, context, key);
}
if ((0, utils_1.isStaticLiteral)(value)) {
return;
}
else {
const newExpr = (0, utils_1.parseExprWithRewriteClass)((0, codegen_1.genBabelExpr)(value), loc, context, value);
if (newExpr) {
prop.value = newExpr;
}
}
}
});
return expr;
}
function createClassBindingByArrayExpression(expr) {
const elements = [];
expr.elements.forEach((prop) => {
if ((0, types_1.isStringLiteral)(prop) || (0, types_1.isIdentifier)(prop)) {
elements.push(prop);
}
});
return (0, types_1.arrayExpression)(elements);
}
function createClassBindingByObjectExpression(expr) {
const elements = [];
expr.properties.forEach((prop) => {
if ((0, types_1.isObjectProperty)(prop)) {
const { value } = prop;
if ((0, ast_1.isUndefined)(value) || (0, types_1.isPrivateName)(prop.key)) {
// remove {a:undefined}
return;
}
if ((0, types_1.isLiteral)(value)) {
// {a:true,b:1,c:0} => ['a','b']
if ((0, ast_1.isTrueExpr)(value)) {
elements.push(prop.computed
? prop.key
: (0, ast_1.parseStringLiteral)(prop.key));
}
return;
}
elements.push((0, types_1.logicalExpression)('&&', value, prop.computed ? prop.key : (0, ast_1.parseStringLiteral)(prop.key)));
}
});
return (0, types_1.arrayExpression)(elements);
}
@@ -0,0 +1,11 @@
import { type ComponentNode, type DirectiveNode, type ElementNode } from '@vue/compiler-core';
import { type NodeTransform, type TransformContext } from '../transform';
export declare const transformComponent: NodeTransform;
/**
* 重写组件 props 绑定
* @param node
* @param context
*/
export declare function rewriteBinding({ tag, props }: ComponentNode, context: TransformContext): void;
export declare function isPropsBinding({ arg }: DirectiveNode): boolean | undefined;
export declare function rewritePropsBinding(dir: DirectiveNode, node: ElementNode, context: TransformContext): void;
@@ -0,0 +1,223 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.rewritePropsBinding = exports.isPropsBinding = exports.rewriteBinding = exports.transformComponent = void 0;
const shared_1 = require("@vue/shared");
const compiler_core_1 = require("@vue/compiler-core");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const transform_1 = require("../transform");
const utils_1 = require("./utils");
const codegen_1 = require("../codegen");
const types_1 = require("@babel/types");
const runtimeHelpers_1 = require("../runtimeHelpers");
const ast_1 = require("../ast");
const vIf_1 = require("./vIf");
const transformComponent = (node, context) => {
if (!(0, uni_cli_shared_1.isUserComponent)(node, context)) {
return;
}
// 新版本的 vue,识别 template 有差异,可能认为是自定义组件
if (node.tag === 'template') {
return;
}
addComponentType(node, context);
addVueId(node, context);
processBooleanAttr(node);
return function postTransformComponent() {
context.vueIds.pop();
};
};
exports.transformComponent = transformComponent;
function addComponentType(node, context) {
if (!context.isMiniProgramComponent(node.tag)) {
return;
}
node.props.push((0, uni_cli_shared_1.createAttributeNode)(utils_1.ATTR_COM_TYPE, 'm'));
}
function addVueId(node, context) {
let { hashId, scopes, currentScope, currentVueId } = context;
if (!hashId) {
return;
}
let vueId = hashId + '-' + scopes.vueId++;
const indexs = [];
while (currentScope) {
if ((0, transform_1.isVForScope)(currentScope)) {
indexs.push(`+'-'+${currentScope.indexAlias}`);
}
currentScope = currentScope.parent;
}
const inFor = !!indexs.length;
if (inFor) {
vueId = `'${vueId}'` + indexs.reverse().join('');
}
context.vueIds.push(vueId);
let value = vueId;
if (currentVueId) {
const isParentDynamic = currentVueId.includes('+');
const isCurrentDynamic = vueId.includes('+');
if (isParentDynamic || isCurrentDynamic) {
value = `(${vueId})+','+(${isParentDynamic ? currentVueId : `'${currentVueId}'`})`;
}
else {
value = vueId + ',' + currentVueId;
}
}
if (value.includes('+')) {
return node.props.push((0, uni_cli_shared_1.createBindDirectiveNode)(utils_1.ATTR_VUE_ID, value));
}
return node.props.push((0, uni_cli_shared_1.createAttributeNode)(utils_1.ATTR_VUE_ID, value));
}
/**
* <uni-collapse accordion/> => <uni-collapse :accordion="true"/>
* 否则部分平台(快手)可能获取到的 accordion 是空字符串
* @param param0
*/
function processBooleanAttr({ props }) {
props.forEach((prop, index) => {
if (prop.type === compiler_core_1.NodeTypes.ATTRIBUTE &&
typeof prop.value === 'undefined') {
props.splice(index, 1, (0, uni_cli_shared_1.createBindDirectiveNode)(prop.name, 'true'));
}
});
}
const builtInProps = [
// 'id',
'class',
'style',
utils_1.ATTR_VUE_ID,
utils_1.ATTR_VUE_PROPS,
utils_1.ATTR_VUE_SLOTS,
utils_1.ATTR_VUE_REF,
utils_1.ATTR_VUE_REF_IN_FOR,
utils_1.ATTR_COM_TYPE,
utils_1.ATTR_ELEMENT_ID,
utils_1.ATTR_SET_ELEMENT_STYLE,
'eO',
'e-o',
'onVI',
'ref',
'slot',
'key',
'is',
];
function isComponentProp(name) {
if (builtInProps.includes(name)) {
return false;
}
if (name.startsWith('data-')) {
return false;
}
if (name === (0, utils_1.filterObserverName)(utils_1.ATTR_SET_ELEMENT_STYLE)) {
return false;
}
return true;
}
/**
* 重写组件 props 绑定
* @param node
* @param context
*/
function rewriteBinding({ tag, props }, context) {
const isMiniProgramComponent = context.isMiniProgramComponent(tag);
if (isMiniProgramComponent === 'plugin' ||
isMiniProgramComponent === 'dynamicLib' ||
isMiniProgramComponent === 'xr-frame' ||
isMiniProgramComponent === 'ext') {
// 因无法介入插件类型组件内部实现,故保留原始属性
return;
}
const createObjectProperty = isMiniProgramComponent
? (name, value) => (0, types_1.objectProperty)((0, types_1.identifier)((0, shared_1.camelize)(name)), value)
: (name, value) => {
const computed = !(0, compiler_core_1.isSimpleIdentifier)(name);
return (0, types_1.objectProperty)(computed ? (0, types_1.stringLiteral)(name) : (0, types_1.identifier)(name), value, computed);
};
const properties = [];
for (let i = 0; i < props.length; i++) {
const prop = props[i];
let isIdProp = false;
if ((0, uni_cli_shared_1.isAttributeNode)(prop)) {
const { name } = prop;
isIdProp = name === 'id';
if (!isComponentProp(name)) {
continue;
}
properties.push(createObjectProperty(name, (0, types_1.stringLiteral)(prop.value?.content || '')));
}
else if ((0, uni_cli_shared_1.isDirectiveNode)(prop)) {
if (prop.name !== 'bind') {
continue;
}
const { arg, exp } = prop;
if (!exp) {
continue;
}
if (!arg) {
const spreadElement = createVBindSpreadElement(prop, context);
if (spreadElement) {
properties.push(spreadElement);
}
}
else if ((0, compiler_core_1.isStaticExp)(arg)) {
isIdProp = arg.content === 'id';
if (!isComponentProp(arg.content)) {
continue;
}
// :name="name"
const valueExpr = (0, ast_1.parseExpr)((0, codegen_1.genExpr)(exp), context, exp);
if (!valueExpr) {
continue;
}
properties.push(createObjectProperty(arg.content, valueExpr));
}
else {
// :[dynamic]="dynamic"
const leftExpr = (0, ast_1.parseExpr)((0, codegen_1.genExpr)(arg), context, exp);
if (!leftExpr) {
continue;
}
const valueExpr = (0, ast_1.parseExpr)((0, codegen_1.genExpr)(exp), context, exp);
if (!valueExpr) {
continue;
}
properties.push((0, types_1.objectProperty)((0, types_1.logicalExpression)('||', leftExpr, (0, types_1.stringLiteral)('')), valueExpr, true));
}
}
// 即保留 id 属性,又补充到 props 中
if (!isIdProp) {
props.splice(i, 1);
i--;
}
}
if (properties.length) {
props.push((0, uni_cli_shared_1.createBindDirectiveNode)(utils_1.ATTR_VUE_PROPS, (0, codegen_1.genBabelExpr)((0, types_1.objectExpression)(properties))));
}
}
exports.rewriteBinding = rewriteBinding;
function createVBindSpreadElement(prop, context) {
const { arg, exp } = prop;
if (!exp) {
return;
}
if (!arg) {
const argument = (0, ast_1.parseExpr)((0, codegen_1.genExpr)(exp), context, exp);
if (!argument) {
return;
}
return (0, types_1.spreadElement)(argument);
}
}
function isPropsBinding({ arg }) {
return (arg &&
arg.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION &&
arg.content === utils_1.ATTR_VUE_PROPS);
}
exports.isPropsBinding = isPropsBinding;
function rewritePropsBinding(dir, node, context) {
dir.exp = (0, compiler_core_1.createSimpleExpression)((0, codegen_1.genBabelExpr)((0, utils_1.rewirteWithHelper)(runtimeHelpers_1.RENDER_PROPS, (0, ast_1.parseExpr)(dir.exp, context), dir.loc, context)) +
(((0, vIf_1.isIfElementNode)(node) && node.vIf.name === 'else') ||
context.miniProgram.component?.getPropertySync
? `||''`
: ''));
}
exports.rewritePropsBinding = rewritePropsBinding;
@@ -0,0 +1,9 @@
import { type ElementNode, type Property, type TemplateLiteral } from '@vue/compiler-core';
import { type NodeTransform, type TransformContext } from '../transform';
export interface DirectiveTransformResult {
props: Property[];
needRuntime?: boolean | symbol;
ssrTagParts?: TemplateLiteral['elements'];
}
export declare const transformElement: NodeTransform;
export declare function processProps(node: ElementNode, context: TransformContext, props?: ElementNode['props']): void;
@@ -0,0 +1,200 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.processProps = exports.transformElement = void 0;
const shared_1 = require("@vue/shared");
const compiler_core_1 = require("@vue/compiler-core");
const uni_shared_1 = require("@dcloudio/uni-shared");
const errors_1 = require("../errors");
const vModel_1 = require("./vModel");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const transformElement = (node, context) => {
return function postTransformElement() {
node = context.currentNode;
if (!(node.type === compiler_core_1.NodeTypes.ELEMENT &&
(node.tagType === compiler_core_1.ElementTypes.ELEMENT ||
node.tagType === compiler_core_1.ElementTypes.COMPONENT))) {
return;
}
if (node.tagType === compiler_core_1.ElementTypes.COMPONENT) {
processComponent(node, context);
}
if (context.scopeId) {
addScopeId(node, context.scopeId);
}
const { props } = node;
if (props.length > 0) {
processProps(node, context);
}
};
};
exports.transformElement = transformElement;
function addScopeId(node, scopeId) {
return (0, uni_cli_shared_1.addStaticClass)(node, scopeId);
}
function processComponent(node, context) {
const { tag } = node;
if (context.bindingComponents[tag]) {
return;
}
// 1. dynamic component
if ((0, uni_shared_1.isComponentTag)(tag)) {
return context.onError((0, errors_1.createMPCompilerError)(8 /* MPErrorCodes.X_DYNAMIC_COMPONENT_NOT_SUPPORTED */, node.loc));
}
if ((0, compiler_core_1.findDir)(node, 'is')) {
return context.onError((0, errors_1.createMPCompilerError)(6 /* MPErrorCodes.X_V_IS_NOT_SUPPORTED */, node.loc));
}
// TODO not supported
// const isProp = findProp(node, 'is')
// if (isProp) {
// }
// 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)
const builtIn = (0, compiler_core_1.isCoreComponent)(tag) || context.isBuiltInComponent(tag);
if (builtIn) {
return context.onError((0, errors_1.createMPCompilerError)(7 /* MPErrorCodes.X_NOT_SUPPORTED */, node.loc, tag));
}
// 3. user component (from setup bindings)
const fromSetup = resolveSetupReference(tag, context);
if (fromSetup) {
return (context.bindingComponents[tag] = {
name: fromSetup,
type: "setup" /* BindingComponentTypes.SETUP */,
});
}
const dotIndex = tag.indexOf('.');
if (dotIndex > 0) {
return context.onError((0, errors_1.createMPCompilerError)(7 /* MPErrorCodes.X_NOT_SUPPORTED */, node.loc, tag));
}
// 4. Self referencing component (inferred from filename)
if (context.selfName && (0, shared_1.capitalize)((0, shared_1.camelize)(tag)) === context.selfName) {
return (context.bindingComponents[tag] = {
name: (0, compiler_core_1.toValidAssetId)(tag, `component`),
type: "self" /* BindingComponentTypes.SELF */,
});
}
// 5. user component (resolve)
context.bindingComponents[tag] = {
name: (0, compiler_core_1.toValidAssetId)(tag, `component`),
type: "unknown" /* BindingComponentTypes.UNKNOWN */,
};
context.helper(compiler_core_1.RESOLVE_COMPONENT);
}
function resolveSetupReference(name, context) {
const bindings = context.bindingMetadata;
if (!bindings || bindings.__isScriptSetup === false) {
return;
}
const camelName = (0, shared_1.camelize)(name);
const PascalName = (0, shared_1.capitalize)(camelName);
const checkType = (type) => {
if (bindings[name] === type) {
return name;
}
if (bindings[camelName] === type) {
return camelName;
}
if (bindings[PascalName] === type) {
return PascalName;
}
};
const fromConst = checkType(compiler_core_1.BindingTypes.SETUP_CONST) ||
checkType(compiler_core_1.BindingTypes.SETUP_REACTIVE_CONST) ||
checkType(compiler_core_1.BindingTypes.LITERAL_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(compiler_core_1.BindingTypes.SETUP_LET) ||
checkType(compiler_core_1.BindingTypes.SETUP_REF) ||
checkType(compiler_core_1.BindingTypes.SETUP_MAYBE_REF);
if (fromMaybeRef) {
return context.inline
? // setup scope bindings that may be refs need to be unrefed
`${context.helperString(compiler_core_1.UNREF)}(${fromMaybeRef})`
: `$setup[${JSON.stringify(fromMaybeRef)}]`;
}
}
function processProps(node, context, props = node.props) {
const { tag } = node;
const isComponent = node.tagType === compiler_core_1.ElementTypes.COMPONENT;
const isPluginComponent = isComponent && context.isMiniProgramComponent(node.tag) === 'plugin';
for (let i = 0; i < props.length; i++) {
const prop = props[i];
if (prop.type === compiler_core_1.NodeTypes.DIRECTIVE) {
// directives
const { name, arg, loc } = prop;
const isVBind = name === 'bind';
const isVOn = name === 'on';
// skip v-slot - it is handled by its dedicated transform.
if (name === 'slot') {
if (!isComponent) {
context.onError((0, compiler_core_1.createCompilerError)(compiler_core_1.ErrorCodes.X_V_SLOT_MISPLACED, loc));
}
continue;
}
// skip v-once/v-memo - they are handled by dedicated transforms.
if (name === 'once' || name === 'memo') {
continue;
}
// skip v-is and :is on <component>
if (name === 'is' ||
(isVBind && (0, compiler_core_1.isStaticArgOf)(arg, 'is') && (0, uni_shared_1.isComponentTag)(tag))) {
continue;
}
if (isVBind || isVOn) {
// v-on=""
// v-bind=""
if (!arg) {
if (isVOn) {
context.onError((0, errors_1.createMPCompilerError)(0 /* MPErrorCodes.X_V_ON_NO_ARGUMENT */, loc));
}
if (isVBind && (!isComponent || isPluginComponent)) {
context.onError((0, errors_1.createMPCompilerError)(2 /* MPErrorCodes.X_V_BIND_NO_ARGUMENT */, loc));
}
continue;
}
// v-on:[a]=""
// v-on:[a.b]=""
// v-bind:[a]=""
// v-bind:[a.b]=""
if (!(arg.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION && arg.isStatic)) {
if (isVOn) {
context.onError((0, errors_1.createMPCompilerError)(1 /* MPErrorCodes.X_V_ON_DYNAMIC_EVENT */, loc));
}
if (isVBind && (!isComponent || isPluginComponent)) {
context.onError((0, errors_1.createMPCompilerError)(3 /* MPErrorCodes.X_V_BIND_DYNAMIC_ARGUMENT */, loc));
}
continue;
}
}
const directiveTransform = context.directiveTransforms[name];
if (name !== 'model' && directiveTransform) {
const { props } = directiveTransform(prop, node, context);
if (props.length) {
prop.exp = props[0].value;
}
}
}
}
const transformVModel = (context.directiveTransforms.model ||
vModel_1.transformModel);
processVModel(node, transformVModel, context);
}
exports.processProps = processProps;
function processVModel(node, transformVModel, context) {
const { props } = node;
const dirs = [];
for (let i = 0; i < props.length; i++) {
const prop = props[i];
if (prop.type === compiler_core_1.NodeTypes.DIRECTIVE && prop.name === 'model') {
dirs.push(...transformVModel(prop, node, context)
.props);
props.splice(i, 1);
i--;
}
}
if (dirs.length) {
props.push(...dirs);
}
}
@@ -0,0 +1,5 @@
import { type ExpressionNode, type SimpleExpressionNode } from '@vue/compiler-core';
import type { NodeTransform, TransformContext } from '../transform';
export declare const transformExpression: NodeTransform;
export declare function processExpression(node: SimpleExpressionNode, context: TransformContext, asParams?: boolean, asRawStatements?: boolean, localVars?: Record<string, number>): ExpressionNode;
export declare function isBuiltInIdentifier(id: string | ExpressionNode): boolean;
@@ -0,0 +1,299 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isBuiltInIdentifier = exports.processExpression = exports.transformExpression = void 0;
const shared_1 = require("@vue/shared");
const compiler_core_1 = require("@vue/compiler-core");
const parser_1 = require("@babel/parser");
const isLiteralWhitelisted = /*#__PURE__*/ (0, shared_1.makeMap)('true,false,null,this');
const transformExpression = (node, context) => {
if (node.type === compiler_core_1.NodeTypes.INTERPOLATION) {
node.content = processExpression(node.content, context);
}
else if (node.type === compiler_core_1.NodeTypes.ELEMENT) {
// handle directives on element
for (let i = 0; i < node.props.length; i++) {
const dir = node.props[i];
// do not process for v-on & v-for since they are special handled
if (dir.type === compiler_core_1.NodeTypes.DIRECTIVE && dir.name !== 'for') {
const exp = dir.exp;
const arg = dir.arg;
// do not process exp if this is v-on:arg - we need special handling
// for wrapping inline statements.
if (exp &&
exp.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION &&
!(dir.name === 'on' && arg)) {
dir.exp = processExpression(exp, context,
// slot args must be processed as function params
dir.name === 'slot');
}
if (arg && arg.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION && !arg.isStatic) {
dir.arg = processExpression(arg, context);
}
}
}
}
};
exports.transformExpression = transformExpression;
// Important: since this function uses Node.js only dependencies, it should
// always be used with a leading !__BROWSER__ check so that it can be
// tree-shaken from the browser build.
function processExpression(node, context,
// some expressions like v-slot props & v-for aliases should be parsed as
// function params
asParams = false,
// v-on handler values may contain multiple statements
asRawStatements = false, localVars = Object.create(context.identifiers)) {
if (!context.prefixIdentifiers || !node.content.trim()) {
return node;
}
const { inline, bindingMetadata } = context;
const rewriteIdentifier = (raw, parent, id) => {
const type = (0, shared_1.hasOwn)(bindingMetadata, raw) && bindingMetadata[raw];
if (inline) {
// x = y
const isAssignmentLVal = parent && parent.type === 'AssignmentExpression' && parent.left === id;
// x++
const isUpdateArg = parent && parent.type === 'UpdateExpression' && parent.argument === id;
// ({ x } = y)
const isDestructureAssignment = parent && (0, compiler_core_1.isInDestructureAssignment)(parent, parentStack);
if (isConst(type) || localVars[raw]) {
return raw;
}
else if (type === compiler_core_1.BindingTypes.SETUP_REF) {
return `${raw}.value`;
}
else if (type === compiler_core_1.BindingTypes.SETUP_MAYBE_REF) {
// const binding that may or may not be ref
// if it's not a ref, then assignments don't make sense -
// so we ignore the non-ref assignment case and generate code
// that assumes the value to be a ref for more efficiency
return isAssignmentLVal || isUpdateArg || isDestructureAssignment
? `${raw}.value`
: `${context.helperString(compiler_core_1.UNREF)}(${raw})`;
}
else if (type === compiler_core_1.BindingTypes.SETUP_LET) {
if (isAssignmentLVal) {
// let binding.
// this is a bit more tricky as we need to cover the case where
// let is a local non-ref value, and we need to replicate the
// right hand side value.
// x = y --> isRef(x) ? x.value = y : x = y
const { right: rVal, operator } = parent;
const rExp = rawExp.slice(rVal.start - 1, rVal.end - 1);
const rExpString = stringifyExpression(processExpression((0, compiler_core_1.createSimpleExpression)(rExp, false), context, false, false, knownIds));
return `${context.helperString(compiler_core_1.IS_REF)}(${raw})${context.isTS ? ` //@ts-ignore\n` : ``} ? ${raw}.value ${operator} ${rExpString} : ${raw}`;
}
else if (isUpdateArg) {
// make id replace parent in the code range so the raw update operator
// is removed
id.start = parent.start;
id.end = parent.end;
const { prefix: isPrefix, operator } = parent;
const prefix = isPrefix ? operator : ``;
const postfix = isPrefix ? `` : operator;
// let binding.
// x++ --> isRef(a) ? a.value++ : a++
return `${context.helperString(compiler_core_1.IS_REF)}(${raw})${context.isTS ? ` //@ts-ignore\n` : ``} ? ${prefix}${raw}.value${postfix} : ${prefix}${raw}${postfix}`;
}
else if (isDestructureAssignment) {
// TODO
// let binding in a destructure assignment - it's very tricky to
// handle both possible cases here without altering the original
// structure of the code, so we just assume it's not a ref here
// for now
return raw;
}
else {
return `${context.helperString(compiler_core_1.UNREF)}(${raw})`;
}
}
else if (type === compiler_core_1.BindingTypes.PROPS) {
// use __props which is generated by compileScript so in ts mode
// it gets correct type
return (0, shared_1.genPropsAccessExp)(raw);
}
else if (type === compiler_core_1.BindingTypes.PROPS_ALIASED) {
// prop with a different local alias (from defineProps() destructure)
return (0, shared_1.genPropsAccessExp)(bindingMetadata.__propsAliases[raw]);
}
}
else {
if ((type && type.startsWith('setup')) ||
type === compiler_core_1.BindingTypes.LITERAL_CONST) {
// setup bindings in non-inline mode
return `$setup.${raw}`;
}
else if (type === compiler_core_1.BindingTypes.PROPS_ALIASED) {
return `$props['${bindingMetadata.__propsAliases[raw]}']`;
}
else if (type) {
return `$${type}.${raw}`;
}
}
// fallback to ctx
return `_ctx.${raw}`;
};
// fast path if expression is a simple identifier.
const rawExp = node.content;
// bail constant on parens (function invocation) and dot (member access)
const bailConstant = rawExp.indexOf(`(`) > -1 || rawExp.indexOf('.') > 0;
if ((0, compiler_core_1.isSimpleIdentifier)(rawExp)) {
const isScopeVarReference = context.identifiers[rawExp];
const isAllowedGlobal = (0, shared_1.isGloballyWhitelisted)(rawExp);
const isLiteral = isLiteralWhitelisted(rawExp);
const isFilter = context.filters.includes(rawExp);
const isBuiltIn = isBuiltInIdentifier(rawExp);
if (!asParams &&
!isScopeVarReference &&
!isAllowedGlobal &&
!isLiteral &&
!isFilter &&
!isBuiltIn) {
// const bindings exposed from setup can be skipped for patching but
// cannot be hoisted to module scope
if (isConst(bindingMetadata[node.content])) {
node.constType = compiler_core_1.ConstantTypes.CAN_SKIP_PATCH;
}
node.content = rewriteIdentifier(rawExp);
}
else if (!isScopeVarReference) {
if (isLiteral) {
node.constType = compiler_core_1.ConstantTypes.CAN_STRINGIFY;
}
else {
node.constType = compiler_core_1.ConstantTypes.CAN_HOIST;
}
}
return node;
}
let ast;
// exp needs to be parsed differently:
// 1. Multiple inline statements (v-on, with presence of `;`): parse as raw
// exp, but make sure to pad with spaces for consistent ranges
// 2. Expressions: wrap with parens (for e.g. object expressions)
// 3. Function arguments (v-for, v-slot): place in a function argument position
const source = asRawStatements
? ` ${rawExp} `
: `(${rawExp})${asParams ? `=>{}` : ``}`;
try {
ast = (0, parser_1.parse)(source, {
plugins: context.expressionPlugins,
}).program;
}
catch (e) {
context.onError((0, compiler_core_1.createCompilerError)(compiler_core_1.ErrorCodes.X_INVALID_EXPRESSION, node.loc, undefined, '\n' + source + '\n' + e.message));
return node;
}
const ids = [];
const parentStack = [];
const knownIds = Object.create(context.identifiers);
context.filters.forEach((name) => {
knownIds[name] = 1;
});
(0, compiler_core_1.walkIdentifiers)(ast, (node, parent, _, isReferenced, isLocal) => {
if ((0, compiler_core_1.isStaticPropertyKey)(node, parent)) {
return;
}
const needPrefix = isReferenced && canPrefix(node);
if (needPrefix && !isLocal) {
if ((0, compiler_core_1.isStaticProperty)(parent) && parent.shorthand) {
// property shorthand like { foo }, we need to add the key since
// we rewrite the value
;
node.prefix = `${node.name}: `;
}
node.name = rewriteIdentifier(node.name, parent, node);
ids.push(node);
}
else {
// The identifier is considered constant unless it's pointing to a
// local scope variable (a v-for alias, or a v-slot prop)
if (!(needPrefix && isLocal) && !bailConstant) {
;
node.isConstant = true;
}
// also generate sub-expressions for other identifiers for better
// source map support. (except for property keys which are static)
ids.push(node);
}
}, true, // invoke on ALL identifiers
parentStack, knownIds);
// We break up the compound expression into an array of strings and sub
// expressions (for identifiers that have been prefixed). In codegen, if
// an ExpressionNode has the `.children` property, it will be used instead of
// `.content`.
const children = [];
ids.sort((a, b) => a.start - b.start);
ids.forEach((id, i) => {
// range is offset by -1 due to the wrapping parens when parsed
const start = id.start - 1;
const end = id.end - 1;
const last = ids[i - 1];
const leadingText = rawExp.slice(last ? last.end - 1 : 0, start);
if (leadingText.length || id.prefix) {
children.push(leadingText + (id.prefix || ``));
}
const source = rawExp.slice(start, end);
children.push((0, compiler_core_1.createSimpleExpression)(id.name, false, {
source,
start: (0, compiler_core_1.advancePositionWithClone)(node.loc.start, source, start),
end: (0, compiler_core_1.advancePositionWithClone)(node.loc.start, source, end),
}, id.isConstant ? compiler_core_1.ConstantTypes.CAN_STRINGIFY : compiler_core_1.ConstantTypes.NOT_CONSTANT));
if (i === ids.length - 1 && end < rawExp.length) {
children.push(rawExp.slice(end));
}
});
let ret;
if (children.length) {
ret = (0, compiler_core_1.createCompoundExpression)(children, node.loc);
}
else {
ret = node;
ret.constType = bailConstant
? compiler_core_1.ConstantTypes.NOT_CONSTANT
: compiler_core_1.ConstantTypes.CAN_STRINGIFY;
}
ret.identifiers = Object.keys(knownIds);
return ret;
}
exports.processExpression = processExpression;
function canPrefix(id) {
// skip whitelisted globals
if ((0, shared_1.isGloballyWhitelisted)(id.name)) {
return false;
}
// special case for webpack compilation
if (id.name === 'require') {
return false;
}
return true;
}
function stringifyExpression(exp) {
if ((0, shared_1.isString)(exp)) {
return exp;
}
else if (exp.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
return exp.content;
}
else {
return exp.children
.map(stringifyExpression)
.join('');
}
}
const builtInIdentifiers = ['__l'];
function isBuiltInIdentifier(id) {
if (!(0, shared_1.isString)(id)) {
if (id.type !== compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
return false;
}
id = id.content;
}
return builtInIdentifiers.includes(id);
}
exports.isBuiltInIdentifier = isBuiltInIdentifier;
function isConst(type) {
return (type === compiler_core_1.BindingTypes.SETUP_CONST ||
type === compiler_core_1.BindingTypes.LITERAL_CONST ||
type === compiler_core_1.BindingTypes.SETUP_REACTIVE_CONST);
}
@@ -0,0 +1,2 @@
import type { NodeTransform } from '../transform';
export declare const transformIdentifier: NodeTransform;
@@ -0,0 +1,157 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformIdentifier = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const utils_1 = require("./utils");
const transformClass_1 = require("./transformClass");
const transformStyle_1 = require("./transformStyle");
const runtimeHelpers_1 = require("../runtimeHelpers");
const transformSlot_1 = require("./transformSlot");
const vSlot_1 = require("./vSlot");
const transformRef_1 = require("./transformRef");
const transformComponent_1 = require("./transformComponent");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const shared_1 = require("@vue/shared");
const transformUniElement_1 = require("./transformUniElement");
const transformIdentifier = (node, context) => {
return function transformIdentifier() {
if (node.type === compiler_core_1.NodeTypes.INTERPOLATION) {
const content = node.content;
let isFilter = false;
if (content.type === compiler_core_1.NodeTypes.COMPOUND_EXPRESSION) {
const firstChild = content.children[0];
isFilter =
!(0, shared_1.isString)(firstChild) &&
!(0, shared_1.isSymbol)(firstChild) &&
firstChild.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION &&
context.filters.includes(firstChild.content);
}
if (!isFilter) {
node.content = (0, utils_1.rewriteExpression)((0, compiler_core_1.createCompoundExpression)([
`${context.helperString(runtimeHelpers_1.TO_DISPLAY_STRING)}(`,
content,
`)`,
]), context);
}
}
else if ((0, compiler_core_1.isSlotOutlet)(node)) {
(0, transformSlot_1.rewriteSlot)(node, context);
}
else if (node.type === compiler_core_1.NodeTypes.ELEMENT) {
let hasClassBinding = false;
let hasStyleBinding = false;
(0, transformRef_1.rewriteRef)(node, context);
if (context.isX) {
(0, transformUniElement_1.rewriteId)(node, context);
}
if ((0, uni_cli_shared_1.isUserComponent)(node, context)) {
(0, transformComponent_1.rewriteBinding)(node, context);
}
const { props } = node;
const virtualHost = !!(context.miniProgram.component?.mergeVirtualHostAttributes &&
context.rootNode === node);
let elementId = '';
let skipIndex = [];
// 第一步:在 x 中,先处理 id 属性,用于提前获取 elementId 对应的变量名
if (context.isX) {
for (let i = 0; i < props.length; i++) {
const dir = props[i];
if (dir.type === compiler_core_1.NodeTypes.DIRECTIVE) {
const { arg, exp } = dir;
if (arg && exp && (0, uni_cli_shared_1.isSimpleExpressionNode)(arg)) {
if (arg.content === 'id' || arg.content === utils_1.ATTR_ELEMENT_ID) {
dir.exp = (0, utils_1.rewriteExpression)(exp, context);
elementId = dir.exp.content;
skipIndex.push(i);
}
}
}
}
}
for (let i = 0; i < props.length; i++) {
if (context.isX) {
// 已经处理过了
if (skipIndex.includes(i)) {
continue;
}
}
const dir = props[i];
if (dir.type === compiler_core_1.NodeTypes.DIRECTIVE) {
const arg = dir.arg;
if (arg) {
// TODO 指令暂不不支持动态参数,v-bind:[arg] v-on:[event]
if (!(arg.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION && arg.isStatic)) {
// v-slot:[slotName] 支持
if (dir.name === 'slot') {
(0, vSlot_1.rewriteVSlot)(dir, context);
}
else {
props.splice(i, 1);
i--;
continue;
}
}
}
const exp = dir.exp;
if (exp) {
if (isBuiltIn(dir)) {
// noop
}
else if ((0, transformClass_1.isClassBinding)(dir)) {
hasClassBinding = true;
(0, transformClass_1.rewriteClass)(i, dir, props, virtualHost, context);
}
else if ((0, transformStyle_1.isStyleBinding)(dir)) {
hasStyleBinding = true;
(0, transformStyle_1.rewriteStyle)(i, dir, props, virtualHost, context, elementId);
}
else if ((0, transformComponent_1.isPropsBinding)(dir)) {
(0, transformComponent_1.rewritePropsBinding)(dir, node, context);
}
else {
if (context.isX &&
elementId &&
arg &&
(0, uni_cli_shared_1.isSimpleExpressionNode)(arg) &&
arg.content === utils_1.ATTR_SET_ELEMENT_STYLE) {
dir.exp = (0, compiler_core_1.createSimpleExpression)(`$eS[${elementId}]`);
}
else {
dir.exp = (0, utils_1.rewriteExpression)(exp, context);
}
}
}
}
}
if (virtualHost) {
if (!hasClassBinding) {
hasClassBinding = true;
props.push((0, transformClass_1.createVirtualHostClass)(props, context));
}
if (!hasStyleBinding) {
hasStyleBinding = true;
props.push((0, transformStyle_1.createVirtualHostStyle)(props, context));
}
}
if (hasClassBinding) {
const staticClassIndex = (0, transformClass_1.findStaticClassIndex)(props);
if (staticClassIndex > -1) {
props.splice(staticClassIndex, 1);
}
}
if (hasStyleBinding) {
const staticStyleIndex = (0, transformStyle_1.findStaticStyleIndex)(props);
if (staticStyleIndex > -1) {
props.splice(staticStyleIndex, 1);
}
}
}
};
};
exports.transformIdentifier = transformIdentifier;
const builtInProps = [utils_1.ATTR_VUE_SLOTS];
function isBuiltIn({ arg, exp }) {
return (arg?.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION &&
builtInProps.includes(arg.content) &&
exp?.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION);
}
@@ -0,0 +1,4 @@
import { type DirectiveNode } from '@vue/compiler-core';
import type { ForElementNode } from './vFor';
export declare function isSelfKey({ arg, exp }: DirectiveNode, vFor: ForElementNode['vFor'] | false): boolean | undefined;
export declare function rewriteSelfKey(dir: DirectiveNode): void;
+19
View File
@@ -0,0 +1,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.rewriteSelfKey = exports.isSelfKey = void 0;
const compiler_core_1 = require("@vue/compiler-core");
function isSelfKey({ arg, exp }, vFor) {
return (vFor &&
arg &&
exp &&
arg.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION &&
arg.content === 'key' &&
exp.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION &&
exp.content === vFor.valueAlias);
}
exports.isSelfKey = isSelfKey;
function rewriteSelfKey(dir) {
;
dir.exp.content = '*this';
}
exports.rewriteSelfKey = rewriteSelfKey;
@@ -0,0 +1,8 @@
import { type AttributeNode, type DirectiveNode, type ElementNode } from '@vue/compiler-core';
import type { TransformContext } from '../transform';
export declare function rewriteRef(node: ElementNode, context: TransformContext): void;
export declare function parseRefCode(prop: AttributeNode | DirectiveNode, context: TransformContext): {
code: string;
refKey: string;
};
export declare function rewriteRefProp(helper: symbol, prop: AttributeNode | DirectiveNode, idProp: AttributeNode | DirectiveNode, opts: Record<string, any>, context: TransformContext): void;
+126
View File
@@ -0,0 +1,126 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.rewriteRefProp = exports.parseRefCode = exports.rewriteRef = void 0;
const types_1 = require("@babel/types");
const compiler_core_1 = require("@vue/compiler-core");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const utils_1 = require("./utils");
const runtimeHelpers_1 = require("../runtimeHelpers");
const codegen_1 = require("../codegen");
const ast_1 = require("../ast");
function rewriteRef(node, context) {
const vueIdProp = (0, compiler_core_1.findProp)(node, utils_1.ATTR_VUE_ID);
if (!vueIdProp) {
return;
}
const refProp = (0, compiler_core_1.findProp)(node, 'u-' + uni_cli_shared_1.VUE_REF) || (0, compiler_core_1.findProp)(node, 'u-' + uni_cli_shared_1.VUE_REF_IN_FOR);
if (!refProp) {
return;
}
if ((0, compiler_core_1.findProp)(node, 'ref')) {
// 支付宝小程序
const code = parseAlipayRefCode(refProp, context);
if (code && context.inline && !(0, uni_cli_shared_1.isDirectiveNode)(refProp)) {
refProp.value.content = code;
const refPropIndex = node.props.findIndex((prop) => prop === refProp);
node.props.splice(refPropIndex, 1, (0, uni_cli_shared_1.createBindDirectiveNode)(refProp.name, code));
}
}
else {
rewriteRefProp(runtimeHelpers_1.SET_REF, refProp, vueIdProp, {}, context);
}
}
exports.rewriteRef = rewriteRef;
function parseRef(prop, context) {
let expr;
let refKey = '';
const isDir = (0, uni_cli_shared_1.isDirectiveNode)(prop);
if (isDir) {
if (prop.exp) {
expr = (0, ast_1.parseExpr)(prop.exp, context, prop.exp);
}
}
else {
const { value } = prop;
if (value && value.content) {
if (context.inline && context.bindingMetadata[value.content]) {
expr = (0, types_1.identifier)(value.content);
refKey = value.content;
}
else {
expr = (0, types_1.stringLiteral)(value.content);
}
}
}
return { expr, refKey };
}
function parseRefCode(prop, context) {
const { expr, refKey } = parseRef(prop, context);
if (!expr) {
return { code: '', refKey };
}
return { code: (0, codegen_1.genBabelExpr)(expr), refKey };
}
exports.parseRefCode = parseRefCode;
function rewriteRefProp(helper, prop, idProp, opts, context) {
let id = '';
if ((0, uni_cli_shared_1.isDirectiveNode)(idProp)) {
const vueIdExpr = (0, ast_1.parseExpr)(idProp.exp, context, idProp.exp);
if (vueIdExpr) {
id = (0, codegen_1.genBabelExpr)(vueIdExpr);
}
}
else {
id = `'${idProp.value.content}'`;
}
if (!id) {
return;
}
const { code, refKey } = parseRefCode(prop, context);
if (refKey) {
opts.k = refKey;
}
if (context.inVFor) {
opts.f = 1;
}
(0, utils_1.parseExprWithRewrite)(context.helperString(helper) +
'(' +
code +
', ' +
id +
(Object.keys(opts).length ? ', ' + JSON.stringify(opts) : '') +
')', prop.loc, context);
}
exports.rewriteRefProp = rewriteRefProp;
function parseAlipayRefCode(prop, context) {
let expr;
const isDir = (0, uni_cli_shared_1.isDirectiveNode)(prop);
if (isDir) {
if (prop.exp) {
expr = (0, ast_1.parseExpr)(prop.exp, context, prop.exp);
}
}
else {
if (prop.value?.content) {
expr = context.inline
? processInlineRef(prop, context)
: (0, types_1.stringLiteral)(prop.value.content);
}
}
if (!expr) {
return;
}
return (0, codegen_1.genBabelExpr)(expr);
}
function processInlineRef(prop, context) {
const properties = [];
const { refKey } = parseRef(prop, context);
properties.push((0, types_1.objectProperty)((0, types_1.identifier)('r'), (0, types_1.identifier)(prop.value.content)));
if (refKey) {
properties.push((0, types_1.objectProperty)((0, types_1.identifier)('k'), (0, types_1.stringLiteral)(refKey)));
}
if (context.inVFor) {
properties.push((0, types_1.objectProperty)((0, types_1.identifier)('f'), (0, types_1.numericLiteral)(1)));
}
return (0, types_1.arrowFunctionExpression)([], (0, types_1.objectExpression)(properties));
}
@@ -0,0 +1,2 @@
import type { NodeTransform } from '../transform';
export declare const transformRoot: NodeTransform;
@@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformRoot = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const ast_1 = require("../ast");
const types_1 = require("@babel/types");
const codegen_1 = require("../codegen");
const transformRoot = (node, context) => {
if (node.type !== compiler_core_1.NodeTypes.ROOT) {
return;
}
if (context.bindingCssVars.length) {
node.children.forEach((child) => {
if (child.type !== compiler_core_1.NodeTypes.ELEMENT) {
return;
}
addCssVars(child, context);
});
}
};
exports.transformRoot = transformRoot;
const CSS_VARS = '__cssVars()';
function addCssVars(node, context) {
const styleProp = (0, compiler_core_1.findProp)(node, 'style', true);
if (!styleProp) {
node.props.push((0, uni_cli_shared_1.createBindDirectiveNode)('style', CSS_VARS));
}
else {
if (styleProp.exp?.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
let expr = (0, ast_1.parseExpr)(styleProp.exp.content, context);
if ((0, types_1.isArrayExpression)(expr)) {
expr.elements.push((0, types_1.identifier)(CSS_VARS));
}
else {
expr = (0, types_1.arrayExpression)([expr, (0, types_1.identifier)(CSS_VARS)]);
}
styleProp.exp.content = (0, codegen_1.genBabelExpr)(expr);
}
}
}
@@ -0,0 +1,7 @@
import { type DirectiveNode, type SlotOutletNode } from '@vue/compiler-core';
import { type TransformContext } from '../transform';
export declare function rewriteSlot(node: SlotOutletNode, context: TransformContext): void;
export interface NameScopedSlotDirectiveNode extends DirectiveNode {
slotName: string;
}
export declare function parseVForKeyAlias(context: TransformContext): string[];
+188
View File
@@ -0,0 +1,188 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseVForKeyAlias = exports.rewriteSlot = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const shared_1 = require("@vue/shared");
const uni_shared_1 = require("@dcloudio/uni-shared");
const runtimeHelpers_1 = require("../runtimeHelpers");
const codegen_1 = require("../codegen");
const transform_1 = require("../transform");
const transformElement_1 = require("./transformElement");
const utils_1 = require("./utils");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const __1 = require("..");
const ast_1 = require("../ast");
function rewriteSlot(node, context) {
let slotName = `"${uni_shared_1.SLOT_DEFAULT_NAME}"`;
let hasOtherDir = false;
const nonNameProps = [];
const { props } = node;
// 默认插槽强制设置name
if (!(0, compiler_core_1.findProp)(node, 'name')) {
props.unshift((0, uni_cli_shared_1.createAttributeNode)('name', 'default'));
}
for (let i = 0; i < props.length; i++) {
const p = props[i];
if (p.type === compiler_core_1.NodeTypes.ATTRIBUTE) {
if (p.value) {
if (p.name === 'name') {
p.value.content = (0, uni_shared_1.dynamicSlotName)(p.value.content);
slotName = JSON.stringify(p.value.content);
}
else {
p.name = (0, shared_1.camelize)(p.name);
nonNameProps.push(p);
}
}
}
else {
if (p.name !== 'bind') {
hasOtherDir = true;
}
if (p.name === 'bind' && (0, compiler_core_1.isStaticArgOf)(p.arg, 'name')) {
if (p.exp) {
slotName = (0, compiler_core_1.createCompoundExpression)([
context.helperString(__1.DYNAMIC_SLOT) + '(',
p.exp,
')',
]);
let slotKey;
const keys = parseVForKeyAlias(context);
if (keys.length) {
const babelNode = (0, ast_1.parseExpr)(p.exp, context);
// 在 v-for 中,判断是否插槽名使用 v-for 的 key 变量
if (babelNode && (0, utils_1.isReferencedByIds)(babelNode, keys)) {
slotKey = parseScopedSlotKey(context);
}
}
p.exp = (0, utils_1.rewriteExpression)((0, compiler_core_1.createCompoundExpression)([
context.helperString(__1.DYNAMIC_SLOT) + '(',
p.exp,
slotKey ? `+'-'+` + slotKey : '',
')',
]), context);
}
}
else {
if (p.name === 'bind' && p.arg && (0, compiler_core_1.isStaticExp)(p.arg)) {
p.arg.content = (0, shared_1.camelize)(p.arg.content);
}
nonNameProps.push(p);
}
}
}
if (hasOtherDir) {
context.onError((0, compiler_core_1.createCompilerError)(compiler_core_1.ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET, node.loc));
}
if (nonNameProps.length > 0) {
(0, transformElement_1.processProps)(node, context, nonNameProps);
const properties = [];
nonNameProps.forEach((prop) => {
const property = transformProperty(prop, context);
property && properties.push(property);
});
if (properties.length) {
transformScopedSlotName(node, context);
const vForIndexAlias = parseVForIndexAlias(context);
(0, utils_1.rewriteExpression)((0, compiler_core_1.createCompoundExpression)([
context.helperString(runtimeHelpers_1.RENDER_SLOT) + '(',
slotName,
',',
`{${properties.join(',')}}`,
`${vForIndexAlias ? ',' + parseScopedSlotKey(context) : ''}`,
')',
]), context);
}
else {
// 非作用域默认插槽直接移除命名
if (slotName === `"${uni_shared_1.SLOT_DEFAULT_NAME}"`) {
(0, utils_1.removeAttribute)(node, 'name');
}
}
}
else {
// 非作用域默认插槽直接移除命名
if (slotName === `"${uni_shared_1.SLOT_DEFAULT_NAME}"`) {
(0, utils_1.removeAttribute)(node, 'name');
}
}
}
exports.rewriteSlot = rewriteSlot;
function parseVForIndexAlias(context) {
let { currentScope } = context;
while (currentScope) {
if ((0, transform_1.isVForScope)(currentScope) && !(0, transform_1.isScopedSlotVFor)(currentScope)) {
return currentScope.indexAlias;
}
currentScope = currentScope.parent;
}
}
function transformScopedSlotName(node, context) {
if (!context.miniProgram.slot.dynamicSlotNames) {
return;
}
const slotKey = parseScopedSlotKey(context);
if (!slotKey) {
return;
}
const nameProps = (0, compiler_core_1.findProp)(node, 'name');
if (nameProps && nameProps.type === compiler_core_1.NodeTypes.ATTRIBUTE && nameProps.value) {
const { props } = node;
props.splice(props.indexOf(nameProps), 1, createScopedSlotDirectiveNode(nameProps.value.content, slotKey, context));
}
}
function createScopedSlotDirectiveNode(name, slotKey, context) {
const dir = (0, uni_cli_shared_1.createBindDirectiveNode)('name', (0, utils_1.rewriteExpression)((0, compiler_core_1.createSimpleExpression)(`"${name}-"+` + slotKey), context)
.content);
// 存储原始的 slot 名称
dir.slotName = name;
return dir;
}
function parseVForKeyAlias(context) {
let { currentScope } = context;
const keys = [];
while (currentScope) {
if ((0, transform_1.isVForScope)(currentScope) && !(0, transform_1.isScopedSlotVFor)(currentScope)) {
keys.push(currentScope.keyAlias);
}
currentScope = currentScope.parent;
}
return keys;
}
exports.parseVForKeyAlias = parseVForKeyAlias;
function parseVForIndexes(context) {
let { currentScope } = context;
const indexes = [];
while (currentScope) {
if ((0, transform_1.isVForScope)(currentScope) && !(0, transform_1.isScopedSlotVFor)(currentScope)) {
indexes.push(currentScope.indexAlias);
}
currentScope = currentScope.parent;
}
return indexes;
}
function parseSlotKeyByVForIndexes(indexes) {
return indexes.reverse().join(`+'-'+`);
}
function parseScopedSlotKey(context) {
const indexes = parseVForIndexes(context);
const inFor = !!indexes.length;
if (inFor) {
return parseSlotKeyByVForIndexes(indexes);
}
}
function transformProperty(dir, _) {
if ((0, uni_cli_shared_1.isDirectiveNode)(dir)) {
if (!dir.arg || !dir.exp) {
return;
}
const isStaticArg = dir.arg.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION && dir.arg.isStatic;
if (isStaticArg) {
return `${dir.arg.content}:${(0, codegen_1.genExpr)(dir.exp)}`;
}
return `[${(0, codegen_1.genExpr)(dir.arg)}||'']:${(0, codegen_1.genExpr)(dir.exp)}`;
}
if (dir.value) {
return `${dir.name}:${(0, codegen_1.genExpr)(dir.value)}`;
}
}
@@ -0,0 +1,6 @@
import { type AttributeNode, type DirectiveNode } from '@vue/compiler-core';
import type { TransformContext } from '../transform';
export declare function isStyleBinding({ arg, exp }: DirectiveNode): boolean | undefined;
export declare function findStaticStyleIndex(props: (AttributeNode | DirectiveNode)[]): number;
export declare function rewriteStyle(index: number, styleBindingProp: DirectiveNode, props: (AttributeNode | DirectiveNode)[], virtualHost: boolean, context: TransformContext, elementId?: string): void;
export declare function createVirtualHostStyle(props: (AttributeNode | DirectiveNode)[], context: TransformContext): DirectiveNode;
@@ -0,0 +1,189 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createVirtualHostStyle = exports.rewriteStyle = exports.findStaticStyleIndex = exports.isStyleBinding = void 0;
const types_1 = require("@babel/types");
const compiler_core_1 = require("@vue/compiler-core");
const shared_1 = require("@vue/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 utils_1 = require("./utils");
function isStyleBinding({ arg, exp }) {
return (arg && arg.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION && arg.content === 'style');
}
exports.isStyleBinding = isStyleBinding;
function findStaticStyleIndex(props) {
return props.findIndex((prop) => prop.name === 'style');
}
exports.findStaticStyleIndex = findStaticStyleIndex;
function rewriteStyle(index, styleBindingProp, props, virtualHost, context, elementId) {
const expr = styleBindingProp.exp
? (0, ast_1.parseExpr)(styleBindingProp.exp, context)
: undefined;
let styleBidingExpr = expr;
if (expr) {
if ((0, types_1.isObjectExpression)(expr)) {
styleBidingExpr = createStyleBindingByObjectExpression(rewriteStyleObjectExpression(expr, styleBindingProp.loc, context));
}
else if ((0, types_1.isArrayExpression)(expr)) {
styleBidingExpr = createStyleBindingByArrayExpression(rewriteStyleArrayExpression(expr, context));
}
else {
// 在 x 中,如果有 id 且不支持 setStyle
if (elementId &&
context.isX &&
!context.miniProgram.filter?.setStyle &&
(0, uni_cli_shared_1.isCompoundExpressionNode)(styleBindingProp.exp)) {
rewriteStyleExpression(styleBindingProp.exp, context);
styleBidingExpr = (0, ast_1.parseExpr)(`$eS[${elementId}]`, context);
}
else {
styleBidingExpr = (0, ast_1.parseExpr)(rewriteStyleExpression(styleBindingProp.exp, context).content, context);
}
}
if (!styleBidingExpr) {
return;
}
}
else if (!virtualHost) {
return;
}
const staticStylePropIndex = findStaticStyleIndex(props);
if (staticStylePropIndex > -1) {
const staticStyle = props[staticStylePropIndex].value
.content;
if (staticStyle.trim()) {
if (styleBidingExpr) {
if (index > staticStylePropIndex) {
styleBidingExpr = (0, types_1.binaryExpression)('+', addSemicolon((0, types_1.stringLiteral)(staticStyle)), styleBidingExpr);
}
else {
styleBidingExpr = (0, types_1.binaryExpression)('+', addSemicolon(styleBidingExpr), (0, types_1.stringLiteral)(staticStyle));
}
}
else {
styleBidingExpr = (0, types_1.stringLiteral)(staticStyle);
}
}
}
if (virtualHost) {
styleBidingExpr = styleBidingExpr
? (0, types_1.binaryExpression)('+', addSemicolon(styleBidingExpr), (0, types_1.identifier)(utils_1.VIRTUAL_HOST_STYLE))
: (0, types_1.identifier)(utils_1.VIRTUAL_HOST_STYLE);
}
styleBindingProp.exp = (0, compiler_core_1.createSimpleExpression)((0, codegen_1.genBabelExpr)(styleBidingExpr));
}
exports.rewriteStyle = rewriteStyle;
function createVirtualHostStyle(props, context) {
const styleBindingProp = (0, uni_cli_shared_1.createBindDirectiveNode)('style', '');
delete styleBindingProp.exp;
rewriteStyle(0, styleBindingProp, props, true, context);
return styleBindingProp;
}
exports.createVirtualHostStyle = createVirtualHostStyle;
function rewriteStyleExpression(expr, context) {
return (0, utils_1.rewriteExpression)((0, compiler_core_1.createCompoundExpression)([
context.helperString(runtimeHelpers_1.STRINGIFY_STYLE) + '(',
expr,
')',
]), context);
}
function rewriteStyleArrayExpression(expr, context) {
expr.elements.forEach((prop, index) => {
if (!(0, types_1.isStringLiteral)(prop)) {
const code = (0, codegen_1.genBabelExpr)((0, types_1.arrayExpression)([(0, types_1.isSpreadElement)(prop) ? prop.argument : prop]));
expr.elements[index] = (0, types_1.identifier)(rewriteStyleExpression((0, compiler_core_1.createSimpleExpression)(code.slice(1, -1), false), context).content);
}
});
return expr;
}
function rewriteStyleObjectExpression(expr, loc, context) {
expr.properties.forEach((prop, index) => {
if ((0, types_1.isSpreadElement)(prop)) {
// <view :style="{...obj}"/>
// <view style="{{a}}"/>
const newExpr = (0, utils_1.rewriteSpreadElement)(runtimeHelpers_1.STRINGIFY_STYLE, prop, loc, context);
if (newExpr) {
prop.argument = newExpr;
}
}
else if ((0, types_1.isObjectProperty)(prop)) {
const { key, value, computed } = prop;
if (!(0, types_1.isPrivateName)(key)) {
if (computed) {
// {[handle(computedKey)]:1} => {[a]:1}
const newExpr = (0, utils_1.rewirteWithHelper)(runtimeHelpers_1.HYPHENATE, key, loc, context);
if (newExpr) {
prop.key = newExpr;
}
}
else {
// {fontSize:'15px'} => {'font-size':'15px'}
prop.key = (0, ast_1.parseStringLiteral)(key);
prop.key.value = (0, shared_1.hyphenate)(prop.key.value) + ':';
}
// {fontSize:`${fontSize}px`} => {'font-size':a}
if ((0, utils_1.isStaticLiteral)(value)) {
return;
}
else {
const newExpr = (0, utils_1.parseExprWithRewrite)((0, codegen_1.genBabelExpr)(value), loc, context, value);
if (newExpr) {
prop.value = newExpr;
}
}
}
}
});
return expr;
}
function addSemicolon(expr) {
return createBinaryExpression(expr, (0, types_1.stringLiteral)(';'));
}
function createBinaryExpression(left, right) {
return (0, types_1.binaryExpression)('+', left, right);
}
function createStyleBindingByArrayExpression(expr) {
let result;
function concat(expr) {
if (!result) {
result = expr;
}
else {
result = createBinaryExpression(addSemicolon(result), expr);
}
}
expr.elements.forEach((prop) => {
if ((0, types_1.isStringLiteral)(prop) || (0, types_1.isIdentifier)(prop)) {
concat(prop);
}
});
return result;
}
function createStyleBindingByObjectExpression(expr) {
let result;
function concat(expr) {
if (!result) {
result = expr;
}
else {
result = createBinaryExpression(addSemicolon(result), expr);
}
}
expr.properties.forEach((prop) => {
if ((0, types_1.isSpreadElement)(prop)) {
concat(prop.argument);
}
else if ((0, types_1.isObjectProperty)(prop)) {
const { key, value } = prop;
if (!(0, types_1.isPrivateName)(key)) {
const expr = createBinaryExpression((0, types_1.isStringLiteral)(key)
? key // 之前已经补充了:
: createBinaryExpression(key, (0, types_1.stringLiteral)(':')), value);
concat(expr);
}
}
});
return result;
}
@@ -0,0 +1,2 @@
import type { NodeTransform } from '../transform';
export declare const transformTag: NodeTransform;
+17
View File
@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformTag = void 0;
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const compiler_core_1 = require("@vue/compiler-core");
const transformTag = (node, _) => {
if (!(0, uni_cli_shared_1.isElementNode)(node) ||
(_ && _.isCustomElement && _.isCustomElement(node.tag))) {
return;
}
const newTag = uni_cli_shared_1.HTML_TO_MINI_PROGRAM_TAGS[node.tag];
if (newTag) {
node.tag = newTag;
node.tagType = compiler_core_1.ElementTypes.ELEMENT;
}
};
exports.transformTag = transformTag;
@@ -0,0 +1,3 @@
import { type ElementNode } from '@vue/compiler-core';
import type { TransformContext } from '../transform';
export declare function rewriteId(node: ElementNode, context: TransformContext): void;
@@ -0,0 +1,142 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.rewriteId = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const runtimeHelpers_1 = require("../runtimeHelpers");
const utils_1 = require("./utils");
const transformSlot_1 = require("./transformSlot");
const transformRef_1 = require("./transformRef");
const shared_1 = require("@vue/shared");
const builtInCustomElements = ['uni-cloud-db-element'];
const builtInComponents = ['unicloud-db'];
function rewriteId(node, context) {
const isUniElement = !(0, uni_cli_shared_1.isUserComponent)(node, context);
const origTagName = node.tag;
const isBuiltInComponent = !isUniElement && builtInComponents.includes(origTagName);
const userComponent = !(isUniElement || isBuiltInComponent);
if (userComponent) {
// TODO 目前不对用户的自定义组件支持 id 查询 UniElement
// 后续要做的话,需要考虑自定义组件内部的单节点或多节点
return;
}
const isBuiltInCustomElement = builtInCustomElements.includes(origTagName);
if (isUniElement) {
// 将内置的自定义元素转换为 view
if (isBuiltInCustomElement) {
node.props.unshift((0, uni_cli_shared_1.createAttributeNode)(utils_1.ATTR_ELEMENT_TAG, origTagName));
node.tag = 'view';
}
}
// 内置组件使用了 ref,没有 id 时,自动补充一个
const refProp = (0, compiler_core_1.findProp)(node, utils_1.ATTR_VUE_REF) || (0, compiler_core_1.findProp)(node, 'ref');
if (refProp && !(0, compiler_core_1.findProp)(node, 'id')) {
if (context.inVFor) {
// v-for 中的 ref 需要使用 v-for 的 key 作为 id
const keyAlias = (0, transformSlot_1.parseVForKeyAlias)(context);
// 微信小程序元素id必须以字母开头,所以hashId不能放到前边,它可能是数字开头
const id = 'r' + context.elementRefIndex++ + '-' + context.hashId + '-';
node.props.push((0, uni_cli_shared_1.createBindDirectiveNode)('id', (0, compiler_core_1.createCompoundExpression)([`'${id}'+`, keyAlias.join(`+'-'+`)])));
}
else {
const id = 'r' + context.elementRefIndex++ + '-' + context.hashId;
node.props.push((0, uni_cli_shared_1.createAttributeNode)('id', id));
}
}
const idProp = (0, compiler_core_1.findProp)(node, 'id');
if (!idProp) {
return;
}
let idOptions = origTagName;
if (isBuiltInComponent || isBuiltInCustomElement) {
idOptions = {
name: origTagName,
type: isBuiltInComponent
? 1 /* SetUniElementIdTagType.BuiltInComponent */
: 2 /* SetUniElementIdTagType.BuiltInRootElement */,
};
}
let idExprNode;
// id="test" => :id="setUniElementId('test')"
// 目前标签名有隐患,可能传入的是自定义组件名称
if ((0, uni_cli_shared_1.isAttributeNode)(idProp)) {
if (!idProp.value) {
return;
}
idExprNode = `'${idProp.value.content}'`;
node.props.push((0, uni_cli_shared_1.createBindDirectiveNode)(utils_1.ATTR_ELEMENT_ID, (0, compiler_core_1.createCompoundExpression)([
context.helperString(runtimeHelpers_1.SET_UNI_ELEMENT_ID) + '(',
idExprNode,
',',
(0, shared_1.isString)(idOptions) ? `'${idOptions}'` : JSON.stringify(idOptions),
parseUniElementRefCode(node, context),
')',
])));
}
else if (idProp.exp) {
idExprNode = idProp.exp;
const idPropIndex = node.props.indexOf(idProp);
// :id="a" => :id="setUniElementId(a)"
node.props.splice(idPropIndex, 1, (0, uni_cli_shared_1.createBindDirectiveNode)('id', (0, compiler_core_1.createCompoundExpression)([
context.helperString(runtimeHelpers_1.SET_UNI_ELEMENT_ID) + '(',
idExprNode,
',',
(0, shared_1.isString)(idOptions) ? `'${idOptions}'` : JSON.stringify(idOptions),
parseUniElementRefCode(node, context),
')',
])));
}
if (context.miniProgram.filter?.setStyle) {
// 支持通过filter来设置style
node.props.push((0, uni_cli_shared_1.createBindDirectiveNode)((0, utils_1.filterObserverName)(utils_1.ATTR_SET_ELEMENT_STYLE), (0, utils_1.filterName)(utils_1.FILTER_SET_ELEMENT_STYLE)));
node.props.push((0, uni_cli_shared_1.createBindDirectiveNode)(utils_1.ATTR_SET_ELEMENT_STYLE, ''));
if (!context.autoImportFilters.find((filter) => filter.name === utils_1.FILTER_MODULE_NAME)) {
context.autoImportFilters.push({
name: utils_1.FILTER_MODULE_NAME,
id: utils_1.FILTER_MODULE_FILE_NAME,
type: 'filter',
});
}
}
else {
// 如果没有动态绑定 style,则创建一个新的
const styleProp = (0, compiler_core_1.findProp)(node, 'style', true, true);
if (!styleProp) {
node.props.push((0, uni_cli_shared_1.createBindDirectiveNode)('style', (0, compiler_core_1.createCompoundExpression)([
context.helperString(runtimeHelpers_1.SET_UNI_ELEMENT_STYLE) + '(',
idExprNode,
')',
])));
}
else {
// 传递已绑定的 style
styleProp.exp = (0, compiler_core_1.createCompoundExpression)([
context.helperString(runtimeHelpers_1.SET_UNI_ELEMENT_STYLE) + '(',
idExprNode,
',',
styleProp.exp,
')',
]);
}
}
}
exports.rewriteId = rewriteId;
function parseUniElementRefCode(node, context) {
const refProp = (0, compiler_core_1.findProp)(node, utils_1.ATTR_VUE_REF) || (0, compiler_core_1.findProp)(node, 'ref');
if (!refProp) {
return '';
}
const { code, refKey } = (0, transformRef_1.parseRefCode)(refProp, context);
const opts = {};
if (refKey) {
opts.k = refKey;
}
if (context.inVFor) {
opts.f = 1;
}
const children = [',', code];
if (Object.keys(opts).length) {
children.push(',', JSON.stringify(opts));
}
return (0, compiler_core_1.createCompoundExpression)(children);
}
+35
View File
@@ -0,0 +1,35 @@
import { type Expression, type Identifier, type MemberExpression, type Node, type SpreadElement } from '@babel/types';
import { type ElementNode, type ExpressionNode, type SimpleExpressionNode, type SourceLocation, type TransformContext as VueTransformContext } from '@vue/compiler-core';
import type { CodegenScope } from '../options';
import { type TransformContext } from '../transform';
export declare const ATTR_VUE_ID = "u-i";
export declare const ATTR_VUE_SLOTS = "u-s";
export declare const ATTR_VUE_PROPS = "u-p";
export declare const ATTR_VUE_REF: string;
export declare const ATTR_VUE_REF_IN_FOR: string;
export declare const ATTR_COM_TYPE = "u-t";
export declare const ATTR_ELEMENT_ID = "u-e";
export declare const ATTR_ELEMENT_TAG = "u-t";
export declare const ATTR_SET_ELEMENT_STYLE = "eS";
export declare const FILTER_MODULE_NAME = "uV";
export declare const FILTER_MODULE_FILE_NAME = "uniView";
export declare const FILTER_SET_ELEMENT_STYLE = "sS";
export declare const SCOPED_SLOT_IDENTIFIER = "__SCOPED_SLOT__";
export declare const VIRTUAL_HOST_STYLE = "virtualHostStyle";
export declare const VIRTUAL_HOST_CLASS = "virtualHostClass";
export declare function filterObserverName(name: string): string;
export declare function filterName(name: string): string;
export declare function rewriteSpreadElement(name: symbol, expr: SpreadElement, loc: SourceLocation, context: TransformContext): Identifier | MemberExpression | undefined;
export declare function rewirteWithHelper(name: symbol, expr: Expression, loc: SourceLocation, context: TransformContext): Identifier | MemberExpression | undefined;
export declare function parseExprWithRewrite(code: string, loc: SourceLocation, context: TransformContext, node?: Expression): Identifier | MemberExpression | undefined;
export declare function parseExprWithRewriteClass(code: string, loc: SourceLocation, context: TransformContext, node: Expression): Identifier | MemberExpression | undefined;
export declare function rewriteExpressionWithoutProperty(node: ExpressionNode, context: TransformContext, babelNode?: Expression, scope?: CodegenScope): SimpleExpressionNode;
export declare function rewriteExpression(node: ExpressionNode, context: TransformContext | VueTransformContext, babelNode?: Expression, scope?: CodegenScope, { property, ignoreLiteral, referencedScope, }?: {
property: boolean;
ignoreLiteral: boolean;
referencedScope?: CodegenScope;
}): SimpleExpressionNode;
export declare function findReferencedScope(node: Expression, scope: CodegenScope, findReferenced?: boolean): CodegenScope;
export declare function isReferencedByIds(node: Expression, knownIds: string[]): boolean;
export declare function isStaticLiteral(value: Node | null | undefined): boolean;
export declare function removeAttribute(node: ElementNode, name: string): void;
+151
View File
@@ -0,0 +1,151 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.removeAttribute = exports.isStaticLiteral = exports.isReferencedByIds = exports.findReferencedScope = exports.rewriteExpression = exports.rewriteExpressionWithoutProperty = exports.parseExprWithRewriteClass = exports.parseExprWithRewrite = exports.rewirteWithHelper = exports.rewriteSpreadElement = exports.filterName = exports.filterObserverName = exports.VIRTUAL_HOST_CLASS = exports.VIRTUAL_HOST_STYLE = exports.SCOPED_SLOT_IDENTIFIER = exports.FILTER_SET_ELEMENT_STYLE = exports.FILTER_MODULE_FILE_NAME = exports.FILTER_MODULE_NAME = exports.ATTR_SET_ELEMENT_STYLE = exports.ATTR_ELEMENT_TAG = exports.ATTR_ELEMENT_ID = exports.ATTR_COM_TYPE = exports.ATTR_VUE_REF_IN_FOR = exports.ATTR_VUE_REF = exports.ATTR_VUE_PROPS = exports.ATTR_VUE_SLOTS = exports.ATTR_VUE_ID = void 0;
const types_1 = require("@babel/types");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const compiler_core_1 = require("@vue/compiler-core");
const estree_walker_1 = require("estree-walker");
const ast_1 = require("../ast");
const codegen_1 = require("../codegen");
const transform_1 = require("../transform");
// v-i,v-s 不能在 quickapp-webview 中使用,估计是内部处理成了指令之类的
exports.ATTR_VUE_ID = 'u-i';
exports.ATTR_VUE_SLOTS = 'u-s';
exports.ATTR_VUE_PROPS = 'u-p';
exports.ATTR_VUE_REF = 'u-' + uni_cli_shared_1.VUE_REF;
exports.ATTR_VUE_REF_IN_FOR = 'u-' + uni_cli_shared_1.VUE_REF_IN_FOR;
exports.ATTR_COM_TYPE = 'u-t';
exports.ATTR_ELEMENT_ID = 'u-e';
exports.ATTR_ELEMENT_TAG = 'u-t';
exports.ATTR_SET_ELEMENT_STYLE = 'eS'; // 不能使用连字符e-s
exports.FILTER_MODULE_NAME = 'uV'; // uniView
exports.FILTER_MODULE_FILE_NAME = 'uniView';
exports.FILTER_SET_ELEMENT_STYLE = 'sS'; // setStyle
exports.SCOPED_SLOT_IDENTIFIER = '__SCOPED_SLOT__';
exports.VIRTUAL_HOST_STYLE = 'virtualHostStyle';
exports.VIRTUAL_HOST_CLASS = 'virtualHostClass';
function filterObserverName(name) {
return 'change:' + name;
}
exports.filterObserverName = filterObserverName;
function filterName(name) {
return exports.FILTER_MODULE_NAME + '.' + name;
}
exports.filterName = filterName;
function rewriteSpreadElement(name, expr, loc, context) {
return rewirteWithHelper(name, expr.argument, loc, context);
}
exports.rewriteSpreadElement = rewriteSpreadElement;
function rewirteWithHelper(name, expr, loc, context) {
return parseExprWithRewrite(context.helperString(name) + '(' + (0, codegen_1.genBabelExpr)(expr) + ')', loc, context);
}
exports.rewirteWithHelper = rewirteWithHelper;
function parseExprWithRewrite(code, loc, context, node) {
return (0, ast_1.parseExpr)(rewriteExpression((0, compiler_core_1.createSimpleExpression)(code, false, loc), context, node), context);
}
exports.parseExprWithRewrite = parseExprWithRewrite;
function parseExprWithRewriteClass(code, loc, context, node) {
// a?1:0
return (0, ast_1.parseExpr)(rewriteExpression((0, compiler_core_1.createSimpleExpression)(code, false, loc), context, !(0, ast_1.isUndefined)(node)
? (0, types_1.conditionalExpression)(node, (0, types_1.numericLiteral)(1), (0, types_1.stringLiteral)(''))
: node), context);
}
exports.parseExprWithRewriteClass = parseExprWithRewriteClass;
function rewriteExpressionWithoutProperty(node, context, babelNode, scope = context.currentScope) {
return rewriteExpression(node, context, babelNode, scope, {
property: false,
ignoreLiteral: false,
});
}
exports.rewriteExpressionWithoutProperty = rewriteExpressionWithoutProperty;
function rewriteExpression(node, context, babelNode, scope = context.currentScope, { property, ignoreLiteral, referencedScope, } = {
property: true,
ignoreLiteral: false,
}) {
if (node.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION && node.isStatic) {
return node;
}
if (!babelNode) {
const code = (0, codegen_1.genExpr)(node);
babelNode = (0, ast_1.parseExpr)(code, context, node);
if (!babelNode) {
return (0, compiler_core_1.createSimpleExpression)(code);
}
}
if (!ignoreLiteral && isStaticLiteral(babelNode)) {
return node;
}
if ((0, ast_1.isUndefined)(babelNode)) {
return (0, compiler_core_1.createSimpleExpression)('undefined', false, node.loc);
}
// wxs 等表达式
if (context.filters?.length) {
if (isReferencedByIds(babelNode, context.filters)) {
return (0, compiler_core_1.createSimpleExpression)((0, codegen_1.genExpr)(node), false, node.loc);
}
}
referencedScope = referencedScope || findReferencedScope(babelNode, scope);
const id = referencedScope.id.next();
if (property) {
referencedScope.properties.push((0, types_1.objectProperty)((0, types_1.identifier)(id), babelNode));
}
// 在 v-for 中包含的 v-if 块,所有变量需要补充当前 v-for value 前缀
if ((0, transform_1.isVIfScope)(referencedScope)) {
if ((0, transform_1.isVForScope)(referencedScope.parentScope)) {
return (0, compiler_core_1.createSimpleExpression)(referencedScope.parentScope.valueAlias + '.' + id);
}
return (0, compiler_core_1.createSimpleExpression)(id);
}
else if ((0, transform_1.isVForScope)(referencedScope)) {
return (0, compiler_core_1.createSimpleExpression)(referencedScope.valueAlias + '.' + id);
}
return (0, compiler_core_1.createSimpleExpression)(id);
}
exports.rewriteExpression = rewriteExpression;
function findReferencedScope(node, scope, findReferenced = true) {
if ((0, transform_1.isVIfScope)(scope)) {
return scope;
}
else if ((0, transform_1.isVForScope)(scope)) {
if (!findReferenced) {
return scope;
}
if (isReferencedByIds(node, scope.locals)) {
return scope;
}
return findReferencedScope(node, scope.parent, findReferenced);
}
return scope;
}
exports.findReferencedScope = findReferencedScope;
function isReferencedByIds(node, knownIds) {
let referenced = false;
(0, estree_walker_1.walk)(node, {
enter(node, parent) {
if (referenced) {
return this.skip();
}
if (!(0, types_1.isIdentifier)(node)) {
return;
}
if (knownIds.includes(node.name) &&
(!parent || (0, types_1.isReferenced)(node, parent))) {
referenced = true;
return this.skip();
}
},
});
return referenced;
}
exports.isReferencedByIds = isReferencedByIds;
function isStaticLiteral(value) {
return (0, types_1.isLiteral)(value) && !(0, types_1.isTemplateLiteral)(value);
}
exports.isStaticLiteral = isStaticLiteral;
function removeAttribute(node, name) {
const index = node.props.findIndex((prop) => prop.name === name);
if (index > -1) {
node.props.splice(index, 1);
}
}
exports.removeAttribute = removeAttribute;
+2
View File
@@ -0,0 +1,2 @@
import type { DirectiveTransform } from '../transform';
export declare const transformBind: DirectiveTransform;
+49
View File
@@ -0,0 +1,49 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformBind = void 0;
const shared_1 = require("@vue/shared");
const compiler_core_1 = require("@vue/compiler-core");
const errors_1 = require("../errors");
const transformBind = (dir, _node, context) => {
const { exp, modifiers, loc } = dir;
const arg = dir.arg;
if (arg.type !== compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
arg.children.unshift(`(`);
arg.children.push(`) || ""`);
}
else if (!arg.isStatic) {
arg.content = `${arg.content} || ""`;
}
// .sync is replaced by v-model:arg
if (modifiers.includes('camel')) {
if (arg.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
if (arg.isStatic) {
arg.content = (0, shared_1.camelize)(arg.content);
}
else {
// arg.content = `${context.helperString(CAMELIZE)}(${arg.content})`
}
}
else {
// arg.children.unshift(`${context.helperString(CAMELIZE)}(`)
// arg.children.push(`)`)
}
}
if (modifiers.includes('prop')) {
context[context.isX ? 'onError' : 'onWarn']((0, errors_1.createMPCompilerError)(4 /* MPErrorCodes.X_V_BIND_MODIFIER_PROP */, loc));
}
if (modifiers.includes('attr')) {
context[context.isX ? 'onError' : 'onWarn']((0, errors_1.createMPCompilerError)(5 /* MPErrorCodes.X_V_BIND_MODIFIER_ATTR */, loc));
}
if (!exp ||
(exp.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION && !exp.content.trim())) {
context.onError((0, compiler_core_1.createCompilerError)(compiler_core_1.ErrorCodes.X_V_BIND_NO_EXPRESSION, loc));
return {
props: [(0, compiler_core_1.createObjectProperty)(arg, (0, compiler_core_1.createSimpleExpression)('', true, loc))],
};
}
return {
props: [(0, compiler_core_1.createObjectProperty)(arg, exp)],
};
};
exports.transformBind = transformBind;
+37
View File
@@ -0,0 +1,37 @@
import { type ElementNode, ElementTypes, type ExpressionNode, type SimpleExpressionNode } from '@vue/compiler-core';
import { type NodeTransform, type TransformContext } from '../transform';
import { type Expression, type Identifier, type Pattern, type RestElement } from '@babel/types';
import type { CodegenScope, CodegenVForScope } from '../options';
export type VForOptions = Omit<ForParseResult, 'tagType'> & {
sourceExpr?: Expression;
sourceAlias: string;
sourceCode: string;
valueCode: string;
valueExpr: Identifier | Pattern | RestElement;
valueAlias: string;
keyCode: string;
keyExpr: Identifier | Pattern | RestElement;
keyAlias: string;
indexCode: string;
indexExpr: Identifier | Pattern | RestElement;
indexAlias: string;
node: ElementNode;
};
export type ForElementNode = ElementNode & {
vFor: VForOptions & {
source: ExpressionNode;
};
};
export declare function isForElementNode(node: unknown): node is ForElementNode;
export declare const transformFor: NodeTransform;
export declare function parseVForScope(currentScope: CodegenScope): CodegenVForScope | undefined;
export interface ForParseResult {
source: ExpressionNode;
value: ExpressionNode;
key: ExpressionNode;
index: ExpressionNode;
tagType: ElementTypes;
}
export declare function parseForExpression(input: SimpleExpressionNode, context: TransformContext): ForParseResult | undefined;
export declare function createForLoopParams({ value, key, index }: ForParseResult, memoArgs?: ExpressionNode[]): ExpressionNode[];
export declare function createVForArrowFunctionExpression({ valueExpr, keyExpr, indexExpr, properties, }: CodegenVForScope): import("@babel/types").ArrowFunctionExpression;
+303
View File
@@ -0,0 +1,303 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createVForArrowFunctionExpression = exports.createForLoopParams = exports.parseForExpression = exports.parseVForScope = exports.transformFor = exports.isForElementNode = void 0;
const shared_1 = require("@vue/shared");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const compiler_core_1 = require("@vue/compiler-core");
const ast_1 = require("../ast");
const transform_1 = require("../transform");
const transformExpression_1 = require("./transformExpression");
const codegen_1 = require("../codegen");
const types_1 = require("@babel/types");
const utils_1 = require("./utils");
const runtimeHelpers_1 = require("../runtimeHelpers");
const vSlot_1 = require("./vSlot");
function isForElementNode(node) {
return !!node.vFor;
}
exports.isForElementNode = isForElementNode;
exports.transformFor = (0, transform_1.createStructuralDirectiveTransform)('for', (node, dir, context) => {
if (!dir.exp) {
context.onError((0, compiler_core_1.createCompilerError)(compiler_core_1.ErrorCodes.X_V_FOR_NO_EXPRESSION, dir.loc));
return;
}
const parseResult = parseForExpression(dir.exp, context);
if (!parseResult) {
context.onError((0, compiler_core_1.createCompilerError)(compiler_core_1.ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION, dir.loc));
return;
}
parseResult.tagType = node.tagType;
const { addIdentifiers, removeIdentifiers } = context;
const { source, value, key, index } = parseResult;
if (context.prefixIdentifiers) {
addIdentifiers(value);
addIdentifiers(key);
addIdentifiers(index);
}
const { currentScope: parentScope, scopes, popScope } = context;
const sourceExpr = (0, ast_1.parseExpr)(source, context);
const valueCode = (0, codegen_1.genExpr)(value);
const valueExpr = (0, ast_1.parseParam)(valueCode, context, value);
const valueAlias = parseAlias(valueExpr, valueCode, 'v' + scopes.vFor);
const keyCode = (0, codegen_1.genExpr)(key);
const keyExpr = (0, ast_1.parseParam)(keyCode, context, key);
const keyAlias = parseAlias(keyExpr, keyCode, 'k' + scopes.vFor);
const indexCode = (0, codegen_1.genExpr)(index);
const indexExpr = (0, ast_1.parseParam)(indexCode, context, index);
const indexAlias = parseAlias(indexExpr, indexCode, 'i' + scopes.vFor);
// 先占位 vFor,后续更新 cloneSourceExpr 为 CallExpression
const cloneSourceExpr = (0, types_1.cloneNode)(sourceExpr, false);
const sourceAliasReferencedScope = (0, utils_1.findReferencedScope)(cloneSourceExpr, context.currentScope,
// vFor 嵌套时,始终保持嵌套关系,issues/3263
false);
// 寻找子节点中 if 指令作用域
const vIfReferencedScope = findVIfReferencedScope(node, context.currentScope, context);
// 取最近的作用域
const referencedScope = vIfReferencedScope &&
context.getScopeIndex(vIfReferencedScope) >
context.getScopeIndex(sourceAliasReferencedScope)
? vIfReferencedScope
: sourceAliasReferencedScope;
const sourceAlias = (0, utils_1.rewriteExpression)(source, context, cloneSourceExpr, parentScope,
// 强制 rewrite,因为即使是字符串,数字,也要走 vFor 函数
{
property: true,
ignoreLiteral: true,
referencedScope,
}).content;
const sourceCode = `{{${sourceAlias}}}`;
const vForData = {
source,
sourceExpr,
sourceAlias,
sourceCode,
value,
valueCode,
valueExpr,
valueAlias,
key,
keyCode,
keyExpr,
keyAlias,
index,
indexCode,
indexExpr,
indexAlias,
node,
};
const vForScope = context.addVForScope({
...vForData,
locals: findVForLocals(parseResult),
});
const vFor = {
...vForData,
};
const isScopedSlot = (0, transform_1.isScopedSlotVFor)(vForScope);
node.vFor = vFor;
scopes.vFor++;
return () => {
scopes.vFor--;
if ((0, compiler_core_1.isTemplateNode)(node)) {
node.children.some((c) => {
if (c.type === compiler_core_1.NodeTypes.ELEMENT && !isForElementNode(c)) {
const key = (0, compiler_core_1.findProp)(c, 'key');
if (key) {
context.onError((0, compiler_core_1.createCompilerError)(compiler_core_1.ErrorCodes.X_V_FOR_TEMPLATE_KEY_PLACEMENT, key.loc));
return true;
}
}
});
}
if (context.prefixIdentifiers) {
value && removeIdentifiers(value);
key && removeIdentifiers(key);
index && removeIdentifiers(index);
}
(0, shared_1.extend)(clearExpr(cloneSourceExpr), isScopedSlot
? (0, vSlot_1.createVSlotCallExpression)(node
.slotComponent, vForScope, context)
: createVForCallExpression(vForScope, context));
popScope();
};
});
function clearExpr(expr) {
Object.keys(expr).forEach((key) => {
delete expr[key];
});
return expr;
}
function parseAlias(babelExpr, exprCode, fallback) {
if ((0, types_1.isIdentifier)(babelExpr)) {
return exprCode;
}
return fallback;
}
function parseVForScope(currentScope) {
while (currentScope) {
if ((0, transform_1.isVForScope)(currentScope) && !(0, transform_1.isScopedSlotVFor)(currentScope)) {
return currentScope;
}
currentScope = currentScope.parent;
}
}
exports.parseVForScope = parseVForScope;
function findVIfReferencedScope(node, currentScope, context) {
if (!currentScope) {
return;
}
const vForScope = parseVForScope(currentScope);
if (!vForScope) {
return;
}
if (!node.children.find((item) => checkVIfReferenced(item, vForScope, context))) {
return findVIfReferencedScope(node, currentScope.parent, context);
}
return vForScope;
}
function checkVIfReferenced(node, vForScope, context) {
if (!(0, uni_cli_shared_1.isElementNode)(node)) {
return false;
}
// 嵌套 for 不查找
if ((0, compiler_core_1.findDir)(node, 'for')) {
return false;
}
const ifDir = (0, compiler_core_1.findDir)(node, 'if');
if (ifDir) {
return checkDirReferenced(ifDir.exp, vForScope, context);
}
const elseIfDir = (0, compiler_core_1.findDir)(node, 'else-if');
if (elseIfDir) {
return checkDirReferenced(elseIfDir.exp, vForScope, context);
}
return !!node.children.find((item) => checkVIfReferenced(item, vForScope, context));
}
function checkDirReferenced(node, vForScope, context) {
if (node) {
const babelNode = (0, ast_1.parseExpr)(node, context);
if (babelNode && (0, utils_1.isReferencedByIds)(babelNode, vForScope.locals)) {
return true;
}
}
return false;
}
function findVForLocals({ value, key, index }) {
const ids = [];
if (value) {
findIds(value, ids);
}
if (key) {
findIds(key, ids);
}
if (index) {
findIds(index, ids);
}
return ids;
}
function findIds(exp, ids) {
if ((0, shared_1.isString)(exp)) {
ids.push(exp);
}
else if (exp.identifiers) {
exp.identifiers.forEach((id) => ids.push(id));
}
else if (exp.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
ids.push(exp.content);
}
}
const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;
const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;
const stripParensRE = /^\(|\)$/g;
function parseForExpression(input, context) {
const loc = input.loc;
const exp = input.content;
const inMatch = exp.match(forAliasRE);
if (!inMatch)
return;
const [, LHS, RHS] = inMatch;
const result = {
source: createAliasExpression(loc, RHS.trim(), exp.indexOf(RHS, LHS.length)),
value: (0, compiler_core_1.createSimpleExpression)('v' + context.scopes.vFor),
key: (0, compiler_core_1.createSimpleExpression)('k' + context.scopes.vFor),
index: (0, compiler_core_1.createSimpleExpression)('i' + context.scopes.vFor),
tagType: compiler_core_1.ElementTypes.ELEMENT,
};
if (context.prefixIdentifiers) {
result.source = (0, transformExpression_1.processExpression)(result.source, context);
}
let valueContent = LHS.trim().replace(stripParensRE, '').trim();
const trimmedOffset = LHS.indexOf(valueContent);
const iteratorMatch = valueContent.match(forIteratorRE);
if (iteratorMatch) {
valueContent = valueContent.replace(forIteratorRE, '').trim();
const keyContent = iteratorMatch[1].trim();
let keyOffset;
if (keyContent) {
keyOffset = exp.indexOf(keyContent, trimmedOffset + valueContent.length);
result.key = createAliasExpression(loc, keyContent, keyOffset);
if (context.prefixIdentifiers) {
result.key = (0, transformExpression_1.processExpression)(result.key, context, true);
}
}
if (iteratorMatch[2]) {
const indexContent = iteratorMatch[2].trim();
if (indexContent) {
result.index = createAliasExpression(loc, indexContent, exp.indexOf(indexContent, result.key
? keyOffset + keyContent.length
: trimmedOffset + valueContent.length));
if (context.prefixIdentifiers) {
result.index = (0, transformExpression_1.processExpression)(result.index, context, true);
}
}
}
}
if (valueContent) {
result.value = createAliasExpression(loc, valueContent, trimmedOffset);
if (context.prefixIdentifiers) {
result.value = (0, transformExpression_1.processExpression)(result.value, context, true);
}
}
return result;
}
exports.parseForExpression = parseForExpression;
function createAliasExpression(range, content, offset) {
return (0, compiler_core_1.createSimpleExpression)(content, false, (0, uni_cli_shared_1.getInnerRange)(range, offset, content.length));
}
function createForLoopParams({ value, key, index }, memoArgs = []) {
return createParamsList([value, key, index, ...memoArgs]);
}
exports.createForLoopParams = createForLoopParams;
function createParamsList(args) {
let i = args.length;
while (i--) {
if (args[i])
break;
}
return args
.slice(0, i + 1)
.map((arg, i) => arg || (0, compiler_core_1.createSimpleExpression)(`_`.repeat(i + 1), false));
}
function createVForCallExpression(vForScope, context) {
// let sourceExpr: Expression = vForScope.sourceExpr!
// if (isNumericLiteral(sourceExpr)) {
// sourceExpr = numericLiteralToArrayExpr((sourceExpr as NumericLiteral).value)
// }
return (0, types_1.callExpression)((0, types_1.identifier)(context.helperString(runtimeHelpers_1.V_FOR)), [
vForScope.sourceExpr,
createVForArrowFunctionExpression(vForScope),
]);
}
function createVForArrowFunctionExpression({ valueExpr, keyExpr, indexExpr, properties, }) {
const params = [];
if (valueExpr) {
params.push(valueExpr);
}
if (keyExpr) {
params.push(keyExpr);
}
if (indexExpr) {
params.push(indexExpr);
}
return (0, types_1.arrowFunctionExpression)(params, (0, types_1.blockStatement)([(0, types_1.returnStatement)((0, types_1.objectExpression)(properties))]));
}
exports.createVForArrowFunctionExpression = createVForArrowFunctionExpression;
+2
View File
@@ -0,0 +1,2 @@
import type { NodeTransform } from '../transform';
export declare const transformHtml: NodeTransform;
+35
View File
@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformHtml = void 0;
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const compiler_core_1 = require("@vue/compiler-core");
const transformHtml = (node, _) => {
if (!(0, uni_cli_shared_1.isElementNode)(node)) {
return;
}
const dir = (0, compiler_core_1.findDir)(node, 'html');
if (!dir) {
return;
}
// remove v-html
node.props.splice(node.props.indexOf(dir), 1);
if (node.tagType !== compiler_core_1.ElementTypes.ELEMENT) {
return;
}
node.isSelfClosing = false;
node.children = [createRichText(node, dir)];
};
exports.transformHtml = transformHtml;
function createRichText(node, dir) {
return {
tag: 'rich-text',
type: compiler_core_1.NodeTypes.ELEMENT,
tagType: compiler_core_1.ElementTypes.ELEMENT,
props: [(0, uni_cli_shared_1.createBindDirectiveNode)('nodes', dir.exp || '')],
isSelfClosing: true,
children: [],
codegenNode: undefined,
ns: node.ns,
loc: node.loc,
};
}
+13
View File
@@ -0,0 +1,13 @@
import { type DirectiveNode, type ElementNode, type IfNode } from '@vue/compiler-core';
import { type NodeTransform, type TransformContext } from '../transform';
interface IfOptions {
name: string;
condition?: string;
}
export type IfElementNode = ElementNode & {
vIf: IfOptions;
};
export declare function isIfElementNode(node: unknown): node is IfElementNode;
export declare const transformIf: NodeTransform;
export declare function processIf(node: ElementNode, dir: DirectiveNode, context: TransformContext, processCodegen?: (node: IfNode, branch: IfElementNode, isRoot: boolean) => (() => void) | undefined): (() => void) | undefined;
export {};
+139
View File
@@ -0,0 +1,139 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.processIf = exports.transformIf = exports.isIfElementNode = void 0;
const types_1 = require("@babel/types");
const compiler_core_1 = require("@vue/compiler-core");
const ast_1 = require("../ast");
const transform_1 = require("../transform");
const transformExpression_1 = require("./transformExpression");
const utils_1 = require("./utils");
function isIfElementNode(node) {
return !!node.vIf;
}
exports.isIfElementNode = isIfElementNode;
exports.transformIf = (0, transform_1.createStructuralDirectiveTransform)(/^(if|else|else-if)$/, (node, dir, context) => {
return processIf(node, dir, context, (ifNode, branch, isRoot) => {
const { currentScope: parentScope, popScope } = context;
const ifOptions = {
name: dir.name,
};
branch.vIf = ifOptions;
const condition = dir.exp ? (0, ast_1.parseExpr)(dir.exp, context) : undefined;
const vIfScope = context.addVIfScope({
name: dir.name,
condition,
});
if (condition) {
if (!(0, utils_1.isStaticLiteral)(condition)) {
ifOptions.condition = (0, utils_1.rewriteExpression)(dir.exp, context, condition, parentScope).content;
}
else {
ifOptions.condition = dir.exp.content;
}
}
return () => {
if (isRoot) {
parentScope.properties.push((0, ast_1.createVIfSpreadElement)(vIfScope));
}
else {
const vIfSpreadElement = findVIfSpreadElement(parentScope);
if (!vIfSpreadElement) {
popScope();
return context.onError((0, compiler_core_1.createCompilerError)(compiler_core_1.ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, node.loc));
}
let alternate = (0, ast_1.createObjectExpression)([]);
if (dir.name === 'else-if') {
alternate = (0, ast_1.createVIfConditionalExpression)(vIfScope);
}
else if (dir.name === 'else') {
alternate = (0, ast_1.createObjectExpression)(vIfScope.properties);
}
findVIfConditionalExpression(vIfSpreadElement.argument).alternate = alternate;
}
popScope();
};
});
});
function processIf(node, dir, context, processCodegen) {
if (dir.name !== 'else' &&
(!dir.exp || !dir.exp.content.trim())) {
const loc = dir.exp ? dir.exp.loc : node.loc;
context.onError((0, compiler_core_1.createCompilerError)(compiler_core_1.ErrorCodes.X_V_IF_NO_EXPRESSION, dir.loc));
dir.exp = (0, compiler_core_1.createSimpleExpression)(`true`, false, loc);
}
if (context.prefixIdentifiers && dir.exp) {
// dir.exp can only be simple expression because vIf transform is applied
// before expression transform.
dir.exp = (0, transformExpression_1.processExpression)(dir.exp, context);
}
if (dir.name === 'if') {
const ifNode = {
type: compiler_core_1.NodeTypes.IF,
loc: node.loc,
branches: [node],
};
context.replaceNode(ifNode);
if (processCodegen) {
return processCodegen(ifNode, node, true);
}
}
else {
// locate the adjacent v-if
const siblings = context.parent.children;
let i = siblings.indexOf(node);
while (i-- >= -1) {
const sibling = siblings[i];
if (sibling && sibling.type === compiler_core_1.NodeTypes.COMMENT) {
context.removeNode(sibling);
continue;
}
if (sibling &&
sibling.type === compiler_core_1.NodeTypes.TEXT &&
!sibling.content.trim().length) {
context.removeNode(sibling);
continue;
}
if (sibling && sibling.type === compiler_core_1.NodeTypes.IF) {
// Check if v-else was followed by v-else-if
if (dir.name === 'else-if' &&
sibling.branches[sibling.branches.length - 1].vIf.condition === undefined) {
context.onError((0, compiler_core_1.createCompilerError)(compiler_core_1.ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, node.loc));
}
// move the node to the if node's branches
context.removeNode();
sibling.branches.push(node);
const onExit = processCodegen &&
processCodegen(sibling, node, false);
// since the branch was removed, it will not be traversed.
// make sure to traverse here.
(0, transform_1.traverseNode)(node, context);
// call on exit
if (onExit)
onExit();
// make sure to reset currentNode after traversal to indicate this
// node has been removed.
context.currentNode = null;
}
else {
context.onError((0, compiler_core_1.createCompilerError)(compiler_core_1.ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, node.loc));
}
break;
}
}
}
exports.processIf = processIf;
function findVIfSpreadElement({ properties }) {
const len = properties.length;
for (let i = len - 1; i >= 0; i--) {
const prop = properties[i];
if ((0, types_1.isSpreadElement)(prop)) {
return prop;
}
}
}
function findVIfConditionalExpression(vIfConditionalExpression) {
if ((0, types_1.isConditionalExpression)(vIfConditionalExpression.alternate)) {
return findVIfConditionalExpression(vIfConditionalExpression.alternate);
}
return vIfConditionalExpression;
}
+2
View File
@@ -0,0 +1,2 @@
import { type DirectiveTransform } from '@vue/compiler-core';
export declare const transformModel: DirectiveTransform;
+210
View File
@@ -0,0 +1,210 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformModel = void 0;
const shared_1 = require("@vue/shared");
const compiler_core_1 = require("@vue/compiler-core");
const compiler_dom_1 = require("@vue/compiler-dom");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const runtimeHelpers_1 = require("../runtimeHelpers");
const codegen_1 = require("../codegen");
const vOn_1 = require("./vOn");
const transformModel = (dir, node, _context) => {
const context = _context;
const baseResult = (0, compiler_core_1.transformModel)(dir, node, _context);
// base transform has errors OR component v-model (only need props)
if (!baseResult.props.length || node.tagType === compiler_core_1.ElementTypes.COMPONENT) {
return transformComponentVModel(baseResult.props, node, context);
}
if (dir.arg) {
context.onError((0, compiler_dom_1.createDOMCompilerError)(compiler_dom_1.DOMErrorCodes.X_V_MODEL_ARG_ON_ELEMENT, dir.arg.loc));
}
function checkDuplicatedValue() {
const value = (0, compiler_core_1.findDir)(node, 'bind');
if (value && (0, compiler_core_1.isStaticArgOf)(value.arg, 'value')) {
context.onError((0, compiler_dom_1.createDOMCompilerError)(compiler_dom_1.DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE, value.loc));
}
}
const { tag } = node;
if (tag === 'input' || tag === 'textarea') {
checkDuplicatedValue();
}
else {
context.onError((0, compiler_dom_1.createDOMCompilerError)(compiler_dom_1.DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT, dir.loc));
}
if (dir.modifiers.length) {
const arg = dir.arg;
const modifiers = dir.modifiers
.map((m) => ((0, compiler_core_1.isSimpleIdentifier)(m) ? m : JSON.stringify(m)) + `: true`)
.join(`, `);
const modifiersKey = arg
? (0, compiler_core_1.isStaticExp)(arg)
? `${arg.content}Modifiers`
: (0, compiler_core_1.createCompoundExpression)([arg, ' + "Modifiers"'])
: `modelModifiers`;
baseResult.props.push((0, compiler_core_1.createObjectProperty)(modifiersKey, (0, compiler_core_1.createSimpleExpression)(`{ ${modifiers} }`, false, dir.loc, compiler_core_1.ConstantTypes.CAN_HOIST)));
}
return transformElementVModel(baseResult.props, node, context);
};
exports.transformModel = transformModel;
function findInputDirectiveNode(props) {
return props.find((prop) => prop.type === compiler_core_1.NodeTypes.DIRECTIVE &&
prop.name === 'on' &&
prop.arg?.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION &&
prop.arg.content === 'input');
}
function transformElementVModel(props, node, context) {
const dirs = transformVModel(props, node, context, {
isComponent: false,
binding: 'value',
event: 'input',
formatEventCode(code) {
return code.replace(/=\s\$event/g, `= $event.detail.value`);
},
});
if (dirs.length === 2) {
// 快手小程序的 input v-model 被转换到 data-e-o 中,补充到 data-e-o 中
const inputExp = findDatasetEventOpts(node);
if (inputExp) {
inputExp.children[2] = combineVOn(dirs[1].exp, inputExp.children[2], node, context);
dirs.length = 1;
}
else {
const inputDir = findInputDirectiveNode(node.props);
if (inputDir && inputDir.exp) {
// 合并到已有的 input 事件中
inputDir.exp = combineVOn(dirs[1].exp, inputDir.exp, node, context);
dirs.length = 1;
}
}
}
return { props: dirs };
}
/**
* {
* "type": 7,
* "name": "bind",
* "loc": {},
* "modifiers": [],
* "arg": {
* "type": 4,
* "loc": {},
* "content": "data-e-o",
* "isStatic": true,
* "constType": 3
* },
* "exp": {
* "type": 8,
* "loc": {},
* "children": ["{", {
* "type": 8,
* "loc": {},
* "children": ["'input'", ": ", {
* "type": 8,
* "loc": {},
* "children": ["_o(", {
* "type": 4,
* "content": "_ctx.input",
* "isStatic": false,
* "constType": 0,
* "loc": {}
* }, ")"]
* }, ","]
* }, "}"]
* }
* }
* @param node
* @returns
*/
function findDatasetEventOpts(node) {
const eventOptsProp = (0, compiler_core_1.findProp)(node, uni_cli_shared_1.ATTR_DATASET_EVENT_OPTS, true, false);
if (!eventOptsProp) {
return;
}
const { exp } = eventOptsProp;
if (exp?.type !== compiler_core_1.NodeTypes.COMPOUND_EXPRESSION) {
return;
}
for (let i = 0; i < exp.children.length; i++) {
const childExp = exp.children[i];
if ((0, shared_1.isSymbol)(childExp) || (0, shared_1.isString)(childExp)) {
continue;
}
if (childExp.type !== compiler_core_1.NodeTypes.COMPOUND_EXPRESSION) {
continue;
}
if (childExp.children[0] !== `'input'`) {
continue;
}
const inputExp = childExp.children[2];
if ((0, shared_1.isSymbol)(inputExp) ||
(0, shared_1.isString)(inputExp) ||
inputExp.type !== compiler_core_1.NodeTypes.COMPOUND_EXPRESSION) {
continue;
}
return childExp;
}
}
function parseVOn(exp, context) {
return (0, codegen_1.genExpr)(exp).slice(context.helperString(runtimeHelpers_1.V_ON).length + 1, -1);
}
function combineVOn(exp1, exp2, node, context) {
return (0, vOn_1.wrapperVOn)((0, compiler_core_1.createCompoundExpression)([
`[`,
parseVOn(exp1, context),
',',
parseVOn(exp2, context),
`]`,
]), node, context);
}
function transformComponentVModel(props, node, context) {
return {
props: transformVModel(props, node, context, {
isComponent: true,
formatEventCode(code) {
return code;
},
}),
};
}
function transformVModel(props, node, context, { isComponent, binding, event, formatEventCode, }) {
if (props.length < 2) {
return [];
}
const { key: modelValueArg, value: modelValeExpr } = props[0];
const { key: onUpdateArg, value: onUpdateExpr } = props[1];
if (modelValueArg.type !== compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
return [];
}
if (onUpdateArg.type !== compiler_core_1.NodeTypes.SIMPLE_EXPRESSION ||
!onUpdateArg.content.startsWith('onUpdate:')) {
return [];
}
const vBindModelValue = (0, uni_cli_shared_1.createBindDirectiveNode)(binding || modelValueArg.content, (0, codegen_1.genExpr)(modelValeExpr));
const modifiers = parseVModelModifiers(props[2]);
// onUpdateExpr 通常是 ExpressionNode 或者被 cache 的 ExpressionNode
const vOnValue = (onUpdateExpr.type === compiler_core_1.NodeTypes.JS_CACHE_EXPRESSION
? onUpdateExpr.value
: onUpdateExpr);
const vOnUpdate = (0, uni_cli_shared_1.createOnDirectiveNode)(event || (0, shared_1.camelize)(onUpdateArg.content.replace('onUpdate:', 'update-')), formatEventCode((0, codegen_1.genExpr)((0, vOn_1.wrapperVOn)(modifiers
? wrapperVModelModifiers(vOnValue, modifiers, context, isComponent)
: vOnValue, node, context))));
return [vBindModelValue, vOnUpdate];
}
function parseVModelModifiers(property) {
if (property &&
(0, uni_cli_shared_1.isSimpleExpressionNode)(property.key) &&
property.key.content.endsWith('Modifiers') &&
(0, uni_cli_shared_1.isSimpleExpressionNode)(property.value)) {
return property.value.content;
}
}
function wrapperVModelModifiers(exp, modifiers, context, isComponent = false) {
return (0, compiler_core_1.createCompoundExpression)([
`${context.helperString(runtimeHelpers_1.WITH_MODEL_MODIFIERS)}(`,
exp,
',',
modifiers,
`${isComponent ? `, true` : ``}`,
`)`,
]);
}
+8
View File
@@ -0,0 +1,8 @@
import { type DirectiveNode, type DirectiveTransform, type ElementNode, type ExpressionNode, type SimpleExpressionNode } from '@vue/compiler-core';
import type { TransformContext } from '../transform';
export interface VOnDirectiveNode extends DirectiveNode {
arg: ExpressionNode;
exp: SimpleExpressionNode | undefined;
}
export declare const transformOn: DirectiveTransform;
export declare function wrapperVOn(value: ExpressionNode, node: ElementNode, context: TransformContext): ExpressionNode;
+172
View File
@@ -0,0 +1,172 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.wrapperVOn = exports.transformOn = void 0;
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const compiler_core_1 = require("@vue/compiler-core");
const shared_1 = require("@vue/shared");
const __1 = require("..");
const runtimeHelpers_1 = require("../runtimeHelpers");
const transformExpression_1 = require("./transformExpression");
const vFor_1 = require("./vFor");
const fnExpRE = /^\s*([\w$_]+|(async\s*)?\([^)]*?\))\s*=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/;
const transformOn = (dir, node, _context, augmentor) => {
const context = _context;
const { loc, modifiers, arg } = dir;
if (!dir.exp && !modifiers.length) {
context.onError((0, compiler_core_1.createCompilerError)(compiler_core_1.ErrorCodes.X_V_ON_NO_EXPRESSION, loc));
}
let eventName;
if (arg.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
if (arg.isStatic) {
const rawName = arg.content;
// for all event listeners, auto convert it to camelCase. See issue #2249
eventName = (0, compiler_core_1.createSimpleExpression)((0, shared_1.toHandlerKey)((0, shared_1.camelize)(rawName)), true, arg.loc);
}
else {
// #2388
eventName = (0, compiler_core_1.createCompoundExpression)([
// `${context.helperString(TO_HANDLER_KEY)}(`,
arg,
// `)`,
]);
}
}
else {
// already a compound expression.
eventName = arg;
eventName.children.unshift(`${context.helperString(compiler_core_1.TO_HANDLER_KEY)}(`);
eventName.children.push(`)`);
}
// handler processing
let exp = dir.exp;
if (exp && !exp.content.trim()) {
exp = undefined;
}
let shouldCache = context.cacheHandlers && !exp && !context.inVOnce;
if (exp) {
const isMemberExp = (0, compiler_core_1.isMemberExpression)(exp.content, context);
const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content));
const hasMultipleStatements = exp.content.includes(`;`);
// process the expression since it's been skipped
if (context.prefixIdentifiers) {
isInlineStatement && context.addIdentifiers(`$event`);
exp = dir.exp = (0, transformExpression_1.processExpression)(exp, context, false, hasMultipleStatements);
isInlineStatement && context.removeIdentifiers(`$event`);
// with scope analysis, the function is hoistable if it has no reference
// to scope variables.
shouldCache =
context.cacheHandlers &&
// unnecessary to cache inside v-once
!context.inVOnce &&
// runtime constants don't need to be cached
// (this is analyzed by compileScript in SFC <script setup>)
!(exp.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION && exp.constType > 0) &&
// #1541 bail if this is a member exp handler passed to a component -
// we need to use the original function to preserve arity,
// e.g. <transition> relies on checking cb.length to determine
// transition end handling. Inline function is ok since its arity
// is preserved even when cached.
!(isMemberExp && node.tagType === compiler_core_1.ElementTypes.COMPONENT) &&
// bail if the function references closure variables (v-for, v-slot)
// it must be passed fresh to avoid stale values.
!(0, compiler_core_1.hasScopeRef)(exp, context.identifiers) &&
// wxs event
!isFilterExpr(exp, context);
// If the expression is optimizable and is a member expression pointing
// to a function, turn it into invocation (and wrap in an arrow function
// below) so that it always accesses the latest value when called - thus
// avoiding the need to be patched.
if (shouldCache && isMemberExp) {
if (exp.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
exp.content = `${exp.content} && ${exp.content}(...args)`;
}
else {
exp.children = [...exp.children, ` && `, ...exp.children, `(...args)`];
}
}
}
if (isInlineStatement || (shouldCache && isMemberExp)) {
// wrap inline statement in a function expression
exp = (0, compiler_core_1.createCompoundExpression)([
`${isInlineStatement
? context.isTS
? `($event: any)`
: `$event`
: `${context.isTS ? `\n//@ts-ignore\n` : ``}(...args)`} => ${hasMultipleStatements ? `{` : `(`}`,
exp,
hasMultipleStatements ? `}` : `)`,
]);
}
}
let ret = {
props: [
(0, compiler_core_1.createObjectProperty)(eventName, exp || (0, compiler_core_1.createSimpleExpression)(`() => {}`, false, loc)),
],
};
// apply extended compiler augmentor
if (augmentor) {
ret = augmentor(ret);
}
// TODO
if (shouldCache) {
// cache handlers so that it's always the same handler being passed down.
// this avoids unnecessary re-renders when users use inline handlers on
// components.
// ret.props[0].value = wrapper(
// context.cache(ret.props[0].value) as ExpressionNode,
// context
// )
ret.props[0].value = wrapperVOn(ret.props[0].value, node, context);
}
else {
ret.props[0].value = wrapperVOn(ret.props[0].value, node, context);
}
// mark the key as handler for props normalization check
ret.props.forEach((p) => (p.key.isHandlerKey = true));
return ret;
};
exports.transformOn = transformOn;
function isFilterExpr(value, context) {
if (context.filters.length && value.type === compiler_core_1.NodeTypes.COMPOUND_EXPRESSION) {
const firstChild = value.children[0];
if (firstChild.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION &&
context.filters.includes(firstChild.content)) {
return true;
}
}
return false;
}
function wrapperVOn(value, node, context) {
if ((0, transformExpression_1.isBuiltInIdentifier)(value)) {
return value;
}
// wxs event
if (isFilterExpr(value, context)) {
return value;
}
const keys = [];
if (context.miniProgram.event?.key && context.inVFor) {
let keyProp = (0, compiler_core_1.findProp)(node, 'key');
if (!keyProp) {
const vForScope = (0, vFor_1.parseVForScope)(context.currentScope);
if (vForScope) {
keyProp = (0, compiler_core_1.findProp)(vForScope.node, 'key');
}
}
// 对 for 中的所有事件增加 key 标记,避免微信小程序不更新事件对象
if (keyProp && (0, uni_cli_shared_1.isDirectiveNode)(keyProp) && keyProp.exp) {
const keyCode = (0, __1.genExpr)(keyProp.exp);
if (keyCode) {
keys.push(',');
keys.push((0, __1.genExpr)(keyProp.exp));
}
}
}
return (0, compiler_core_1.createCompoundExpression)([
`${context.helperString(runtimeHelpers_1.V_ON)}(`,
value,
...keys,
`)`,
]);
}
exports.wrapperVOn = wrapperVOn;
+16
View File
@@ -0,0 +1,16 @@
import { type BinaryExpression } from '@babel/types';
import { type ComponentNode, type CompoundExpressionNode, type DirectiveNode } from '@vue/compiler-core';
import type { CodegenScope, CodegenVForScope } from '../options';
import { type NodeTransform, type TransformContext } from '../transform';
export declare const transformSlot: NodeTransform;
export declare function rewriteVSlot(dir: DirectiveNode, context: TransformContext): void;
export declare function findSlotName(slotDir: DirectiveNode): string | CompoundExpressionNode;
export declare function findCurrentPath(id: string, scope: CodegenScope): BinaryExpression | import("@babel/types").StringLiteral;
/**
* 目前无用
* @param vForScope
* @param parentScope
* @param context
*/
export declare function rewriteScopedSlotVForScope(vForScope: CodegenVForScope, parentScope: CodegenScope, context: TransformContext): void;
export declare function createVSlotCallExpression(slotComponent: ComponentNode, vForScope: CodegenVForScope, context: TransformContext): import("@babel/types").CallExpression;
+274
View File
@@ -0,0 +1,274 @@
"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 !== compiler_core_1.NodeTypes.COMMENT) {
implicitDefaultChildren.push(slotElement);
}
continue;
}
if (onComponentSlot) {
// already has on-component slot - this is incorrect usage.
context.onError((0, compiler_core_1.createCompilerError)(compiler_core_1.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 === compiler_core_1.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: compiler_core_1.NodeTypes.ELEMENT,
tag: 'template',
tagType: compiler_core_1.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: compiler_core_1.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: compiler_core_1.NodeTypes.ELEMENT,
tagType: compiler_core_1.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 === compiler_core_1.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)([
// 插槽名称,数据更新 pathvueId
(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;
+2
View File
@@ -0,0 +1,2 @@
import type { NodeTransform } from '../transform';
export declare const transformText: NodeTransform;
+28
View File
@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformText = void 0;
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const compiler_core_1 = require("@vue/compiler-core");
const transformText = (node, _) => {
if (!(0, uni_cli_shared_1.isElementNode)(node)) {
return;
}
const dir = (0, compiler_core_1.findDir)(node, 'text');
if (!dir) {
return;
}
// remove v-text
node.props.splice(node.props.indexOf(dir), 1);
if (node.tagType !== compiler_core_1.ElementTypes.ELEMENT) {
return;
}
node.isSelfClosing = false;
node.children = [
{
type: compiler_core_1.NodeTypes.INTERPOLATION,
loc: dir.exp.loc,
content: dir.exp,
},
];
};
exports.transformText = transformText;