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()
 | |
|   })
 | |
| }
 |