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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"}