206 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
		
		
			
		
	
	
			206 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
|  | /** | ||
|  |  * @fileoverview 将微信端的代码转换到各个平台 | ||
|  |  */ | ||
|  | const through2 = require('through2') | ||
|  | 
 | ||
|  | // api 前缀
 | ||
|  | const prefix = { | ||
|  |   weixin: { | ||
|  |     wxml: 'wx:', | ||
|  |     js: 'wx.' | ||
|  |   }, | ||
|  |   qq: { | ||
|  |     wxml: 'qq:', | ||
|  |     js: 'qq.' | ||
|  |   }, | ||
|  |   baidu: { | ||
|  |     wxml: 's-', | ||
|  |     js: 'swan.' | ||
|  |   }, | ||
|  |   alipay: { | ||
|  |     wxml: 'a:', | ||
|  |     js: 'my.' | ||
|  |   }, | ||
|  |   toutiao: { | ||
|  |     wxml: 'tt:', | ||
|  |     js: 'tt.' | ||
|  |   } | ||
|  | } | ||
|  | // 文件名后缀
 | ||
|  | const suffix = { | ||
|  |   weixin: { | ||
|  |     wxml: '.wxml', | ||
|  |     wxss: '.wxss' | ||
|  |   }, | ||
|  |   qq: { | ||
|  |     wxml: '.qml', | ||
|  |     wxss: '.qss' | ||
|  |   }, | ||
|  |   baidu: { | ||
|  |     wxml: '.swan', | ||
|  |     wxss: '.css' | ||
|  |   }, | ||
|  |   alipay: { | ||
|  |     wxml: '.axml', | ||
|  |     wxss: '.acss' | ||
|  |   }, | ||
|  |   toutiao: { | ||
|  |     wxml: '.ttml', | ||
|  |     wxss: '.ttss' | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * @description 取出两个括号之间的内容 | ||
|  |  * @param {string} content 总内容 | ||
|  |  * @param {number} i 开始位置 | ||
|  |  */ | ||
|  | function getSection (content, i) { | ||
|  |   let j = i + 1 | ||
|  |   let num = 1 | ||
|  |   const start = content[i] | ||
|  |   const end = start === '(' ? ')' : '}' | ||
|  |   while (num) { | ||
|  |     if (content[j] === start) { | ||
|  |       num++ | ||
|  |     } else if (content[j] === end) { | ||
|  |       num-- | ||
|  |     } | ||
|  |     j++ | ||
|  |   } | ||
|  |   return content.substring(i, j) | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * @description 处理不同小程序平台间的差异 | ||
|  |  * @param {string} platform 使用平台 | ||
|  |  */ | ||
|  | module.exports = function (platform) { | ||
|  |   if (platform !== 'uni-app') { | ||
|  |     platform = platform.split('-')[1] | ||
|  |   } | ||
|  |   return through2.obj(function (file, _, callback) { | ||
|  |     if (file.isBuffer()) { | ||
|  |       let content = file.contents.toString() | ||
|  |       if (platform === 'uni-app') { | ||
|  |         if (file.extname === '.js') { | ||
|  |           content = content.replace(/\.properties/g, '') | ||
|  |         } | ||
|  |       } else { | ||
|  |         // wxml 文件处理
 | ||
|  |         if (file.extname === '.wxml') { | ||
|  |           content = content.replace(/wx:/g, prefix[platform].wxml) // 替换 api 前缀
 | ||
|  |           file.extname = suffix[platform].wxml // 修改后缀名
 | ||
|  |           if (platform === 'qq') { | ||
|  |             // wxs 转为 qs
 | ||
|  |             content = content.replace(/<wxs/g, '<qs').replace(/<\/wxs/g, '</qs') | ||
|  |           } else if (platform === 'baidu') { | ||
|  |             content = content.replace(/s-if=['"]{{(\S+)}}['"]/g, 's-if="$1"') // s-if 和 s-for 后不加 {{}}
 | ||
|  |               .replace(/s-for=['"]{{(\S+)}}['"]/g, 's-for="$1"') | ||
|  |               .replace(/data="(.*?)"/g, 'data="{$1}"') | ||
|  |           } else if (platform === 'alipay') { | ||
|  |             content = content.replace('block-size', 'handle-size') | ||
|  |               .replace(/longpress/g, 'longTap') | ||
|  |               .replace(/bind([\S])/g, (_, $1) => { // bindevent 转为 onEvent
 | ||
|  |                 return 'on' + $1.toUpperCase() | ||
|  |               }).replace(/catch([\S])/g, (_, $1) => { // catchevent 转为 catchEvent
 | ||
|  |                 return 'catch' + $1.toUpperCase() | ||
|  |               }) | ||
|  |           } | ||
|  |         } else if (file.extname === '.js') { | ||
|  |           // js 文件处理
 | ||
|  |           // 替换 api 前缀
 | ||
|  |           content = content.replace(/wx\./g, prefix[platform].js) | ||
|  | 
 | ||
|  |           // 支付宝格式转换
 | ||
|  |           if (platform === 'alipay') { | ||
|  |             // 将 aa.triggerEvent('bb', cc) 替换为 aa.props.onBb && aa.props.onBb(cc)
 | ||
|  |             content = content.replace(/([a-zA-Z0-9._]+).triggerEvent\(['"](\S+?)['"],*/g, function (_, $1, $2) { | ||
|  |               const method = `${$1}.props.on${$2[0].toUpperCase()}${$2.slice(1)}` | ||
|  |               return `${method}&&${method}(` | ||
|  |             }) | ||
|  | 
 | ||
|  |             // 转换 showToast
 | ||
|  |             let i = content.indexOf('.showToast') | ||
|  |             while (i !== -1) { | ||
|  |               i += 10 | ||
|  |               const section = getSection(content, i) | ||
|  |               content = content.substr(0, i) + section.replace('title', 'content') + content.substr(i + section.length) | ||
|  |               i = content.indexOf('.showToast', i) | ||
|  |             } | ||
|  |             // 转换 showActionSheet
 | ||
|  |             i = content.indexOf('.showActionSheet') | ||
|  |             while (i !== -1) { | ||
|  |               i += 16 | ||
|  |               const section = getSection(content, i) | ||
|  |               content = content.substr(0, i) + section.replace('itemList', 'items') + content.substr(i + section.length) | ||
|  |               i = content.indexOf('.showActionSheet', i) | ||
|  |             } | ||
|  |             // 转换 setClipboardData
 | ||
|  |             i = content.indexOf('.setClipboardData') | ||
|  |             while (i !== -1) { | ||
|  |               i += 17 | ||
|  |               const section = getSection(content, i) | ||
|  |               content = content.substr(0, i - 4) + section.replace('data', 'text') + content.substr(i + section.length) | ||
|  |               i = content.indexOf('.setClipboardData', i) | ||
|  |             } | ||
|  |             // 组件格式转换
 | ||
|  |             if (content.includes('Component({')) { | ||
|  |               // 替换生命周期
 | ||
|  |               content = content.replace('created:', 'didMount:') | ||
|  |                 .replace('attached:', 'didMount:') | ||
|  |                 .replace('detached:', 'didUnmount:') | ||
|  |               // 将 properties 字段转为 props 格式
 | ||
|  |               i = content.indexOf('{', content.indexOf('properties:')) | ||
|  |               let props | ||
|  |               let propsStr = '{' | ||
|  |               const objStr = getSection(content, i) | ||
|  |               // 取出整个 properties 字段
 | ||
|  |               eval('props = ' + objStr) // eslint-disable-line
 | ||
|  |               for (const item in props) { | ||
|  |                 if (!props[item]) continue | ||
|  |                 propsStr += item + ':' | ||
|  |                 if (props[item].value) { | ||
|  |                   // 设置了默认值
 | ||
|  |                   if (typeof props[item].value === 'boolean') { | ||
|  |                     propsStr += props[item].value ? '!0' : '!1' | ||
|  |                   } else { | ||
|  |                     propsStr += props[item].value | ||
|  |                   } | ||
|  |                 } else { | ||
|  |                   // 没有设置默认值
 | ||
|  |                   const type = props[item].type || props[item] | ||
|  |                   if (type === String) { | ||
|  |                     propsStr += '""' | ||
|  |                   } else if (type === Boolean) { | ||
|  |                     propsStr += '!1' | ||
|  |                   } else if (type === Number) { | ||
|  |                     propsStr += '0' | ||
|  |                   } else if (type === Object) { | ||
|  |                     propsStr += '{}' | ||
|  |                   } else if (type === Array) { | ||
|  |                     propsStr += '[]' | ||
|  |                   } | ||
|  |                 } | ||
|  |                 propsStr += ',' | ||
|  |               } | ||
|  |               content = content.substr(0, i) + propsStr.substring(0, propsStr.length - 1) + '}' + content.substr(i + objStr.length) | ||
|  |             } | ||
|  | 
 | ||
|  |             content = content.replace(/properties/g, 'props') | ||
|  |               .replace(/\.setNavigationBarTitle/g, '.setNavigationBar') | ||
|  |           } else { | ||
|  |             content = content.replace(/\.properties/g, '.data') | ||
|  |           } | ||
|  |         } else if (file.extname === '.wxss') { | ||
|  |           // wxss 文件处理
 | ||
|  |           file.extname = suffix[platform].wxss // 修改后缀名
 | ||
|  |         } | ||
|  |       } | ||
|  |       file.contents = Buffer.from(content) | ||
|  |     } | ||
|  |     this.push(file) | ||
|  |     callback() | ||
|  |   }) | ||
|  | } |