// --inspect-brk const t = require('@babel/types'); const _ = module.exports = {}; const utils = _; const babylon = require('babylon'); const traverse = require('@babel/traverse')["default"]; const generate = require('@babel/generator')["default"]; const weexMixins = require('chameleon-mixins/weex-mixins.js'); _.trimCurly = (str) => str.replace(/(?:{{)|(?:}})/ig, ''); _.getModelKey = function(modelKey) { modelKey = _.trimCurly(modelKey); modelKey = modelKey.trim(); return modelKey; } // 驼峰化单词 _.camelize = function(str) { return str.replace(/[-_\s]+(.)/g, function(match, key) { return key ? key.toUpperCase() : ''; }) } // 中划线化单词 _.dasherise = function(str) { return str.replace(/([A-Z])/g, '-$1').replace(/[-_\s]+/g, '-') .toLowerCase(); } _.analysisFor = function (nodeValue) { // v-for="item in items" let reg1 = /\s*(.+?)\s+(?:in|of)\s+(.+)\s*/; // v-for="(item, index) in items" let reg2 = /\s*\(\s*([^\,\s]+?)\s*\,\s*([^\,\s]+?)\s*\)\s*(?:in|of)\s+(.+)\s*/ let item, index, list; let matches1 = nodeValue.match(reg1); let matches2 = nodeValue.match(reg2); if (matches2) { item = matches2[1]; index = matches2[2]; list = matches2[3]; } else if (matches1) { item = matches1[1]; index = 'index'; list = matches1[2]; } return { item, index, list } } _.titleLize = function (word) { return word.replace(/^\w/, function (match) { return match.toUpperCase(); }) } // ast遍历相关 _.getSiblingPaths = function (path) { let container = path.container; let siblingPaths = []; for (let i = 0; i < container.length; i++) { siblingPaths.push(path.getSibling(i)); } return siblingPaths; } /* 获取某个jsxElement 上的某个具体属性的值* @params: path:代表JSXElement的path值 return 该JSXElement上所有的属性集合 */ _.getJSXElementAttrKeyValue = function (path) { let attributes = path.node.openingElement.attributes || []; return attributes.reduce((attrMap, attr) => { let key = attr.name.name; let value = attr.value.value; if (typeof key === 'string') { attrMap[key] = value } return attrMap; }, {}); } _.trim = function (value) { return value.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); }; _.isInlineStatementFn = function (statament) { let reg = /\(([\s\S]*?)\)/; return statament.match(reg); } // 判断函数参数值在微信中是否是响应式的属性,'index' 代表字符串 'index'+1 代表表达式; _.isReactive = function (value) { let reg = /(?:^'([^']*?)'$)/; return _.trim(value).match(reg); } _.doublequot2singlequot = function (value) { return value.replace(/["]/g, "'"); } _.isMustacheReactive = function (value) { let reg = /(?=.*[{]{2})(?=.*[}]{2})/; return reg.test(value); } _.isOnlySpaceContent = function(value) { let reg = /[^\s]+/; return !reg.test(value); } _.getReactiveValue = function(nodeValue) { let vLength = nodeValue && nodeValue.length; const newValue = []; if (nodeValue && _.isMustacheReactive(nodeValue)) { for (let idx = 0; idx < vLength; idx++) { if (nodeValue[idx] === '{' && idx < vLength - 1 && nodeValue[idx + 1] === '{') { newValue.push("'+("); idx++; } else if (nodeValue[idx] === '}' && idx < vLength - 1 && nodeValue[idx + 1] === '}') { newValue.push(")+'"); idx++; } else { newValue.push(nodeValue[idx]); } } if (newValue.length != 0) { newValue.push("'"); newValue.unshift("'"); const nl = newValue.length; if (nl > 2 && newValue[nl - 1] === "'" && newValue[nl - 2] === ")+'") { newValue.splice(-2, 2); newValue.push(')'); } if (newValue.length > 2 && newValue[0] === "'" && newValue[1] === "'+(") { newValue.splice(0, 2); newValue.unshift('('); } nodeValue = newValue.join(''); } } return nodeValue; }; // 从 let value = `a b {{true ? 'cls1':'cls2'}} c d {{true ? 'cls1':'cls2'}} `;获取 `a b c d` _.getStaticValueFromMixinValue = function(value) { let reg = /[{]{2}[^{}]*?[}]{2}/g; return value.replace(reg, ' '); } /** * @params: * {{'width{'}} {{'width+++'}} cpx:300 cpx:'300cpx' @returnvalue: 将非变量cpx单位转化为rpx; 转化策略: 1 首先将非 {{}} 内的cpx全部转化为rpx,因为非{{}}内的肯定都是cpx这个单位; 2 转化 {{}} 内的cpx 单位,而不能转化变量cpx, */ _.transformWxDynamicStyleCpxToRpx = function(value) { let reg = /[{]{2}([^{}]*?)[}]{2}/g; value = _.transformNotInMustacheCpxToRpx(value); value = value.replace(reg, (match, statement) => `{{${_.transformMustacheCpxToRpx(statement)}}}`); value = _.doublequot2singlequot(value) return value; } _.transformNotInMustacheCpxToRpx = function(value) { let isNotMustacheCpxToRpxReg = /([^{}]+)?(\{\{[^{}]+\}\})?/g; let temp = ''; value.replace(isNotMustacheCpxToRpxReg, (match, $1, $2, $3) => { if ($1) { temp += $1.replace(/cpx/g, 'rpx'); } if ($2) { temp += $2; } }); return temp } _.transformMustacheCpxToRpx = function(source) { const ast = babylon.parse(source, { plugins: ['jsx'] }) traverse(ast, { enter(path) { let node = path.node; if (t.isStringLiteral(node)) { if (node.value.includes('cpx')) { node.value = node.value.replace(/cpx/g, `rpx`); } } } }) let result = generate(ast).code; if (/;$/.test(result)) { // 这里有个坑,jsx解析语法的时候,默认解析的是js语法,所以会在最后多了一个 ; 字符串;但是在 html中 ; 是无法解析的; result = result.slice(0, -1); } return result } _.handleVUEClassNodes = function (options) { let { type } = options; _[`${type}VUEClassNodes`](options); } _.webVUEClassNodes = function (options) { let { classNodes, attributes, extraClass } = options; if (classNodes.length === 0) { extraClass && attributes.push(t.jsxAttribute(t.jsxIdentifier('class'), t.stringLiteral(extraClass))) } else if (classNodes.length === 1) { // 可能是动态class或者静态class classNodes.forEach((itemNode) => { if (t.isJSXNamespacedName(itemNode.name)) { // 动态的 extraClass && attributes.push(t.jsxAttribute(t.jsxIdentifier('class'), t.stringLiteral(extraClass))) } else {// 静态的 itemNode.value.value = `${itemNode.value.value} ${extraClass}` } }) } else if (classNodes.length === 2) { classNodes.forEach((itemNode) => { if (t.isJSXNamespacedName(itemNode.name)) { // 动态的 } else { // 静态的 itemNode.value.value = `${itemNode.value.value} ${extraClass}` } }) } } _.weexVUEClassNodes = function (options) { let { classNodes, attributes, extraClass } = options; if (classNodes.length === 0) { extraClass && attributes.push(t.jsxAttribute(t.jsxIdentifier('class'), t.stringLiteral(extraClass))) } else if (classNodes.length === 1) { // 可能是动态class或者静态class classNodes.forEach((itemNode) => { if (t.isJSXNamespacedName(itemNode.name)) { // 动态的 extraClass && attributes.push(t.jsxAttribute(t.jsxIdentifier('class'), t.stringLiteral(extraClass))); let newClassNodeValue = utils.trimCurly(itemNode.value.value); itemNode.value.value = `${weexMixins.weexClassProxy}((${newClassNodeValue}))` } else {// 静态的 itemNode.value.value = `${itemNode.value.value} ${extraClass}` } }) } else if (classNodes.length === 2) { classNodes.forEach((itemNode) => { if (t.isJSXNamespacedName(itemNode.name)) { // 动态的 // itemNode.value.value = `[(${itemNode.value.value})]`; let newClassNodeValue = utils.trimCurly(itemNode.value.value); itemNode.value.value = `${weexMixins.weexClassProxy}((${newClassNodeValue}))` } else { // 静态的 itemNode.value.value = `${itemNode.value.value} ${extraClass}` } }) } } _.miniappVUEClassNodes = function (options) { let { classNodes, attributes, extraClass } = options; if (classNodes.length === 0) { extraClass && attributes.push(t.jsxAttribute(t.jsxIdentifier('class'), t.stringLiteral(extraClass))) } else if (classNodes.length === 1) { // 可能是动态class或者静态class classNodes.forEach((itemNode) => { // itemNode.value.value = `${itemNode.value.value} ${extraClass}` if (t.isJSXNamespacedName(itemNode.name)) { let newValue = `{{${itemNode.value.value}}} ${extraClass}`; let classNodeIndex = attributes.indexOf(itemNode) if (classNodeIndex !== -1) { attributes.splice(classNodeIndex, 1) } attributes.push(t.jsxAttribute(t.jsxIdentifier('class'), t.stringLiteral(newValue))); } else { itemNode.value.value = `${itemNode.value.value} ${extraClass}` } }) } else if (classNodes.length === 2) { let reactiveClassNode = classNodes.find((item) => t.isJSXNamespacedName(item.name)); let staticClassNode = classNodes.find((item) => t.isJSXIdentifier(item.name)); let reactiveClassNodeValue = reactiveClassNode && reactiveClassNode.value.value; let staticClassNodeValue = staticClassNode && staticClassNode.value.value; let newValue = `{{${reactiveClassNodeValue}}} ${staticClassNodeValue} ${extraClass}` attributes.push(t.jsxAttribute(t.jsxIdentifier('class'), t.stringLiteral(newValue))) classNodes.forEach((classNode) => { let classNodeIndex = attributes.indexOf(classNode); if (classNodeIndex !== -1) { attributes.splice(classNodeIndex, 1) } }) } } // 转换 $event参数 _.getInlineStatementArgs = function(argsStr) { // argsStr:"1,'index'+1,$event,'item',index+1,item" const result = argsStr.split(',').reduce((result, current, index) => { if (current === '$event') { result.push("'$event'"); } else { result.push(current) } return result }, []); return result.join();// "1,'index'+1,'$event','item',index+1,item" } _.isOriginTagOrNativeComp = function(tagName, options) { let usedComponentInfo = (options.usingComponents || []).find((item) => item.tagName === tagName) let isNative = usedComponentInfo && usedComponentInfo.isNative; let isOrigin = (tagName && typeof tagName === 'string' && tagName.indexOf('origin-') === 0); if (isOrigin || isNative) { return true } return false; } // 判断是否是原生组件 _.isNativeComp = function(tagName, options) { let usedComponentInfo = (options.usingComponents || []).find((item) => item.tagName === tagName) let isNative = usedComponentInfo && usedComponentInfo.isNative; return isNative } // 判断是否是组件,不包括第三方原生组件 // {button: "cml-buildin-button"}, _.isNotNativeComponent = function(tagName, options) { let usingComponents = options.usingComponents || []; let buildInComponents = options.buildInComponents || {}; let isComponent = usingComponents.find((comp) => ((comp.tagName === tagName) && !comp.isNative) ) || Object.values(buildInComponents).includes(tagName); return isComponent }