index.js.map 14.3 KB
{"version":3,"names":["NOT_LOCAL_BINDING","cloneNode","identifier","isAssignmentExpression","isAssignmentPattern","isFunction","isIdentifier","isLiteral","isNullLiteral","isObjectMethod","isObjectProperty","isRegExpLiteral","isRestElement","isTemplateLiteral","isVariableDeclarator","toBindingIdentifierName","getFunctionArity","node","count","params","findIndex","param","length","buildPropertyMethodAssignmentWrapper","template","statement","buildGeneratorPropertyMethodAssignmentWrapper","visitor","path","state","name","localDeclar","scope","getBindingIdentifier","outerDeclar","selfReference","stop","getNameFromLiteralId","id","pattern","flags","quasis","map","quasi","value","raw","join","undefined","wrap","method","hasBinding","hasGlobal","rename","build","generator","FUNCTION","FUNCTION_ID","FUNCTION_KEY","generateUidIdentifier","expression","callee","body","i","len","push","getProgramParent","references","visit","selfAssignment","binding","getOwnBinding","kind","traverse","parent","localBinding","supportUnicodeId","computed","key","getBinding","constant","operator","left","test","newId"],"sources":["../src/index.ts"],"sourcesContent":["import template from \"@babel/template\";\nimport {\n  NOT_LOCAL_BINDING,\n  cloneNode,\n  identifier,\n  isAssignmentExpression,\n  isAssignmentPattern,\n  isFunction,\n  isIdentifier,\n  isLiteral,\n  isNullLiteral,\n  isObjectMethod,\n  isObjectProperty,\n  isRegExpLiteral,\n  isRestElement,\n  isTemplateLiteral,\n  isVariableDeclarator,\n  toBindingIdentifierName,\n} from \"@babel/types\";\nimport type * as t from \"@babel/types\";\nimport type { NodePath, Scope, Visitor } from \"@babel/traverse\";\n\nfunction getFunctionArity(node: t.Function): number {\n  const count = node.params.findIndex(\n    param => isAssignmentPattern(param) || isRestElement(param),\n  );\n  return count === -1 ? node.params.length : count;\n}\n\nconst buildPropertyMethodAssignmentWrapper = template.statement(`\n  (function (FUNCTION_KEY) {\n    function FUNCTION_ID() {\n      return FUNCTION_KEY.apply(this, arguments);\n    }\n\n    FUNCTION_ID.toString = function () {\n      return FUNCTION_KEY.toString();\n    }\n\n    return FUNCTION_ID;\n  })(FUNCTION)\n`);\n\nconst buildGeneratorPropertyMethodAssignmentWrapper = template.statement(`\n  (function (FUNCTION_KEY) {\n    function* FUNCTION_ID() {\n      return yield* FUNCTION_KEY.apply(this, arguments);\n    }\n\n    FUNCTION_ID.toString = function () {\n      return FUNCTION_KEY.toString();\n    };\n\n    return FUNCTION_ID;\n  })(FUNCTION)\n`);\n\ntype State = {\n  name: string;\n  outerDeclar: t.Identifier;\n  selfAssignment: boolean;\n  selfReference: boolean;\n};\n\nconst visitor: Visitor<State> = {\n  \"ReferencedIdentifier|BindingIdentifier\"(\n    path: NodePath<t.Identifier>,\n    state,\n  ) {\n    // check if this node matches our function id\n    if (path.node.name !== state.name) return;\n\n    // check that we don't have a local variable declared as that removes the need\n    // for the wrapper\n    const localDeclar = path.scope.getBindingIdentifier(state.name);\n    if (localDeclar !== state.outerDeclar) return;\n\n    state.selfReference = true;\n    path.stop();\n  },\n};\n\nfunction getNameFromLiteralId(id: t.Literal) {\n  if (isNullLiteral(id)) {\n    return \"null\";\n  }\n\n  if (isRegExpLiteral(id)) {\n    return `_${id.pattern}_${id.flags}`;\n  }\n\n  if (isTemplateLiteral(id)) {\n    return id.quasis.map(quasi => quasi.value.raw).join(\"\");\n  }\n\n  if (id.value !== undefined) {\n    return id.value + \"\";\n  }\n\n  return \"\";\n}\n\nfunction wrap(\n  state: State,\n  method: t.FunctionExpression | t.Class,\n  id: t.Identifier,\n  scope: Scope,\n) {\n  if (state.selfReference) {\n    if (scope.hasBinding(id.name) && !scope.hasGlobal(id.name)) {\n      // we can just munge the local binding\n      scope.rename(id.name);\n    } else {\n      // we don't currently support wrapping class expressions\n      if (!isFunction(method)) return;\n\n      // need to add a wrapper since we can't change the references\n      let build = buildPropertyMethodAssignmentWrapper;\n      if (method.generator) {\n        build = buildGeneratorPropertyMethodAssignmentWrapper;\n      }\n\n      const template = (\n        build({\n          FUNCTION: method,\n          FUNCTION_ID: id,\n          FUNCTION_KEY: scope.generateUidIdentifier(id.name),\n        }) as t.ExpressionStatement\n      ).expression as t.CallExpression;\n\n      // shim in dummy params to retain function arity, if you try to read the\n      // source then you'll get the original since it's proxied so it's all good\n      const params = (\n        (template.callee as t.FunctionExpression).body\n          .body[0] as any as t.FunctionExpression\n      ).params;\n\n      for (let i = 0, len = getFunctionArity(method); i < len; i++) {\n        params.push(scope.generateUidIdentifier(\"x\"));\n      }\n\n      return template;\n    }\n  }\n\n  method.id = id;\n  scope.getProgramParent().references[id.name] = true;\n}\n\nfunction visit(\n  node: t.FunctionExpression | t.Class,\n  name: string,\n  scope: Scope,\n) {\n  const state: State = {\n    selfAssignment: false,\n    selfReference: false,\n    outerDeclar: scope.getBindingIdentifier(name),\n    name: name,\n  };\n\n  // check to see if we have a local binding of the id we're setting inside of\n  // the function, this is important as there are caveats associated\n\n  const binding = scope.getOwnBinding(name);\n\n  if (binding) {\n    if (binding.kind === \"param\") {\n      // safari will blow up in strict mode with code like:\n      //\n      //   let t = function t(t) {};\n      //\n      // with the error:\n      //\n      //   Cannot declare a parameter named 't' as it shadows the name of a\n      //   strict mode function.\n      //\n      // this isn't to the spec and they've invented this behaviour which is\n      // **extremely** annoying so we avoid setting the name if it has a param\n      // with the same id\n      state.selfReference = true;\n    } else {\n      // otherwise it's defined somewhere in scope like:\n      //\n      //   let t = function () {\n      //     let t = 2;\n      //   };\n      //\n      // so we can safely just set the id and move along as it shadows the\n      // bound function id\n    }\n  } else if (state.outerDeclar || scope.hasGlobal(name)) {\n    scope.traverse(node, visitor, state);\n  }\n\n  return state;\n}\n\n/**\n * Add id to function/class expression inferred from the AST\n *\n * @export\n * @template N The unamed expression type\n * @param {Object} nodePathLike The NodePath-like input\n * @param {N} nodePathLike.node an AST node\n * @param {NodePath<N>[\"parent\"]} [nodePathLike.parent] The parent of the AST node\n * @param {Scope} nodePathLike.scope The scope associated to the AST node\n * @param {t.LVal | t.StringLiteral | t.NumericLiteral | t.BigIntLiteral} [nodePathLike.id] the fallback naming source when the helper\n * can not infer the function name from the AST\n * @param {boolean} [localBinding=false] whether a name could shadow a self-reference (e.g. converting arrow function)\n * @param {boolean} [supportUnicodeId=false] whether the compilation target supports unicodeId (non-BMP characters) or not\n * @returns {(N | t.CallExpression | void)}\n * - modified node when name can be inferred,\n * - an IIFE when `node` contains a binding shadowing the inferred function name (e.g. `let f = function (f) {}`),\n * - `void` when `node` has `id` property or the helper can not inferred the name or the inferred name contains non-BMP characters that is not supported by current target\n */\nexport default function <N extends t.FunctionExpression | t.Class>(\n  {\n    node,\n    parent,\n    scope,\n    id,\n  }: {\n    node: N;\n    parent?: NodePath<N>[\"parent\"];\n    scope: Scope;\n    id?: t.LVal | t.StringLiteral | t.NumericLiteral | t.BigIntLiteral;\n  },\n  localBinding = false,\n  supportUnicodeId = false,\n): N | t.CallExpression | void {\n  // has an `id` so we don't need to infer one\n  if (node.id) return;\n\n  if (\n    (isObjectProperty(parent) || isObjectMethod(parent, { kind: \"method\" })) &&\n    (!parent.computed || isLiteral(parent.key))\n  ) {\n    // { foo() {} };\n    id = parent.key as\n      | t.Identifier\n      | t.StringLiteral\n      | t.NumericLiteral\n      | t.BigIntLiteral;\n  } else if (isVariableDeclarator(parent)) {\n    // let foo = function () {};\n    id = parent.id;\n\n    // but not \"let foo = () => {};\" being converted to function expression\n    if (isIdentifier(id) && !localBinding) {\n      const binding = scope.parent.getBinding(id.name);\n      if (\n        binding &&\n        binding.constant &&\n        scope.getBinding(id.name) === binding\n      ) {\n        // always going to reference this method\n        node.id = cloneNode(id);\n        // @ts-expect-error Fixme: avoid mutating AST nodes\n        node.id[NOT_LOCAL_BINDING] = true;\n        return;\n      }\n    }\n  } else if (isAssignmentExpression(parent, { operator: \"=\" })) {\n    // foo = function () {};\n    id = parent.left;\n  } else if (!id) {\n    return;\n  }\n\n  let name;\n  if (id && isLiteral(id)) {\n    name = getNameFromLiteralId(id);\n  } else if (id && isIdentifier(id)) {\n    name = id.name;\n  }\n\n  if (name === undefined) {\n    return;\n  }\n\n  if (!supportUnicodeId && isFunction(node) && /[\\uD800-\\uDFFF]/.test(name)) {\n    return;\n  }\n\n  name = toBindingIdentifierName(name);\n  const newId = identifier(name);\n\n  // The id shouldn't be considered a local binding to the function because\n  // we are simply trying to set the function name and not actually create\n  // a local binding.\n  // @ts-expect-error Fixme: avoid mutating AST nodes\n  newId[NOT_LOCAL_BINDING] = true;\n\n  const state = visit(node, name, scope);\n  return wrap(state, node, newId, scope) || node;\n}\n"],"mappings":"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"}