UNPKG

@antmove/alipay-wx

Version:

transform alipay miniprogram to wx miniprogram tool.

365 lines (339 loc) 12 kB
const propsHandle = require('../props/index.js'); const proccessComponentProps = require('../component/props'); let { ref } = require('../config'); const { transformEs6, processMixTemplate } = require('@antmove/utils'); const os = require('os'); const indentWidthChar = ' '; let isAddWxs = false; let funName = ''; /** * @special tags */ function createElement (tagName, children = []) { return { typeof: 'element', key: null, props: {}, type: tagName, children }; } function processSpecialTags (ast = {}) { if (ast.type === 'picker' && ast.children[0].length > 1) { ast.children[0] = [createElement('view', ast.children[0])]; return ast; } } function addWxKey (props) { if (props["a:for"]) { if (!props["a:key"]) { props = Object.assign(props, { 'a:key': { type: 'unknown', value: ['{{index}}'] } }); } } return props; } function transformTypeof (val) { let str = ''; let params = ''; if (/typeof\s*\w+/.test(val)) { val = val.replace(/typeof\s*\w+/, function (a) { str = a.replace(/ +/, ' '); params = str.split(' ')[1]; a = ` custom.isTypeof(${params}) `; return a; }); } if (/typeof\s*\((.+?)\)/.test(val)) { val = val.replace(/typeof\s*\((.+?)\)/, function (a) { str = a.match(/\((.+?)\)/)[0]; params = str.slice(1, str.length - 1); a = ` custom.isTypeof(${params}) `; return a; }); } if (!funName.includes('isTypeof')) { funName += "\n\t\tisTypeof: function(val) {\n\t\t\treturn typeof(val);\n\t\t},"; } return val; } function transformFun (type, val) { val = val.replace(/{{(.*?)}}/, function (a) { type = 'is' + type.charAt(0).toUpperCase() + type.slice(1); let params = a.match(/\w+.?/)[0]; params = params.slice(0, params.length - 1); let str = a.slice(2, a.length - 2); const reg = new RegExp(`${params}`); str = str.replace(reg, '__item'); if (!funName.includes(type)) { funName += `\n\t\t${type}: function(__item) {\n\t\t\treturn ${str};\n\t\t},`; } a = `{{ custom.${type}(${params}) }}`; return a; }); return val; } function transformToString (val) { val = val.replace(/{{(.*\.toString\(\)).*}}/, function (value) { const text = RegExp.$1.toString().split('.')[0]; const str = `custom._toString(${text})`; if (!funName.includes('_toString')) { funName += `\n\t\t_toString: function(val) {\n\t\t\treturn val.toString();\n\t\t},`; } const reg = new RegExp(text); value = value.replace(/\.toString\(\)/, ''); value = value.replace(reg, str); return value; }); return val; } function appendWxs (val) { let arr = ['typeof', 'some', 'every', 'forEach', 'reduce', 'filter', 'toString']; let type = ''; let value = ''; if (val) { value = val.match(/{{(.*?)}}/); } if (value !== null) { arr.some(item => { if (value[0] && value[0].includes(item)) { type = item; return true; } return false; }); switch (type) { case 'typeof': val = transformTypeof(val); break; case 'toString': val = transformToString(val); break; case 'some': val = transformFun(type, val); break; case 'every': val = transformFun(type, val); break; case 'forEach': val = transformFun(type, val); break; case 'reduce': val = transformFun(type, val); break; case 'filter': val = transformFun(type, val); break; default: break; } if (type !== '') { isAddWxs = true; } } return val; } function transformStyle (value) { value = value.trim(); const reg = /{\s?[a-zA-Z]+:.+}/; if (reg.test(value)) { let val = value.slice(1, value.length - 1); val = val.replace(/ +/g, ''); let comma = val.charAt(val.length - 2); if (comma === ',') { const index = val.lastIndexOf(comma); val = val.slice(0, index) + '}'; } value = `{{ custom.transformStyle(${val}) }}`; isAddWxs = true; } if (!funName.includes('transformStyle')) ( funName += `\n\t\ttransformStyle: function(value) {\n\t\t\tvalue = JSON.stringify(value);\n\t\t\tvalue = value.slice(1, value.length - 1);\n\t\t\tlet val ='';\n\t\t\tfor(var i = 0; i < value.length; i++){\n\t\t\t\tif (value[i] !== '"') {\n\t\t\t\t\tif (value.indexOf('transform') === -1) {\n\t\t\t\t\t\tif(value[i] === ','){\n\t\t\t\t\t\t\tval += ';';\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tval += '';\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif(value.charCodeAt(i) >= 65 && value.charCodeAt(i) <= 90) {\n\t\t\t\t\tval += '-' + value[i].toLowerCase();\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tval += value[i];\n\t\t\t}\n\t\t\treturn val;\n\t\t},` ); return value; } function transformStringTemplate (prop) { let value = prop.value.value[0].replace(/ /g, ''); const reg = /^{{`(.+)`}}$/; if (reg.test(value)) { let arr = RegExp.$1.split('$'); let str = arr[1].trim().match(/\s*{.+}/)[0]; str = str.slice(1, str.length - 1); arr[1] = `{{ ${str} }}`; value = arr.join(''); prop.value.value[0] = value; } } function transformSjs (ast) { ast.type = 'wxs'; ast.props['module'] = ast.props.name; ast.props['src'] = ast.props.from; delete ast.props.name; delete ast.props.from; return ast; } function transformRef (prop, filePath) { prop.id = { type: 'unknown', value: prop.ref.value}; const filename = filePath.replace(/\.axml/, '.js'); let obj = { id: prop.ref.value[0], filename }; ref = Object.assign(ref, obj); delete prop.ref; } function transformInput (ast) { if (ast.props[undefined]) { ast.props['type'] = { type: 'unknown', value: ast.props[undefined].value }; delete ast.props[undefined]; } } module.exports = function axmlRender (ast = [], fileInfo) { if (typeof ast === 'string') return ast; let wxsLabel = `<wxs module="custom">\n`; let wxsCode = `\tmodule.exports = {`; isAddWxs = false; let _code = ''; let indentWidth = ''; ast.forEach(function (tagAst) { _code += renderFn(tagAst, fileInfo); }); if (isAddWxs) { wxsCode += funName; wxsCode += '\n\t}'; wxsCode = transformEs6(wxsCode); wxsLabel += wxsCode; wxsLabel += `\n</wxs>`; _code += wxsLabel; } funName = ''; _code = _code.replace(/<text[^>]*\s*.*>\s*.+\s*<\/text>/g, function (val) { val = val.replace(/\r|\n/g, ''); val = val.replace(/ +/g, ' '); return val; }); return _code; function incIndent () { indentWidth += indentWidthChar; } function decIndent () { indentWidth = indentWidth.slice(0, -1 * indentWidthChar.length); } function renderFn (_ast, _fileInfo) { let { props } = _ast; proccessComponentProps(_ast, _fileInfo, axmlRender); processSpecialTags(_ast); _ast.value = appendWxs(_ast.value); if (props && props['style']) { props['style'].value[0] = transformStyle(props['style'].value[0]); } if (_ast.props) { Object.values(_ast.props).forEach(obj => { obj['value'][0] = appendWxs(obj['value'][0]); }); } if (_ast.type === 'import-sjs') { transformSjs(_ast); } if (_ast.type === 'input') { transformInput(_ast); } if (props && props['ref']) { transformRef(props, fileInfo.path); } if (_ast.type === 'textContent') { // todo: fix comment parse bug if (_ast.value.match(/-->/)) { return ''; } return `${_ast.value}`; } let code = ''; let tagName = _ast.type; let children = _ast.children; appendCode(`<${tagName}`); props = addWxKey(props); props = props || {}; let attrCode = ''; Object.keys(props) .forEach(function (prop) { let propInfo = propsHandle(prop, props[prop], ast); transformStringTemplate(propInfo); // a:for process if (propInfo.key === 'wx:for-items' || propInfo.key === 'a:for-items') { propInfo.key = 'a:for'; } if (propInfo.value === null) { // 无值属性 attrCode += ` ${propInfo.key}`; } else { let value = propInfo.value.value[0] || ''; value = value.replace(/\.axml/g, '.wx') .replace(/\.sjs/g, '.wxs'); /** * support unknown type string * */ if (propInfo.value && propInfo.value.type === 'unknown') { let singleIndex = value.indexOf("'"); let doubleIndex = value.indexOf('"'); singleIndex = singleIndex > -1 ? singleIndex : 0; doubleIndex = doubleIndex > -1 ? doubleIndex : 0; if (singleIndex > doubleIndex) { propInfo.value.type = 'double'; } else { propInfo.value.type = 'single'; } } if (propInfo.value && propInfo.value.type === 'double') { attrCode += ` ${propInfo.key}="${value}"`; } else { if (value === '' || value === undefined || !value) { attrCode += ` ${propInfo.key}`; } else { attrCode += ` ${propInfo.key}='${value}'`; } } } }); /** * close element */ if (children === undefined) { appendCode(`${attrCode}/>`); // decIndent() } else { appendCode(`${attrCode}>`); incIndent(); // children element if (Array.isArray(children)) { children.forEach(function (child) { if (Array.isArray(child)) { child.forEach(function (subChild) { appendCode(renderFn(subChild, _fileInfo)); }); } else { appendCode(renderFn(child, _fileInfo)); } }); } else { appendCode(children); } decIndent(); appendCode(`</${tagName}>`); } return code.replace(os.EOL + os.EOL, os.EOL); function appendCode (appendChars) { let isType = processMixTemplate('wx', _ast); if (!isType) return; if (appendChars.trim().length === 0) { return; } if (appendChars.startsWith('<')) { code += (appendChars.startsWith('</') ? os.EOL : '') + String(indentWidth) + appendChars; } else if (appendChars.endsWith('>')) { code += appendChars + os.EOL; } else { code += indentWidth + appendChars; } } } };