UNPKG

babel-plugin-clsx

Version:

Add clsx() automatically to className in React and support Typescript.

91 lines (90 loc) 3.68 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const core_1 = require("@babel/core"); const plugin_syntax_jsx_1 = require("@babel/plugin-syntax-jsx"); const CLSX_IGNORE_GLOBAL_TOKEN = '@clsx-ignore-global'; const CLSX_IGNORE_TOKEN = '@clsx-ignore'; const CLASS_NAME_STRICT_RE = /^className$/; const CLASS_NAME_RE = /^(className|\w+ClassName)$/; const IMPORT_SOURCE = 'clsx'; const IMPORT_NAME = 'default'; const IMPORT_NAMESPACE = '_clsx'; exports.default = (_, opts = {}) => { var _a, _b, _c, _d; (_a = opts.static) !== null && _a !== void 0 ? _a : (opts.static = true); (_b = opts.strict) !== null && _b !== void 0 ? _b : (opts.strict = true); (_c = opts.importSource) !== null && _c !== void 0 ? _c : (opts.importSource = IMPORT_SOURCE); (_d = opts.importName) !== null && _d !== void 0 ? _d : (opts.importName = IMPORT_NAME); const callId = core_1.types.identifier(IMPORT_NAMESPACE); const importDecl = core_1.types.importDeclaration([ opts.importName === IMPORT_NAME ? core_1.types.importDefaultSpecifier(callId) : core_1.types.importSpecifier(callId, core_1.types.identifier(opts.importName)), ], core_1.types.stringLiteral(opts.importSource)); const classNameRE = opts.strict ? CLASS_NAME_STRICT_RE : CLASS_NAME_RE; function isDynamicClassName(node) { return classNameRE.test(node.name.name) && core_1.types.isJSXExpressionContainer(node.value); } function isIgnoredGlobal(nodes) { for (const node of nodes) { if (core_1.types.isImportDeclaration(node)) { if (isIgnored(node, CLSX_IGNORE_GLOBAL_TOKEN)) return true; } else { return isIgnored(node, CLSX_IGNORE_GLOBAL_TOKEN); } } return false; } function isIgnored(node, token = CLSX_IGNORE_TOKEN) { return node.leadingComments ? node.leadingComments.some((comment) => { const ignored = comment.value.trim() === token; if (ignored) comment.ignore = ignored; return ignored; }) : false; } function isNeedTransform(jsxExpr) { if (opts.static) { return core_1.types.isArrayExpression(jsxExpr) || core_1.types.isObjectExpression(jsxExpr); } else { return !core_1.types.isCallExpression(jsxExpr) && !core_1.types.isStringLiteral(jsxExpr); } } function replaceNode(path) { const { node } = path; const args = (core_1.types.isArrayExpression(node) ? node.elements : [node]); const callExpr = core_1.types.callExpression(callId, args); path.replaceWith(callExpr); } return { name: 'clsx', inherits: plugin_syntax_jsx_1.default, visitor: { Program: { enter(path, state) { state.clsxIgnoreGlobal = isIgnoredGlobal(path.node.body); }, exit(path, state) { if (state.clsxImport) { path.node.body.unshift(importDecl); } }, }, JSXAttribute(path, state) { const { node } = path; if (isDynamicClassName(node) && !isIgnored(node) && !state.clsxIgnoreGlobal && isNeedTransform(node.value.expression)) { state.clsxImport = true; replaceNode(path.get('value').get('expression')); } }, }, }; };