[AST Babel Plugin] Hanlde ArrowFunction && FunctionExpression

zhongweinan 2020-02-21

Continue with previous post: https://www.cnblogs.com/Answer1215/p/12342540.html

Now we need to think about functionExpression and ArrowFunction:

function add(a, b) {
    console.log(a, b)
      return a + b
}

function subtract(a, b) {
    console.log(a, b)
      return a - b
}

const multiply = (a, b) => {
    console.log(a, b)
      return a * b;
}

const divide = function(a, b) {
    console.log(a, b)
      return a / b;
}

add(1, 2)
subtract(2, 1)
multiply(3, 4)
divide(25, 5)
console.log(‘sup dawg‘)

Transform code:

export default function(babel) {
  const { types: t } = babel;

  function getFnName(path) {
    const expOrArwFn = path.findParent(t.isVariableDeclaration);
    const parentFn = path.findParent(t.isFunctionDeclaration);
    let faName = "";
    if (parentFn) {
      faName = `${parentFn.node.id.name} `;
    } else if (expOrArwFn) {
      faName = `${expOrArwFn.node.declarations[0].id.name} `;
    } else {
      faName = "";
    }

    return faName;
  }

  return {
    name: "ast-transform", // not required
    visitor: {
      CallExpression(path) {
        if (
          !looksLike(path.node, {
            callee: {
              type: "MemberExpression",
              object: {
                name: "console"
              },
              property: {
                name: "log"
              }
            }
          })
        ) {
          return;
        }

        // insert string into console.log(‘instread here‘, a,b)
        const { line, column } = path.node.loc.start;
        const fnName = getFnName(path);
        const prefix = fnName + `${line}:${column}`;
        path.node.arguments.unshift(t.stringLiteral(prefix));
      }
    }
  };
}

function looksLike(a, b) {
  return (
    a &&
    b &&
    Object.keys(b).every(bKey => {
      const bVal = b[bKey];
      const aVal = a[bKey];
      if (typeof bVal === "function") {
        return bVal(aVal);
      }
      return isPrimitive(bVal) ? bVal === aVal : looksLike(aVal, bVal);
    })
  );
}

function isPrimitive(val) {
  return val == null || /^[sbn]/.test(typeof val);
}

Output:

function add(a, b) {
    console.log("add 2:4", a, b)
      return a + b
}

function subtract(a, b) {
    console.log("subtract 7:4", a, b)
      return a - b
}

const multiply = (a, b) => {
    console.log("multiply 12:4", a, b)
      return a * b;
}

const divide = function(a, b) {
    console.log("divide 17:4", a, b)
      return a / b;
}

add(1, 2)
subtract(2, 1)
multiply(3, 4)
divide()
console.log("25:0", ‘sup dawg‘)

Other solutions;

export default function(babel) {
  const {types: t} = babel

  return {
    name: ‘captains-log‘,
    visitor: {
      CallExpression(path) {
        if (
          !looksLike(path, {
            node: {
              callee: {
                type: ‘MemberExpression‘,
                object: {
                  name: ‘console‘,
                },
              },
            },
          })
        ) {
          return
        }
        let prefix = ‘‘
        const functionName = getFunctionName(path)
        if (functionName) {
          prefix += functionName
        }
        const start = path.node.loc.start
        prefix += ` ${start.line}:${start.column}`
        path.node.arguments.unshift(t.stringLiteral(prefix.trim()))
      },
    },
  }

  function getFunctionName(path) {
    const parentFunction = path.findParent(parent => {
      return (
        t.isFunctionDeclaration(parent) ||
        t.isArrowFunctionExpression(parent) ||
        t.isFunctionExpression(parent)
      )
    })
    if (!parentFunction) {
      return null
    }
    if (looksLike(parentFunction, {node: {id: t.isIdentifier}})) {
      return parentFunction.node.id.name
    } else if (
      t.isVariableDeclarator(parentFunction.parent) ||
      t.isFunctionExpression(parentFunction.parent)
    ) {
      return parentFunction.parent.id.name
    }
    return null
  }
}

function looksLike(a, b) {
  return (
    a &&
    b &&
    Object.keys(b).every(bKey => {
      const bVal = b[bKey]
      const aVal = a[bKey]
      if (typeof bVal === ‘function‘) {
        return bVal(aVal)
      }
      return isPrimitive(bVal) ? bVal === aVal : looksLike(aVal, bVal)
    })
  )
}

function isPrimitive(val) {
  return val == null || /^[sbn]/.test(typeof val)
}

相关推荐

蜗牛慢爬的李成广 / 0评论 2020-01-28