| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- "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 === 5 /* NodeTypes.INTERPOLATION */) {
- node.content = processExpression(node.content, context);
- }
- else if (node.type === 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 === 7 /* 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 === 4 /* 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 === 4 /* 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 (type === "setup-const" /* BindingTypes.SETUP_CONST */ ||
- type === "setup-reactive-const" /* BindingTypes.SETUP_REACTIVE_CONST */ ||
- localVars[raw]) {
- return raw;
- }
- else if (type === "setup-ref" /* BindingTypes.SETUP_REF */) {
- return `${raw}.value`;
- }
- else if (type === "setup-maybe-ref" /* 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 === "setup-let" /* 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 === "props" /* 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 === "props-aliased" /* 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')) {
- // setup bindings in non-inline mode
- return `$setup.${raw}`;
- }
- else if (type === "props-aliased" /* 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 (bindingMetadata[node.content] === "setup-const" /* BindingTypes.SETUP_CONST */) {
- node.constType = 1 /* ConstantTypes.CAN_SKIP_PATCH */;
- }
- node.content = rewriteIdentifier(rawExp);
- }
- else if (!isScopeVarReference) {
- if (isLiteral) {
- node.constType = 3 /* ConstantTypes.CAN_STRINGIFY */;
- }
- else {
- node.constType = 2 /* 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)(45 /* 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 ? 3 /* ConstantTypes.CAN_STRINGIFY */ : 0 /* 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
- ? 0 /* ConstantTypes.NOT_CONSTANT */
- : 3 /* 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 === 4 /* 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 !== 4 /* NodeTypes.SIMPLE_EXPRESSION */) {
- return false;
- }
- id = id.content;
- }
- return builtInIdentifiers.includes(id);
- }
- exports.isBuiltInIdentifier = isBuiltInIdentifier;
|