"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var shared_1 = require("../../shared/js/index");
exports.locStub = {
source: '',
start: { line: 1, column: 1, offset: 0 },
end: { line: 1, column: 1, offset: 0 }
};
function createArrayExpression(elements, loc) {
if (loc === void 0) { loc = exports.locStub; }
return {
type: 16,
loc: loc,
elements: elements
};
}
exports.createArrayExpression = createArrayExpression;
function createObjectExpression(properties, loc) {
if (loc === void 0) { loc = exports.locStub; }
return {
type: 14,
loc: loc,
properties: properties
};
}
exports.createObjectExpression = createObjectExpression;
function createObjectProperty(key, value) {
return {
type: 15,
loc: exports.locStub,
key: shared_1.isString(key) ? createSimpleExpression(key, true) : key,
value: value
};
}
exports.createObjectProperty = createObjectProperty;
function createSimpleExpression(content, isStatic, loc, isConstant) {
if (loc === void 0) { loc = exports.locStub; }
if (isConstant === void 0) { isConstant = false; }
return {
type: 4,
loc: loc,
isConstant: isConstant,
content: content,
isStatic: isStatic
};
}
exports.createSimpleExpression = createSimpleExpression;
function createInterpolation(content, loc) {
return {
type: 5,
loc: loc,
content: shared_1.isString(content)
? createSimpleExpression(content, false, loc)
: content
};
}
exports.createInterpolation = createInterpolation;
function createCompoundExpression(children, loc) {
if (loc === void 0) { loc = exports.locStub; }
return {
type: 8,
loc: loc,
children: children
};
}
exports.createCompoundExpression = createCompoundExpression;
function createCallExpression(callee, args, loc) {
if (args === void 0) { args = []; }
if (loc === void 0) { loc = exports.locStub; }
return {
type: 13,
loc: loc,
callee: callee,
arguments: args
};
}
exports.createCallExpression = createCallExpression;
function createFunctionExpression(params, returns, newline, loc) {
if (newline === void 0) { newline = false; }
if (loc === void 0) { loc = exports.locStub; }
return {
type: 17,
params: params,
returns: returns,
newline: newline,
loc: loc
};
}
exports.createFunctionExpression = createFunctionExpression;
function createSequenceExpression(expressions) {
return {
type: 18,
expressions: expressions,
loc: exports.locStub
};
}
exports.createSequenceExpression = createSequenceExpression;
function createConditionalExpression(test, consequent, alternate) {
return {
type: 19,
test: test,
consequent: consequent,
alternate: alternate,
loc: exports.locStub
};
}
exports.createConditionalExpression = createConditionalExpression;
function createCacheExpression(index, value, isVNode) {
if (isVNode === void 0) { isVNode = false; }
return {
type: 20,
index: index,
value: value,
isVNode: isVNode,
loc: exports.locStub
};
}
exports.createCacheExpression = createCacheExpression;
import { NOOP } from "../util.js";
import { defaultOnError } from "./error.js";
import { __DEV__, isVSlot } from "./utils.js";
import {
NodeTypes,
ElementTypes,
createSimpleExpression,
createCacheExpression,
} from "./ast.js";
import { isSingleElementRoot, hoistStatic } from "./transforms/hoistStatic.js";
import {
TO_DISPLAY_STRING,
FRAGMENT,
helperNameMap,
CREATE_BLOCK,
CREATE_COMMENT,
OPEN_BLOCK,
} from "./runtimeHelpers.js";
export function createTransformContext(
root,
{
prefixIdentifiers = false,
hoistStatic = false,
cacheHandlers = false,
nodeTransforms = [],
directiveTransforms = {},
transformHoist = null,
isBuiltInComponent = NOOP,
expressionPlugins = [],
scopeId = null,
ssr = false,
onError = defaultOnError,
}
) {
const context = {
// options
prefixIdentifiers,
hoistStatic,
cacheHandlers,
nodeTransforms,
directiveTransforms,
transformHoist,
isBuiltInComponent,
expressionPlugins,
scopeId,
ssr,
onError,
// state
root,
helpers: new Set(),
components: new Set(),
directives: new Set(),
hoists: [],
imports: new Set(),
temps: 0,
cached: 0,
identifiers: {},
scopes: {
vFor: 0,
vSlot: 0,
vPre: 0,
vOnce: 0,
},
parent: null,
currentNode: root,
childIndex: 0,
// methods
helper(name) {
context.helpers.add(name);
return name;
},
helperString(name) {
return `_${helperNameMap[context.helper(name)]}`;
},
replaceNode(node) {
// parent, childIndex æ¥èª traverseChildren éé¢çèµå¼
context.parent.children[context.childIndex] = context.currentNode = node;
},
removeNode(node) {
if (__DEV__ && !context.parent) {
throw new Error(`Cannot, remove root node.`);
}
const list = context.parent.children;
// å
ä»èç¹å©å䏿¾ï¼ç¶ååå½åèç¹
const removalIndex = node
? list.indexOf(node)
: context.currentNode
? context.childIndex
: -1;
if (__DEV__ && removalIndex < 0) {
throw new Error(`node being removed is not a child of current parent`);
}
if (!node || node === context.currentNode) {
// å é¤çæ¯å½å traverseNode éå½ä¸æ£éåçèç¹
context.currentNode = null;
context.onNodeRemoved();
} else {
// å é¤å½åèç¹åé¢çå
å¼èç¹
if (context.childIndex > removalIndex) {
context.childIndex--;
context.onNodeRemoved();
}
}
// æ§è¡å é¤
context.parent.children.splice(removalIndex, 1);
},
onNodeRemoved: () => {},
addIdentifiers(exp) {},
removeIdentifiers(exp) {},
hoist(exp) {
context.hoists.push(exp);
const identifier = createSimpleExpression(
`_hoisted_${context.hoists.length}`,
false,
exp.loc,
true
);
identifier.hoisted = exp;
return identifier;
},
cache(exp, isVNode = false) {
return createCacheExpression(++context.cached, exp, isVNode);
},
};
function addId(id) {}
function removeId(id) {}
return context;
}
export function traverseNode(node, context) {
context.currentNode = node;
const { nodeTransforms } = context;
const exitFns = [];
for (let i = 0; i < nodeTransforms.length; i++) {
// è°ç¨è¯¸å¦ transformText ç彿°
const onExit = nodeTransforms[i](node, context);
if (onExit) {
const fns = Array.isArray(onExit) ? onExit : [onExit];
exitFns.push(...fns);
}
if (!context.currentNode) {
// å¯è½è¢«ç§»é¤äº
return;
} else {
// èç¹å¯è½è¢«æ¿æ¢è¿ï¼éæ°å»ºç«å¼ç¨
node = context.currentNode;
}
}
switch (node.type) {
// ... çç¥
case NodeTypes.INTERPOLATION:
if (!context.ssr) {
// è¿ä¸ªå½æ°æ¥èªä¸ä¸æå¤çä¸ç helper(name)
context.helper(TO_DISPLAY_STRING);
}
break;
case NodeTypes.IF:
for (let i = 0; i < node.branches.length; i++) {
traverseNode(node.branches[i], context);
}
break;
case NodeTypes.IF_BRANCH:
case NodeTypes.ELEMENT:
case NodeTypes.ROOT:
traverseChildren(node, context);
break;
}
context.currentNode = node;
let i = exitFns.length;
// æ§è¡ææè½¬æ¢
while (i--) {
exitFns[i]();
}
}
export function transform(root, options) {
const context = createTransformContext(root, options);
traverseNode(root, context);
console.log(root, "000");
if (options.hoistStatic) {
hoistStatic(root, context);
}
if (!options.ssr) {
createRootCodegen(root, context);
}
// ... ssr å¤ç
// root 屿§åå¹¶ï¼åå§å
root.helpers = [...context.helpers];
root.components = [...context.components];
root.directives = [...context.directives];
root.imports = [...context.imports];
root.hoists = context.hoists;
root.temps = context.temps;
root.cached = context.cached;
}
function createRootCodegen(root, context) {
const { helper } = context;
const { children } = root;
const child = children[0];
if (children.length === 1) {
// åªæä¸ä¸ªå©åèç¹
// ä¸å©åèç¹æ¯ä¸ä¸ªå
ç´ element ç±»åï¼å°å®æ¾å¨ä¸ä¸ªä»£ç åéè¿å
// å¦ï¼ { code }
if (isSingleElementRoot(root, child) && child.codegenNode) {
const codegenNode = child.codegenNode;
if (codegenNode.type === NodeTypes.VNODE_CALL) {
codegenNode.isBlock = true;
helper(OPEN_BLOCK);
helper(CREATE_BLOCK);
}
root.codegenNode = codegenNode;
} else {
root.codegenNode = child;
}
} else if (children.length > 1) {
} else {
// 没æå©åèç¹ï¼ codegen è¿å nullï¼çå°æ²¡
// 01 simple text è¿å null é®é¢æ¾å°æ ¹æºäº
}
}
export function traverseChildren(parent, context) {
let i = 0;
const nodeRemoved = () => {
i--;
};
for (; i < parent.children.length; i++) {
const child = parent.children[i];
// è¿ç¥æå符串ï¼åªå¤ç ast child
if (typeof child === "string") continue;
context.parent = parent;
context.childIndex = i;
context.onNodeRemoved = nodeRemoved;
traverseNode(child, context);
}
}
export function createStructuralDirectiveTransform(name, fn) {
const matches =
typeof name === "string" ? (n) => n === name : (n) => name.test(n);
return (node, context) => {
if (node.type === NodeTypes.ELEMENT) {
const { props } = node;
// å¿½ç¥ v-slotï¼å®å¨ vSlot.ts ä¸å¤ç
if (node.tagType === ElementTypes.TEMPLATE && props.some(isVSlot)) {
return;
}
// å¼å§æ¶é v-if æä»¤ç transform 彿°
const exitFns = [];
for (let i = 0; i < props.length; i++) {
const prop = props[i];
if (prop.type === NodeTypes.DIRECTIVE && matches(prop.name)) {
// å é¤åèç¹ä¸çæä»¤å±æ§
props.splice(i, 1);
i--;
const onExit = fn(node, prop, context);
if (onExit) exitFns.push(onExit);
}
}
return exitFns;
}
};
}