UNPKG

babel-helper-decorate-react

Version:
308 lines (307 loc) 14.6 kB
"use strict"; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.defaultReactFunctionCallTokens = exports.defaultReactClassSuperTokens = exports.defaultReactClassCallTokens = exports.defaultReactClassMemberTokens = exports.defaultReactClassMethodsTokens = void 0; const createDecorateVisitor_1 = require("./createDecorateVisitor"); const utils_1 = require("./utils"); const t = require("@babel/types"); const isMemberExpression = (path, name) => { if (typeof name === 'string') { return String(path) === name; } if (typeof name === 'function') { return name(path); } return name.test(String(path)); }; exports.defaultReactClassMethodsTokens = [ 'componentDidUpdate', 'componentDidCatch', 'componentDidMount', 'componentWillMount', 'componentWillReceiveProps', 'componentWillUnmount', 'componentWillUpdate', 'UNSAFE_componentWillMount', 'UNSAFE_componentWillReceiveProps', 'UNSAFE_componentWillUpdate', 'getSnapshotBeforeUpdate', 'shouldComponentUpdate', 'render' ]; exports.defaultReactClassMemberTokens = []; exports.defaultReactClassCallTokens = []; exports.defaultReactClassSuperTokens = []; ['React.Profiler', 'React.Suspense', 'React.StrictMode', 'React.Fragment'].forEach((name) => { exports.defaultReactClassMemberTokens.push(name); exports.defaultReactClassMemberTokens.push(name.split('.')[1]); }); ['React.Component', 'React.PureComponent'].forEach((name) => { exports.defaultReactClassSuperTokens.push(name); exports.defaultReactClassSuperTokens.push(name.split('.')[1]); }); ['React.createRef', 'React.createFactory', 'React.createElement', 'React.cloneElement'].forEach((name) => { exports.defaultReactClassCallTokens.push(name); exports.defaultReactClassCallTokens.push(name.split('.')[1]); }); exports.defaultReactFunctionCallTokens = exports.defaultReactClassCallTokens.slice(); [ 'React.useCallback', 'React.useEffect', 'React.useMemo', 'React.useImperativeHandle', 'React.useLayoutEffect', 'React.useReducer', 'React.useContext', 'React.useState', 'React.useDebugValue', 'React.useRef' ].forEach((name) => { exports.defaultReactFunctionCallTokens.push(name); exports.defaultReactFunctionCallTokens.push(name.split('.')[1]); }); const detectIsValidName = (path) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j; if (t.isFunctionExpression(path.node) || t.isArrowFunctionExpression(path.node)) { const variableDeclartorPath = path.findParent((path) => t.isVariableDeclarator(path.node)); if (variableDeclartorPath && ((_b = (_a = // @ts-ignore variableDeclartorPath.node) === null || _a === void 0 ? void 0 : _a.id) === null || _b === void 0 ? void 0 : _b.name) && // @ts-ignore /^[^a-zA-Z]*?[A-Z]/.test((_d = (_c = variableDeclartorPath.node) === null || _c === void 0 ? void 0 : _c.id) === null || _d === void 0 ? void 0 : _d.name)) { return true; } } if (t.isFunctionDeclaration(path.node) && (!((_e = path.node) === null || _e === void 0 ? void 0 : _e.id) || // @ts-ignore (((_g = (_f = path.node) === null || _f === void 0 ? void 0 : _f.id) === null || _g === void 0 ? void 0 : _g.name) && // @ts-ignore /^[^a-zA-Z]*?[A-Z]/.test((_j = (_h = path.node) === null || _h === void 0 ? void 0 : _h.id) === null || _j === void 0 ? void 0 : _j.name)))) { return true; } return false; }; function createDecorateReactVisitor(_a) { var { reactClassSuperTokens = exports.defaultReactClassSuperTokens, reactClassMethodsTokens = exports.defaultReactClassMethodsTokens, reactClassCallTokens = exports.defaultReactClassCallTokens, reactFunctionCallTokens = exports.defaultReactFunctionCallTokens, reactClassMemberTokens = exports.defaultReactClassMemberTokens, wrapFunctionComponentDecorateTokens = ['React.forwardRef', 'forwardRef'], detectClassComponent = true, detectFunctionComponent = true, detectComponentName = true, condition } = _a, options = __rest(_a, ["reactClassSuperTokens", "reactClassMethodsTokens", "reactClassCallTokens", "reactFunctionCallTokens", "reactClassMemberTokens", "wrapFunctionComponentDecorateTokens", "detectClassComponent", "detectFunctionComponent", "detectComponentName", "condition"]); const mergedOptions = Object.assign({ detectScopeDepth: 1 }, options); const isReactInner = (path) => { let isMatched = false; path.traverse({ CallExpression(path) { if (utils_1.isScopeDepthPassed(path, mergedOptions.detectScopeDepth) && reactFunctionCallTokens.some((token) => isMemberExpression(path.get('callee'), token))) { isMatched = true; path.stop(); } }, // @ts-ignore ['MemberExpression|Identifier'](path) { if (utils_1.isScopeDepthPassed(path, mergedOptions.detectScopeDepth) && reactClassMemberTokens.some((token) => isMemberExpression(path, token))) { isMatched = true; path.stop(); } path.skip(); }, JSXElement(path) { if (utils_1.isScopeDepthPassed(path, mergedOptions.detectScopeDepth)) { isMatched = true; path.stop(); } }, JSXFragment(path) { if (utils_1.isScopeDepthPassed(path, mergedOptions.detectScopeDepth)) { isMatched = true; path.stop(); } } }); return isMatched; }; const vTypes = [ detectFunctionComponent && 'FunctionExpression|ArrowFunctionExpression', detectFunctionComponent && 'FunctionDeclaration', detectClassComponent && 'ClassExpression|ClassDeclaration' ] .filter(Boolean) .map((name) => ({ type: name, condition: (path, a, b, api) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j; if (condition) { if (false === condition(path, a, b, api)) { return false; } } let isMatched = false; if (name === 'ClassExpression|ClassDeclaration') { if (!((_a = path.get('superClass')) === null || _a === void 0 ? void 0 : _a.node)) { return false; } if (utils_1.isScopeDepthPassed(path, mergedOptions.detectScopeDepth) && reactClassSuperTokens.some((token) => isMemberExpression(path.get('superClass'), token))) { path.stop(); return true; } const deltaDepth = (delta) => { if (delta != null) { return mergedOptions.detectScopeDepth != null ? mergedOptions.detectScopeDepth < 0 ? mergedOptions.detectScopeDepth : mergedOptions.detectScopeDepth + delta : mergedOptions.detectScopeDepth; } return mergedOptions.detectScopeDepth; }; path.traverse({ ClassMethod(path) { // console.log(String(path.get('key')), reactClassMethodsTokens.some((token) => isMemberExpression(path.get('key') as any, token))) if (utils_1.isScopeDepthPassed(path, deltaDepth(1)) && reactClassMethodsTokens.some((token) => isMemberExpression(path.get('key'), token))) { isMatched = true; path.stop(); } }, CallExpression(path) { if (utils_1.isScopeDepthPassed(path, deltaDepth(2)) && reactClassCallTokens.some((token) => isMemberExpression(path.get('callee'), token))) { isMatched = true; path.stop(); } }, // @ts-ignore ['MemberExpression|Identifier'](path) { if (utils_1.isScopeDepthPassed(path, deltaDepth(2)) && reactClassMemberTokens.some((token) => isMemberExpression(path, token))) { isMatched = true; path.stop(); } path.skip(); }, JSXElement(path) { if (utils_1.isScopeDepthPassed(path, deltaDepth(2))) { isMatched = true; path.stop(); } }, JSXFragment(path) { if (utils_1.isScopeDepthPassed(path, deltaDepth(2))) { isMatched = true; path.stop(); } } }); return isMatched; } else { // @ts-ignore if (((_b = path.node) === null || _b === void 0 ? void 0 : _b.async) || ((_c = path.node) === null || _c === void 0 ? void 0 : _c.generator)) { return false; } /** * function Button() {} */ if (path.node.type === 'FunctionDeclaration' && isReactInner(path) && (!detectComponentName || detectIsValidName(path))) { const getVariableDeclarator = () => { var _a, _b; // path.opts return t.variableDeclarator( // @ts-ignore t.identifier(((_b = (_a = path.node) === null || _a === void 0 ? void 0 : _a.id) === null || _b === void 0 ? void 0 : _b.name) || '__unknow'), t.functionExpression( // @ts-ignore path.node.id, // @ts-ignore path.node.params, // @ts-ignore path.node.body, // @ts-ignore path.node.generator, // @ts-ignore path.node.async)); }; const getVariableDeclaration = () => { return t.variableDeclaration('const', [getVariableDeclarator()]); }; /** * function X() { * return <div></div> * } * => * const X = function X() { * return <div></div> * } */ if (((_d = path.parent) === null || _d === void 0 ? void 0 : _d.type) === 'Program') { // @ts-ignore utils_1.replaceAdvancedWith(path, getVariableDeclaration()); api.noSkip(); return false; } /** * export function X() { * return <div></div> * } * => * export const X = function X() { * return <div></div> * } */ if (((_e = path.parent) === null || _e === void 0 ? void 0 : _e.type) === 'ExportNamedDeclaration') { utils_1.replaceAdvancedWith(path, getVariableDeclaration()); api.noSkip(); return false; } /** * export default function X() { * return <div></div> * } * => * const X = function X() { * return <div></div> * } * export default X; */ if (((_f = path.parent) === null || _f === void 0 ? void 0 : _f.type) === 'ExportDefaultDeclaration') { // @ts-ignore path.parentPath.insertBefore(getVariableDeclaration()); utils_1.replaceAdvancedWith(path, t.identifier(path.node.id.name)); api.noSkip(); return false; } return false; } // // @ts-ignore // if (path.parent.node?.type === 'CallExpression') { // debugger // } if (detectComponentName && !detectIsValidName(path)) { return false; } if (isReactInner(path)) { const parentPath = path.parentPath; if (((_g = parentPath.node) === null || _g === void 0 ? void 0 : _g.type) === 'CallExpression' && ((_j = (_h = parentPath.node) === null || _h === void 0 ? void 0 : _h.callee) === null || _j === void 0 ? void 0 : _j.name) && wrapFunctionComponentDecorateTokens.some((t) => isMemberExpression(parentPath.get('callee'), t))) { api.wrap(); return true; } return true; } return false; } } })); return createDecorateVisitor_1.default(Object.assign({ deepVisitorTypes: vTypes, visitorTypes: vTypes }, mergedOptions)); } exports.default = createDecorateReactVisitor;