UNPKG

@areslabs/alita-core

Version:

alita-core

343 lines (274 loc) 9.52 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseCode = parseCode; exports.geneReactCode = geneReactCode; exports.isReactComponent = isReactComponent; exports.getPropsChain = getPropsChain; exports.decTemlate = decTemlate; exports.isJSXChild = isJSXChild; exports.isChildComp = isChildComp; exports.isChildCompChild = isChildCompChild; exports.isTextElement = isTextElement; exports.isRenderReturn = isRenderReturn; exports.getOriginal = getOriginal; exports.getAttri = getAttri; exports.elementAddClass = elementAddClass; exports.isReactFragment = isReactFragment; exports.isReactFragmentExpression = isReactFragmentExpression; var _parser = require("@babel/parser"); var _generator = _interopRequireDefault(require("@babel/generator")); var t = _interopRequireWildcard(require("@babel/types")); var _getAndStorecompInfos = require("./getAndStorecompInfos"); var _constants = require("../constants"); var _cacheModuleInfos = require("./cacheModuleInfos"); var _util = require("./util"); var _configure = _interopRequireDefault(require("../configure")); function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Copyright (c) Areslabs. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * */ function parseCode(code, extname) { const plugins = ['classProperties', 'objectRestSpread', 'optionalChaining', ['decorators', { decoratorsBeforeExport: true }], 'classPrivateProperties', 'doExpressions', 'exportDefaultFrom', 'exportNamespaceFrom', 'throwExpressions']; if (extname === '.ts') { plugins.push('typescript'); } else if (extname === '.tsx') { plugins.push('typescript'); plugins.push('jsx'); } else { plugins.push('flow'); plugins.push('jsx'); } return (0, _parser.parse)(code, { sourceType: "module", plugins }); } //TODO 由于babel-loader 无法直接传递AST,所以需要先生成code function geneReactCode(ast) { let code = (0, _generator.default)(ast, { comments: false, jsescOption: {} }).code; return code; } function isReactComponent(superClass) { if (!superClass) return false; // Component, PureComponent if (superClass.type === 'Identifier' && (superClass.name === 'Component' || superClass.name === 'PureComponent' || superClass.name === 'FuncComponent')) { return true; } // React.Component, React.PureComponent if (superClass.type === 'MemberExpression' && superClass.object.name === 'React' && (superClass.property.name === 'Component' || superClass.property.name === 'PureComponent' || superClass.property.name === 'FuncComponent')) { return true; } return false; } /** * 调用链处理为数组: a.b.c --> ['a', 'b', 'c'] * @param memberExpression * @returns {any[]} */ function getPropsChain(memberExpression) { const chain = []; let me = memberExpression; while (me.type === 'MemberExpression') { if (me.property.type === 'Identifier') { chain.push(me.property.name); } else if (me.property.type === 'NumericLiteral') { chain.push(me.property.value); } me = me.object; } if (me.type === 'ThisExpression') { chain.push('this'); } else if (me.type === 'Identifier') { chain.push(me.name); } return chain.reverse(); } /** * 生成独立JSX片段的对应template片段 * @param name * @param rs * @returns {JSXElement} */ function decTemlate(name, rs) { let arr = null; if (rs.type === 'ArrayExpression') { arr = [t.jsxText('\n'), ...rs.elements, t.jsxText('\n')]; } else { arr = [t.jsxText('\n'), rs, t.jsxText('\n')]; } return t.jsxElement(t.jsxOpeningElement(t.jsxIdentifier('template'), [t.jsxAttribute(t.jsxIdentifier('name'), t.stringLiteral(name))]), t.jsxClosingElement(t.jsxIdentifier('template')), arr, false); } /** * 判断是否是JSX的子元素 * * var x = <A><B/><C/></A> * * 其中 A不是, B,C都是JSX子元素。 * @param path * @returns {boolean} */ function isJSXChild(path) { return path.inList && path.listKey === 'children' && path.type === 'JSXElement'; } /** * 子元素是否需要被处理为 generic:抽象节点,一般来说,所有自定义组件都需要 * @param name * @returns {boolean} */ function isChildComp(name, filepath) { if (_constants.wxBaseComp.has(name) || _configure.default.configObj.miniprogramComponents[name]) return false; // 基本组件children 需要转化为childrencpt的组件 if (_getAndStorecompInfos.extChildComp.has(name)) { return true; } const { im } = (0, _cacheModuleInfos.getModuleInfo)(filepath); // 基本组件children 不需要转化为childrencpt的组件 if (_getAndStorecompInfos.allBaseComp.has(name)) { if (im[name] && !(0, _util.judgeLibPath)(im[name].source)) { console.log(`${filepath.replace(_configure.default.inputFullpath, '')} 组件名为${name}${name}基础组件名称重复,可能会导致渲染不成功,建议将${name}重新命名!`.warn); } return false; } // 自定义组件 children都需要转化为childrencpt return true; } /** * 判断 子元素是否是需要被处理为 generic: 抽象节点的情况 * @param path * @returns {any} */ function isChildCompChild(path, filepath) { const jc = isJSXChild(path); if (!jc) return false; const parentElement = path.parentPath; const name = parentElement.node.openingElement.name.name; return isChildComp(name, filepath); } /** * 是否是文本节点 * @param openingElement * @returns {any} */ function isTextElement(openingElement) { if (openingElement.name.name !== 'view') return false; return openingElement.attributes.some(item => item.type === 'JSXAttribute' && item.name.name === _constants.originElementAttrName && (item.value.value === _constants.outerTextOrigin || item.value.value === _constants.innerTextOrigin)); } /** * render方法直接返回JSX * * class A extends Component { * render() { * return <XX/> * } * * } * * class B extends Component { * render() { * if (c1) { * return <X/> * } else { * return <Y/> * } * } * } * * 以上: A的返回值 是true, B的返回值是false * * 微信小程序的自定义组件会退化为一个节点,需要有render的节点上报样式,对于A可以简化处理, * 对于B 理论上来说 任何一个独立JSX片段 都可能是上报的源 * * @type {boolean} */ function isRenderReturn(path) { const pp = path.parentPath.parentPath; if (pp.type !== 'ReturnStatement') return false; if (pp.parentPath.parentPath) { const pppp = pp.parentPath.parentPath; if (pppp.type === 'ClassMethod' && pppp.node.key.name === 'render') { return true; } } } /** * * @param path * @returns {any} */ function getOriginal(path) { const attr = getAttri(path, _constants.originElementAttrName); if (attr) { return attr.value.value; } return ''; } /** * 获取JSXElement的属性 * @param path * @param name * @returns {any} */ function getAttri(path, name) { const attris = path.node.attributes; for (let i = 0; i < attris.length; i++) { const item = attris[i]; if (item.type === 'JSXAttribute' && item.name.name === name) { return item; } } } /** * 给JSXOpeningElement 添加class类名, * * 1. <view/> ---> <view class="xx"/> * 2. <View class="aa"/> ---> <view class="aa xx"/> * * @param jsxOp * @param className */ function elementAddClass(jsxOp, className) { let hasClassAttr = false; jsxOp.attributes.forEach(attr => { if (attr.type === 'JSXAttribute' && attr.name.name === 'class') { hasClassAttr = true; attr.value.value = `${attr.value.value} ${className}`; } }); if (!hasClassAttr) { jsxOp.attributes.push(t.jsxAttribute(t.jsxIdentifier('class'), t.stringLiteral(className))); } } /** * 是否是React.Fragment节点 * @param node * @returns {any} */ function isReactFragment(node) { const name = node.name; if (name && name.type === 'JSXMemberExpression') { return isReactFragmentExpression(name); } return false; } /** * 是否是React.Fragment表达式 * @param node * @returns {any} */ function isReactFragmentExpression(jsxOp) { const object = jsxOp.object; const property = jsxOp.property; if (object && object.name === 'React' && property && property.name === 'Fragment') { return true; } return false; }