// --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
}