UNPKG

saven

Version:
412 lines 14.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const t = require("babel-types"); const babel_generator_1 = require("babel-generator"); const code_frame_1 = require("@babel/code-frame"); const constant_1 = require("./constant"); const lodash_1 = require("lodash"); const fs = require("fs"); const path = require("path"); const jsx_1 = require("./jsx"); const template = require('babel-template'); exports.incrementId = () => { let id = 0; return () => id++; }; function isVarName(str) { if (typeof str !== 'string') { return false; } if (str.trim() !== str) { return false; } try { // tslint:disable-next-line:no-unused-expression new Function(str, 'var ' + str); } catch (e) { return false; } return true; } exports.isVarName = isVarName; function findMethodName(expression) { let methodName; if (t.isIdentifier(expression) || t.isJSXIdentifier(expression)) { methodName = expression.name; } else if (t.isStringLiteral(expression)) { methodName = expression; } else if (t.isMemberExpression(expression) && t.isIdentifier(expression.property)) { const { code } = babel_generator_1.default(expression); const ids = code.split('.'); if (ids[0] === 'this' && ids[1] === 'props' && ids[2]) { methodName = code.replace('this.props.', ''); } else { methodName = expression.property.name; } } else if (t.isCallExpression(expression) && t.isMemberExpression(expression.callee) && t.isIdentifier(expression.callee.object)) { methodName = expression.callee.object.name; } else if (t.isCallExpression(expression) && t.isMemberExpression(expression.callee) && t.isMemberExpression(expression.callee.object) && t.isIdentifier(expression.callee.property) && expression.callee.property.name === 'bind' && t.isIdentifier(expression.callee.object.property)) { methodName = expression.callee.object.property.name; } else { throw codeFrameError(expression.loc, '当 props 为事件时(props name 以 `on` 开头),只能传入一个 this 作用域下的函数。'); } return methodName; } exports.findMethodName = findMethodName; function setParentCondition(jsx, expr, array = false) { const conditionExpr = jsx.findParent(p => p.isConditionalExpression()); const logicExpr = jsx.findParent(p => p.isLogicalExpression({ operator: '&&' })); if (conditionExpr && conditionExpr.isConditionalExpression()) { const consequent = conditionExpr.get('consequent'); if (consequent === jsx || jsx.findParent(p => p === consequent)) { expr = t.conditionalExpression(conditionExpr.get('test').node, expr, array ? t.arrayExpression([]) : t.nullLiteral()); } } if (logicExpr && logicExpr.isLogicalExpression({ operator: '&&' })) { const consequent = logicExpr.get('right'); if (consequent === jsx || jsx.findParent(p => p === consequent)) { expr = t.conditionalExpression(logicExpr.get('left').node, expr, array ? t.arrayExpression([]) : t.nullLiteral()); } } return expr; } exports.setParentCondition = setParentCondition; function generateAnonymousState(scope, expression, refIds, isLogical) { let variableName = `anonymousState_${scope.generateUid()}`; let statementParent = expression.getStatementParent(); if (!statementParent) { throw codeFrameError(expression.node.loc, '无法生成匿名 State,尝试先把值赋到一个变量上再把变量调换。'); } const jsx = isLogical ? expression : expression.findParent(p => p.isJSXElement()); const callExpr = jsx.findParent(p => p.isCallExpression() && isArrayMapCallExpression(p)); const ifExpr = jsx.findParent(p => p.isIfStatement()); const blockStatement = jsx.findParent(p => p.isBlockStatement() && p.parentPath === ifExpr); const expr = setParentCondition(jsx, lodash_1.cloneDeep(expression.node)); if (!callExpr) { refIds.add(t.identifier(variableName)); statementParent.insertBefore(buildConstVariableDeclaration(variableName, expr)); if (blockStatement && blockStatement.isBlockStatement()) { blockStatement.traverse({ VariableDeclarator: (p) => { const { id, init } = p.node; if (t.isIdentifier(id)) { const newId = scope.generateDeclaredUidIdentifier('$' + id.name); refIds.forEach((refId) => { if (refId.name === variableName && !variableName.startsWith('_$')) { refIds.delete(refId); } }); variableName = newId.name; refIds.add(t.identifier(variableName)); blockStatement.scope.rename(id.name, newId.name); p.parentPath.replaceWith(template('ID = INIT;')({ ID: newId, INIT: init })); } } }); } } else { variableName = `${constant_1.LOOP_STATE}_${callExpr.scope.generateUid()}`; const func = callExpr.node.arguments[0]; if (t.isArrowFunctionExpression(func)) { if (!t.isBlockStatement(func.body)) { func.body = t.blockStatement([ buildConstVariableDeclaration(variableName, expr), t.returnStatement(func.body) ]); } else { func.body.body.splice(func.body.body.length - 1, 0, buildConstVariableDeclaration(variableName, expr)); } } } const id = t.identifier(variableName); expression.replaceWith(id); return id; } exports.generateAnonymousState = generateAnonymousState; function isArrayMapCallExpression(callExpression) { return callExpression && t.isCallExpression(callExpression.node) && t.isMemberExpression(callExpression.node.callee) && t.isIdentifier(callExpression.node.callee.property, { name: 'map' }); } exports.isArrayMapCallExpression = isArrayMapCallExpression; function buildConstVariableDeclaration(variableName, expresion) { return t.variableDeclaration('const', [ t.variableDeclarator(t.identifier(variableName), expresion) ]); } exports.buildConstVariableDeclaration = buildConstVariableDeclaration; function setTemplate(name, path, templates) { const parentPath = path.parentPath; const jsxChildren = parentPath.findParent(p => p.isJSXElement()); if (name && !jsxChildren) { templates.set(name, path.node); } } exports.setTemplate = setTemplate; function isContainFunction(p) { let bool = false; p.traverse({ CallExpression() { bool = true; } }); return bool; } exports.isContainFunction = isContainFunction; function slash(input) { const isExtendedLengthPath = /^\\\\\?\\/.test(input); const hasNonAscii = /[^\u0000-\u0080]+/.test(input); const hasChinese = /[^\u4e00-\u9fa5]+/.test(input); // has Chinese characters if (isExtendedLengthPath || (hasNonAscii && !hasChinese)) { return input; } return input.replace(/\\/g, '/'); } function pathResolver(source, location) { const extName = path.extname(source); const promotedPath = source; if (!['js', 'tsx'].includes(extName)) { try { const pathExist = fs.existsSync(path.resolve(path.dirname(location), source, 'index.js')); const tsxPathExist = fs.existsSync(path.resolve(path.dirname(location), source, 'index.tsx')); if (pathExist || tsxPathExist) { let p = path.join(promotedPath, 'index'); if (!p.startsWith('.')) { p = './' + p; } return slash(p); } return slash(promotedPath); } catch (error) { return slash(promotedPath); } } return slash(promotedPath.split('.').slice(0, -1).join('.')); } exports.pathResolver = pathResolver; function codeFrameError(node, msg) { let errMsg = ''; try { errMsg = code_frame_1.codeFrameColumns(exports.setting.sourceCode, node && node.type && node.loc ? node.loc : node); } catch (error) { errMsg = 'failed to locate source'; } return new Error(`${msg} ----- ${errMsg}`); } exports.codeFrameError = codeFrameError; exports.setting = { sourceCode: '' }; function createUUID() { return '$' + 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { let r = Math.random() * 16 | 0; let v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }).replace(/-/g, '').slice(0, 8); } exports.createUUID = createUUID; function createRandomLetters(n) { const str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; return Array(n).join().split(',').map(function () { return str.charAt(Math.floor(Math.random() * str.length)); }).join(''); } exports.createRandomLetters = createRandomLetters; function isBlockIfStatement(ifStatement, blockStatement) { return ifStatement && blockStatement && ifStatement.isIfStatement() && blockStatement.isBlockStatement(); } exports.isBlockIfStatement = isBlockIfStatement; function buildCodeFrame(code) { return (loc) => code_frame_1.codeFrameColumns(code, loc); } exports.buildCodeFrame = buildCodeFrame; function isNumeric(n) { return !isNaN(parseFloat(n)) && isFinite(n); } exports.isNumeric = isNumeric; function buildJSXAttr(name, value) { return t.jSXAttribute(t.jSXIdentifier(name), t.jSXExpressionContainer(value)); } exports.buildJSXAttr = buildJSXAttr; function newJSXIfAttr(jsx, value, path) { const element = jsx.openingElement; if (!t.isJSXIdentifier(element.name)) { return; } if (element.name.name === 'Block' || element.name.name === 'block' || !path) { element.attributes.push(buildJSXAttr('wx:if', value)); } else { const block = jsx_1.buildBlockElement(); newJSXIfAttr(block, value); block.children.push(jsx); path.node = block; } } exports.newJSXIfAttr = newJSXIfAttr; function isContainJSXElement(path) { let matched = false; path.traverse({ JSXElement(p) { matched = true; p.stop(); } }); return matched; } exports.isContainJSXElement = isContainJSXElement; function hasComplexExpression(path) { let matched = false; if (isContainJSXElement(path)) { return false; } if (path.isObjectExpression()) { return true; } if (path.isTemplateLiteral() || path.isCallExpression()) { return true; } if (path.isArrayExpression()) { const { elements } = path.node; if (elements.some(el => t.isObjectExpression(el))) { return true; } } path.traverse({ CallExpression: (p) => { matched = true; p.stop(); }, TemplateLiteral(p) { matched = true; p.stop(); }, ObjectExpression(p) { matched = true; p.stop(); }, ArrayExpression(p) { const { elements } = p.node; if (elements.some(el => t.isObjectExpression(el))) { return true; } }, TaggedTemplateExpression(p) { matched = true; p.stop(); }, MemberExpression(path) { const jsxElement = path.findParent(p => p.isJSXExpressionContainer()); const object = path.get('object'); const property = path.get('property'); const parentPath = path.parentPath; if (jsxElement && object.isThisExpression() && property.isIdentifier({ name: 'state' }) && parentPath.isMemberExpression() && parentPath.parentPath.isMemberExpression()) { const sourceCode = parentPath.parentPath.getSource(); if (sourceCode.includes('[') && sourceCode.includes(']')) { matched = true; path.stop(); } } } }); return matched; } exports.hasComplexExpression = hasComplexExpression; function findFirstIdentifierFromMemberExpression(node, member) { let id; let object = node.object; while (true) { if (t.identifier(object) && !t.isMemberExpression(object)) { id = object; if (member) { object = member; } break; } object = object.object; } return id; } exports.findFirstIdentifierFromMemberExpression = findFirstIdentifierFromMemberExpression; function getArgumentName(arg) { if (t.isThisExpression(arg)) { return 'this'; } else if (t.isNullLiteral(arg)) { return 'null'; } else if (t.isStringLiteral(arg) || t.isNumericLiteral(arg)) { return arg.value; } else if (t.isIdentifier(arg)) { return arg.name; } else { return babel_generator_1.default(arg).code; } throw new Error(`bind 不支持传入该参数: ${arg}`); } exports.getArgumentName = getArgumentName; function isAllLiteral(...args) { return args.every(p => t.isLiteral(p)); } exports.isAllLiteral = isAllLiteral; function reverseBoolean(expression) { return t.unaryExpression('!', expression); } exports.reverseBoolean = reverseBoolean; function isEmptyDeclarator(node) { if (t.isVariableDeclarator(node) && (node.init === null || t.isNullLiteral(node.init))) { return true; } return false; } exports.isEmptyDeclarator = isEmptyDeclarator; function toLetters(num) { let mod = num % 26; let pow = num / 26 | 0; let out = mod ? String.fromCharCode(64 + mod) : (--pow, 'Z'); const letter = pow ? toLetters(pow) + out : out; return letter.toLowerCase(); } exports.toLetters = toLetters; function findIdentifierFromStatement(statement) { if (t.isVariableDeclaration(statement)) { const declarator = statement.declarations.find(s => t.isIdentifier(s.id)); if (declarator && t.isIdentifier(declarator.id)) { return declarator.id.name; } } return '__return'; } exports.findIdentifierFromStatement = findIdentifierFromStatement; //# sourceMappingURL=utils.js.map