304 lines
11 KiB
JavaScript
304 lines
11 KiB
JavaScript
"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)(31 /* ErrorCodes.X_V_FOR_NO_EXPRESSION */, dir.loc));
|
||
return;
|
||
}
|
||
const parseResult = parseForExpression(dir.exp, context);
|
||
if (!parseResult) {
|
||
context.onError((0, compiler_core_1.createCompilerError)(32 /* 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 === 1 /* NodeTypes.ELEMENT */ && !isForElementNode(c)) {
|
||
const key = (0, compiler_core_1.findProp)(c, 'key');
|
||
if (key) {
|
||
context.onError((0, compiler_core_1.createCompilerError)(33 /* 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 === 4 /* 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: 0 /* 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, compiler_core_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;
|