├── .eslintignore ├── index.js ├── tools ├── dcloud_stat │ └── dcloud_stat_conf.js └── sign │ └── README.md ├── src ├── packer.js ├── weapp │ ├── transform │ │ ├── helper │ │ │ ├── tag │ │ │ │ ├── form │ │ │ │ │ ├── input │ │ │ │ │ │ ├── input.css │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── form │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── form.css │ │ │ │ │ ├── picker-view │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── textarea │ │ │ │ │ │ ├── textarea.css │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── radio │ │ │ │ │ │ ├── radio-group │ │ │ │ │ │ │ ├── radio-group.css │ │ │ │ │ │ │ └── index.js │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── checkbox │ │ │ │ │ │ ├── checkbox-group │ │ │ │ │ │ │ ├── checkbox-group.css │ │ │ │ │ │ │ └── index.js │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── label │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── switch │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── slider │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── picker │ │ │ │ │ │ └── index.js │ │ │ │ │ └── button │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── button.css │ │ │ │ ├── map │ │ │ │ │ └── map │ │ │ │ │ │ └── index.js │ │ │ │ ├── canvas │ │ │ │ │ └── canvas │ │ │ │ │ │ └── index.js │ │ │ │ ├── media │ │ │ │ │ ├── camera │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── live-player │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── live-pusher │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── video │ │ │ │ │ │ ├── video.css │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── audio │ │ │ │ │ │ └── index.js │ │ │ │ │ └── image │ │ │ │ │ │ └── index.js │ │ │ │ ├── logic │ │ │ │ │ ├── import │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── block │ │ │ │ │ │ └── index.js │ │ │ │ │ └── template │ │ │ │ │ │ └── index.js │ │ │ │ ├── open │ │ │ │ │ ├── open-data │ │ │ │ │ │ └── index.js │ │ │ │ │ └── web-view │ │ │ │ │ │ └── index.js │ │ │ │ ├── view │ │ │ │ │ ├── cover-view │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── cover-image │ │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── movable-view │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── movable-area │ │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── list-item │ │ │ │ │ │ ├── list-item.css │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── swiper │ │ │ │ │ │ ├── swiper-item │ │ │ │ │ │ │ └── index.js │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── view │ │ │ │ │ │ └── index.js │ │ │ │ │ └── scroll-view │ │ │ │ │ │ └── index.js │ │ │ │ ├── navigator │ │ │ │ │ └── navigator │ │ │ │ │ │ ├── navigator.css │ │ │ │ │ │ └── index.js │ │ │ │ ├── deprecated │ │ │ │ │ ├── modal │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── toast │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── contact-button │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── loading │ │ │ │ │ │ └── index.js │ │ │ │ │ └── action-sheet │ │ │ │ │ │ └── index.js │ │ │ │ ├── basic │ │ │ │ │ ├── icon │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── text │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── progress │ │ │ │ │ │ └── index.js │ │ │ │ │ └── rich-text │ │ │ │ │ │ └── index.js │ │ │ │ ├── util.js │ │ │ │ └── index.js │ │ │ ├── style │ │ │ │ ├── declaration │ │ │ │ │ ├── color │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── list │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── transition │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── margin │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── padding │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── transform │ │ │ │ │ │ └── transform.js │ │ │ │ │ ├── component │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── font │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── text │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── dimension │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── box │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── background │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── flexbox │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── position │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── animation │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── index.js │ │ │ │ │ └── border │ │ │ │ │ │ └── index.js │ │ │ │ ├── uniapp.css │ │ │ │ ├── selector │ │ │ │ │ └── index.js │ │ │ │ ├── index.js │ │ │ │ └── util.js │ │ │ ├── event │ │ │ │ ├── switch │ │ │ │ │ └── index.js │ │ │ │ ├── radio │ │ │ │ │ └── index.js │ │ │ │ ├── slider │ │ │ │ │ └── index.js │ │ │ │ ├── swiper │ │ │ │ │ └── index.js │ │ │ │ ├── tabs │ │ │ │ │ └── index.js │ │ │ │ ├── input │ │ │ │ │ └── index.js │ │ │ │ ├── video │ │ │ │ │ └── index.js │ │ │ │ ├── textarea │ │ │ │ │ └── index.js │ │ │ │ ├── packer.js │ │ │ │ ├── index.js │ │ │ │ └── picker │ │ │ │ │ └── index.js │ │ │ └── directive │ │ │ │ ├── index.js │ │ │ │ └── wx-for.js │ │ ├── page-rewriter │ │ │ ├── root.js │ │ │ ├── template-rewriter │ │ │ │ ├── class.js │ │ │ │ ├── wxml │ │ │ │ │ ├── cdata.js │ │ │ │ │ ├── include.js │ │ │ │ │ └── fragment.js │ │ │ │ ├── content.js │ │ │ │ ├── directive.js │ │ │ │ ├── index.js │ │ │ │ ├── event.js │ │ │ │ ├── attr.js │ │ │ │ └── style.js │ │ │ ├── refresh.js │ │ │ ├── import.js │ │ │ ├── script-rewriter │ │ │ │ └── index.js │ │ │ ├── parser.js │ │ │ ├── style-rewriter │ │ │ │ └── index.js │ │ │ ├── import-rewriter │ │ │ │ └── index.js │ │ │ ├── serialize.js │ │ │ └── tabs.js │ │ ├── index.js │ │ ├── app-rewriter │ │ │ └── index.js │ │ ├── resource-rewriter │ │ │ └── index.js │ │ └── manifest-rewriter │ │ │ └── manifest.json │ ├── wx │ │ ├── barcode │ │ │ └── index.js │ │ ├── vibrator │ │ │ └── index.js │ │ ├── geolocation │ │ │ └── index.js │ │ ├── index.js │ │ ├── brightness │ │ │ └── index.js │ │ ├── clipboard │ │ │ └── index.js │ │ ├── fetch │ │ │ └── index.js │ │ ├── network │ │ │ └── index.js │ │ ├── router │ │ │ └── index.js │ │ ├── file │ │ │ └── index.js │ │ ├── sensor │ │ │ └── index.js │ │ ├── media │ │ │ └── index.js │ │ ├── request │ │ │ └── index.js │ │ ├── device │ │ │ └── index.js │ │ ├── storage │ │ │ └── index.js │ │ ├── packer.js │ │ ├── prompt │ │ │ └── index.js │ │ └── wx.js │ ├── platform │ │ ├── regenerator.js │ │ ├── util.js │ │ ├── modules.js │ │ ├── Template.js │ │ ├── Page.js │ │ ├── quickapp │ │ │ └── index.js │ │ ├── polyfill │ │ │ ├── refresh.js │ │ │ ├── index.js │ │ │ ├── navigationbar.js │ │ │ └── storage.js │ │ ├── wx.js │ │ ├── uniapp │ │ │ └── index.js │ │ ├── richtext.js │ │ ├── navigator.js │ │ ├── router.js │ │ ├── args.js │ │ ├── Behavior.js │ │ ├── Component.js │ │ └── App.js │ ├── config.js │ └── babel │ │ ├── transform.js │ │ ├── uniapp │ │ └── index.js │ │ ├── quickapp │ │ └── index.js │ │ └── wx.js ├── utils │ ├── type.js │ ├── index.js │ └── log.js └── index.js ├── .gitignore ├── .eslintrc ├── test ├── util.js └── weapp │ ├── platform │ ├── util.js │ ├── test.js │ └── behavior.test.js │ ├── transform │ ├── page-rewriter │ │ ├── index.test.js │ │ ├── template-rewriter │ │ │ ├── class.test.js │ │ │ ├── style.test.js │ │ │ └── wxml │ │ │ │ └── include.test.js │ │ ├── style-rewriter │ │ │ └── index.test.js │ │ └── parser.test.js │ ├── helper │ │ ├── tag │ │ │ ├── logic │ │ │ │ └── block │ │ │ │ │ └── index.test.js │ │ │ ├── basic │ │ │ │ ├── icon │ │ │ │ │ └── index.test.js │ │ │ │ ├── process │ │ │ │ │ └── index.test.js │ │ │ │ ├── text │ │ │ │ │ └── index.test.js │ │ │ │ └── rich-text │ │ │ │ │ └── index.test.js │ │ │ ├── open │ │ │ │ └── web-view │ │ │ │ │ └── index.test.js │ │ │ ├── form │ │ │ │ ├── switch │ │ │ │ │ └── index.test.js │ │ │ │ ├── button │ │ │ │ │ └── index.test.js │ │ │ │ ├── checkbox │ │ │ │ │ ├── index.test.js │ │ │ │ │ └── checkbox-group │ │ │ │ │ │ └── index.test.js │ │ │ │ ├── label │ │ │ │ │ └── index.test.js │ │ │ │ ├── radio │ │ │ │ │ ├── index.test.js │ │ │ │ │ └── radio-group │ │ │ │ │ │ └── index.test.js │ │ │ │ ├── slider │ │ │ │ │ └── index.test.js │ │ │ │ ├── input │ │ │ │ │ └── index.test.js │ │ │ │ ├── textarea │ │ │ │ │ └── index.test.js │ │ │ │ └── picker │ │ │ │ │ └── index.test.js │ │ │ ├── media │ │ │ │ ├── image │ │ │ │ │ └── index.test.js │ │ │ │ ├── audio │ │ │ │ │ └── index.test.js │ │ │ │ └── video │ │ │ │ │ └── index.test.js │ │ │ ├── view │ │ │ │ ├── view │ │ │ │ │ └── index.test.js │ │ │ │ ├── swiper │ │ │ │ │ └── index.test.js │ │ │ │ └── scroll-view │ │ │ │ │ └── index.test.js │ │ │ └── navigator │ │ │ │ └── navigator │ │ │ │ └── index.test.js │ │ ├── style │ │ │ ├── declaration │ │ │ │ ├── dimension │ │ │ │ │ └── index.test.js │ │ │ │ ├── list │ │ │ │ │ └── index.test.js │ │ │ │ ├── box │ │ │ │ │ └── index.test.js │ │ │ │ ├── margin │ │ │ │ │ └── index.test.js │ │ │ │ ├── padding │ │ │ │ │ └── index.test.js │ │ │ │ ├── transition │ │ │ │ │ └── index.test.js │ │ │ │ ├── font │ │ │ │ │ └── index.test.js │ │ │ │ ├── flexbox │ │ │ │ │ └── index.test.js │ │ │ │ ├── position │ │ │ │ │ └── index.test.js │ │ │ │ ├── text │ │ │ │ │ └── index.test.js │ │ │ │ ├── transform │ │ │ │ │ └── index.test.js │ │ │ │ ├── border │ │ │ │ │ └── index.test.js │ │ │ │ ├── animation │ │ │ │ │ └── index.test.js │ │ │ │ └── background │ │ │ │ │ └── index.test.js │ │ │ └── selector │ │ │ │ └── index.test.js │ │ └── util.js │ └── manifest-rewriter │ │ └── index.test.js │ ├── wx │ ├── util.js │ ├── vibrator │ │ └── index.test.js │ ├── router │ │ └── index.test.js │ ├── network │ │ └── index.test.js │ ├── geolocation │ │ └── index.test.js │ ├── barcode │ │ └── index.test.js │ ├── sensor │ │ └── index.test.js │ ├── device │ │ └── index.test.js │ ├── record │ │ └── index.test.js │ ├── fetch │ │ └── index.test.js │ ├── media │ │ └── index.test.js │ ├── request │ │ └── index.test.js │ ├── brightness │ │ └── index.test.js │ ├── clipboard │ │ └── index.test.js │ ├── prompt │ │ └── index.test.js │ └── storage │ │ └── index.test.js │ └── babel │ ├── index.test.js │ ├── uniapp │ └── index.test.js │ └── quickapp │ └── index.test.js ├── .npmignore ├── README.md ├── rollup.config.js ├── bin └── uni-migration.js └── package.json /.eslintignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib') 2 | -------------------------------------------------------------------------------- /tools/dcloud_stat/dcloud_stat_conf.js: -------------------------------------------------------------------------------- 1 | exports.app_key = ""; //请在此行填写快应用包名 -------------------------------------------------------------------------------- /src/packer.js: -------------------------------------------------------------------------------- 1 | import weapp from './weapp' 2 | export default { 3 | weapp 4 | } 5 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/input/input.css: -------------------------------------------------------------------------------- 1 | .u-w-input { 2 | height: 52px; 3 | } -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/map/map/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div' 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/canvas/canvas/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div' 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/form/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div' 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/media/camera/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div' 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/form/form.css: -------------------------------------------------------------------------------- 1 | .u-w-form{ 2 | flex-direction: column; 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/picker-view/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div' 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/logic/import/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'import' 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/media/live-player/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div' 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/media/live-pusher/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div' 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/open/open-data/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div' 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/view/cover-view/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div' 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/view/movable-view/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div' 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | 3 | # Node 4 | node_modules/ 5 | 6 | # Created by IDE 7 | .DS_Store 8 | .project 9 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/style/declaration/color/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'opacity': '' 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/media/video/video.css: -------------------------------------------------------------------------------- 1 | .u-w-video{ 2 | width:600px; 3 | height:450px; 4 | } -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/view/cover-view/cover-image/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div' 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/textarea/textarea.css: -------------------------------------------------------------------------------- 1 | .u-w-textarea { 2 | width: 600px; 3 | height: 300px; 4 | } -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/navigator/navigator/navigator.css: -------------------------------------------------------------------------------- 1 | .u-w-navigator { 2 | flex-direction: column; 3 | } -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/view/list-item/list-item.css: -------------------------------------------------------------------------------- 1 | .u-w-list-item { 2 | flex-direction: column; 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/view/movable-view/movable-area/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div' 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/radio/radio-group/radio-group.css: -------------------------------------------------------------------------------- 1 | .u-w-radio-group{ 2 | flex-direction: column; 3 | } 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": [ 4 | "plugin:vue-libs/recommended" 5 | ], 6 | "globals": { 7 | } 8 | } -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/checkbox/checkbox-group/checkbox-group.css: -------------------------------------------------------------------------------- 1 | .u-w-checkbox-group{ 2 | flex-direction: column; 3 | } 4 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/deprecated/modal/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div', 3 | deprecated: '请使用wx.showModal替换' 4 | } 5 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/deprecated/toast/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div', 3 | deprecated: '请使用wx.showToast替换' 4 | } 5 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/label/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div', // 快应用的label不支持子组件,需要用div模拟。 3 | attr: {} 4 | } 5 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/deprecated/contact-button/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'input', 3 | deprecated: '请使用button替换' 4 | } 5 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/deprecated/loading/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div', 3 | deprecated: '请使用wx.showLoading替换' 4 | } 5 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/deprecated/action-sheet/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div', 3 | deprecated: '请使用wx.showActionSheet替换' 4 | } 5 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/basic/icon/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'image', 3 | attr: { 4 | 'size': 'STYLE:width,height' 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/view/swiper/swiper-item/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div', 3 | attr: { 4 | 'item-id': 'id' 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/open/web-view/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'web', 3 | attr: { 4 | 'src': 'src' 5 | }, 6 | event: {} 7 | } 8 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/logic/block/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'block', 3 | attr: { 4 | 'class': '', 5 | 'style': 'I:' 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/util.js: -------------------------------------------------------------------------------- 1 | const util = require('util') 2 | module.exports = { 3 | inspect: v => console.log(util.inspect(v, { 4 | depth: null, 5 | colors: true 6 | })) 7 | } -------------------------------------------------------------------------------- /test/weapp/platform/util.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | global.$app_require$ = () => {} 4 | require(path.join(__dirname.replace('test', 'lib'), './quickapp/index')).default -------------------------------------------------------------------------------- /src/weapp/wx/barcode/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | scanCode: { 3 | name: 'scan' 4 | // args无onlyFromCamera、scanType参数。 5 | // returnValue无scanType、charSet、path参数。 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/utils/type.js: -------------------------------------------------------------------------------- 1 | const _toString = Object.prototype.toString 2 | 3 | export const isFn = v => typeof v === 'function' 4 | export const isPlainObject = v => _toString.call(v) === '[object Object]' 5 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/style/declaration/list/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'list-style': 'I:', 3 | 'list-style-image': 'I:', 4 | 'list-style-position': 'I:', 5 | 'list-style-type': 'I:' 6 | } 7 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/event/switch/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | change: { 3 | detail: function (evt) { 4 | return { 5 | value: evt.checked 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/weapp/transform/page-rewriter/root.js: -------------------------------------------------------------------------------- 1 | export default function rewriteRoot (code, isComponent = false) { 2 | return `
3 | ${code} 4 |
` 5 | } 6 | -------------------------------------------------------------------------------- /src/weapp/platform/regenerator.js: -------------------------------------------------------------------------------- 1 | const _$global$_ = Object.getPrototypeOf(global) || global 2 | 3 | _$global$_.regeneratorRuntime = require('babel-runtime/regenerator') 4 | export default _$global$_.regeneratorRuntime 5 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/switch/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'switch', 3 | attr: { 4 | 'checked': 'checked' 5 | }, 6 | event: { // 标签事件转换配置 7 | 'change': 'change' 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/event/radio/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | change: { // 快应用事件名 3 | detail: function (evt) { // 转换detail 4 | return { 5 | value: evt.value 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/weapp/transform/page-rewriter/template-rewriter/class.js: -------------------------------------------------------------------------------- 1 | export default function addClass (clazz, node) { 2 | const attr = node.attributes 3 | attr['class'] = clazz + (attr['class'] ? (' ' + attr['class']) : '') 4 | } 5 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/event/slider/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | change: { // 快应用事件名 3 | detail: function (evt) { // 转换detail 4 | return { 5 | value: evt.progress 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/event/swiper/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | change: { // 快应用事件名 3 | detail: function (evt) { // 转换detail 4 | return { 5 | current: evt.index 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/event/tabs/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | change: { // 快应用事件名 3 | detail: function (evt) { // 转换detail 4 | return { 5 | current: evt.index 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/event/input/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | change: { // 快应用事件名 3 | detail: function (evt) { // 转换detail 4 | return { 5 | value: evt.value || evt.text 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/weapp/transform/page-rewriter/refresh.js: -------------------------------------------------------------------------------- 1 | export default function rewriteRefresh (code) { 2 | return ` 3 | ${code} 4 | ` 5 | } 6 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/style/declaration/transition/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'transition': 'I:', 3 | 'transition-property': 'I:', 4 | 'transition-duration': 'I:', 5 | 'transition-timing-function': 'I:', 6 | 'transition-delay': 'I:' 7 | } 8 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/view/view/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'div', 3 | attr: { 4 | 'hover-class': 'I:', 5 | 'hover-stop-propagation': 'I:', 6 | 'hover-start-time': 'I:', 7 | 'hover-stay-time': 'I:' 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/basic/text/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name (node) { 3 | if (node.parent && node.parent.name === 'text') { 4 | return 'span' 5 | } 6 | return node.name 7 | }, 8 | content: true, 9 | attr: {} 10 | } 11 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/basic/progress/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'progress', 3 | attr: { 4 | 'percent': 'percent', 5 | 'stroke-width': 'STYLE:stroke-width', 6 | 'color': 'STYLE:color', 7 | 'activecolor': 'STYLE:color' 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | 3 | # Node 4 | node_modules/ 5 | 6 | # Test 7 | test/ 8 | 9 | # Tools 10 | tools/ 11 | 12 | # Created by IDE 13 | .project 14 | .DS_Store 15 | .eslintrc 16 | .eslintignore 17 | 18 | 19 | # Other 20 | /packer.js 21 | rollup.config.js 22 | yarn.lock 23 | -------------------------------------------------------------------------------- /src/weapp/transform/page-rewriter/import.js: -------------------------------------------------------------------------------- 1 | export default function rewriter (deps, options) { 2 | return deps.map(dep => { 3 | return `` 4 | }).join('\r\n') 5 | } 6 | -------------------------------------------------------------------------------- /src/weapp/wx/vibrator/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // 不区分长短,时间均为1s。 3 | vibrateLong: { 4 | name: 'vibrate' 5 | // args无success,fail,complete等回调函数。 6 | }, 7 | vibrateShort: { 8 | name: 'vibrate' 9 | // args无success,fail,complete等回调函数。 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/weapp/transform/index.js: -------------------------------------------------------------------------------- 1 | import app from './app-rewriter' 2 | import resource from './resource-rewriter' 3 | import manifest from './manifest-rewriter' 4 | import page from './page-rewriter' 5 | export default { 6 | manifest, 7 | app, 8 | page, 9 | resource 10 | } 11 | -------------------------------------------------------------------------------- /src/weapp/platform/util.js: -------------------------------------------------------------------------------- 1 | const serviceModules = ['push', 'pay', 'wxpay', 'alipay', 'appshare'] 2 | 3 | export const fixedModuleName = function (module) { 4 | if (~serviceModules.indexOf(module)) { 5 | return '@app-module/service.' + module 6 | } 7 | return '@app-module/system.' + module 8 | } 9 | -------------------------------------------------------------------------------- /src/weapp/wx/geolocation/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | getLocation: { 3 | name: 'getLocation', 4 | args: { 5 | // uniapp没有type、altitude属性 6 | }, 7 | returnValue: { 8 | // uniapp没有speed、accuracy、altitude、verticalAccuracy、horizontalAccuracy返回值 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/directive/index.js: -------------------------------------------------------------------------------- 1 | import wxFor from './wx-for' 2 | export default { 3 | 'wx:for': wxFor, 4 | 'wx:for-items': wxFor, 5 | 'wx:for-item': wxFor, 6 | 'wx:for-index': wxFor, 7 | 'wx:key': wxFor, 8 | 'wx:if': 'if', 9 | 'wx:elif': 'elif', 10 | 'wx:else': 'else' 11 | } 12 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/util.js: -------------------------------------------------------------------------------- 1 | const log = (type, msg) => type + ': ' + '组件`COMPONENT`不支持`NAME`属性配置' + (msg ? (',' + msg) : '') 2 | 3 | export const warn = msg => log('WARN', msg) 4 | export const error = msg => log('ERROR', msg) 5 | export const defaultWarn = warn() 6 | export const defaultError = error() 7 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/view/list-item/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | beforeAttr (node, { 3 | getAttr, 4 | addAttr 5 | }) { 6 | if (!getAttr('type')) { 7 | addAttr('type', 'u-w-list-item') 8 | } 9 | }, 10 | name: 'list-item', 11 | attr: { 12 | 'type': '' 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/weapp/transform/page-rewriter/template-rewriter/wxml/cdata.js: -------------------------------------------------------------------------------- 1 | export default function rewrite (code) { 2 | // 为内容增加 3 | return code.replace(/\]*\>/g, function (match) { 4 | return `${match}/g, function (match) { 6 | return `]]>${match}` 7 | }) 8 | } 9 | -------------------------------------------------------------------------------- /src/weapp/wx/index.js: -------------------------------------------------------------------------------- 1 | import target from './wx'; 2 | 3 | (Object.getPrototypeOf(global) || global).wx = new Proxy(target, { 4 | get (target, methodName) { 5 | if (methodName in target) { 6 | return target[methodName] 7 | } 8 | console.error(`暂不支持"${methodName}"`) 9 | return () => {} 10 | } 11 | }) 12 | -------------------------------------------------------------------------------- /test/weapp/transform/page-rewriter/index.test.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const fs = require('fs-extra') 3 | const chai = require('chai') 4 | const expect = chai.expect 5 | 6 | const rewriter = require(__dirname.replace('test', 'lib')) 7 | 8 | describe('manifest', () => { 9 | it('parseImportWxss', () => {}) 10 | 11 | }) -------------------------------------------------------------------------------- /src/weapp/config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | uniapp: { 3 | ext: { 4 | wxs: '.njs', 5 | wxml: '.nml', 6 | wxss: '.nss', 7 | app: '.njs' 8 | } 9 | }, 10 | quickapp: { 11 | ext: { 12 | wxs: '.js', 13 | wxml: '.ux', 14 | wxss: '.css', 15 | app: '.ux' 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/weapp/wx/util.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const chai = require('chai') 3 | 4 | const modules = {} 5 | global.polyfill = (dirname, def) => modules[`@app-module/system.${path.basename(dirname)}`] = def 6 | global.$app_require$ = (name) => modules[name] || {} 7 | 8 | require('../../../lib/weapp/platform/uniapp/index.js') 9 | require('./wx.js') -------------------------------------------------------------------------------- /tools/sign/README.md: -------------------------------------------------------------------------------- 1 | #####增加release签名 2 | 通过openssl命令等工具生成签名文件`private.pem`、`certificate.pem`,例如: 3 | 4 | `openssl req -newkey rsa:2048 -nodes -keyout private.pem -x509 -days 3650 -out certificate.pem` 5 | 6 | 在工程的sign/release目录,将私钥文件private.pem和证书文件certificate.pem拷贝进去 7 | 8 | 注意: 若未指定release签名,则使用默认的debug签名,由于debug签名是公开的,安全性无法保证,一定不要使用debug签名签发正式上线的应用 -------------------------------------------------------------------------------- /src/weapp/transform/helper/style/declaration/margin/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'margin': (value, declaration, addDeclaration) => { 3 | if (~value.indexOf('auto')) { 4 | // TODO 待处理 5 | return 'I:' 6 | } 7 | }, 8 | 'margin-bottom': '', 9 | 'margin-left': '', 10 | 'margin-right': '', 11 | 'margin-top': '' 12 | } 13 | -------------------------------------------------------------------------------- /src/weapp/transform/page-rewriter/script-rewriter/index.js: -------------------------------------------------------------------------------- 1 | import transform from '../../../babel/transform' 2 | 3 | export default function rewriter (code, pagePath, options) { 4 | const ret = transform(code, { 5 | page: pagePath, 6 | target: options.target 7 | }) 8 | return { 9 | logs: [], 10 | result: ret.code 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/weapp/wx/brightness/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | setScreenBrightness: { 3 | name: 'setValue' 4 | }, 5 | getScreenBrightness: { 6 | name: 'getValue', 7 | returnValue (data) { 8 | const value = String(data.value / 255).substring(0, 7) 9 | return { 10 | value: value 11 | } 12 | } 13 | } 14 | // TODO... 15 | } 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # uni-migration 2 | 3 | 统一转换器,可实现将小程序项目转换为快应用、UniApp项目。 4 | 5 | ## 安装 6 | 7 | $ npm install -g uni-migration 8 | 9 | ## 使用 10 | 11 |    $ uni-migration [options] [weapp_dir] output_dir 12 | 13 | ## 说明 14 | - 小程序模板语法较为丰富,转换后的工程使用hap-toolkit编译可能会报语法错误,推荐使用 [HBuilderX](http://quickapp.dcloud.io) 进行转换开发 15 | - [快应用示例](https://github.com/dcloudio/quickapp) 16 | -------------------------------------------------------------------------------- /src/weapp/wx/clipboard/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | setClipboardData: { 3 | name: 'set', 4 | args (params) { 5 | return { 6 | text: params.data 7 | } 8 | } 9 | }, 10 | getClipboardData: { 11 | name: 'get', 12 | returnValue (data) { 13 | return { 14 | data: data.text 15 | } 16 | } 17 | } 18 | // TODO... 19 | } 20 | -------------------------------------------------------------------------------- /src/weapp/platform/modules.js: -------------------------------------------------------------------------------- 1 | import packer from '../wx/packer' 2 | 3 | const modules = {} 4 | Object.keys(packer).forEach(moduleName => { 5 | const moduleDef = packer[moduleName] 6 | Object.keys(moduleDef).forEach(methodName => { 7 | const methodDef = moduleDef[methodName] 8 | methodDef['module'] = moduleName 9 | modules[methodName] = methodDef 10 | }) 11 | }) 12 | 13 | export default modules 14 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/media/audio/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'audio', 3 | attr: { 4 | 'id': 'id', 5 | 'src': 'src', 6 | 'loop': 'loop', 7 | 'controls': 'controls', 8 | 'poster': 'I:', 9 | 'name': 'I:', 10 | 'author': 'I:' 11 | }, 12 | event: { 13 | 'error': '', 14 | 'play': '', 15 | 'pause': '', 16 | 'timeupdate': '', 17 | 'ended': '' 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/weapp/wx/fetch/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | request: { 3 | name: 'fetch', 4 | returnValue (data) { 5 | let result = null 6 | try { 7 | result = JSON.parse(data.data) 8 | } catch (e) { 9 | result = data.data 10 | } 11 | return { 12 | data: result, 13 | statusCode: data.code, 14 | header: data.headers 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/weapp/wx/vibrator/index.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const expect = chai.expect 3 | 4 | require('../util') 5 | 6 | /** 7 | * 模拟快应用vibrator接口 8 | */ 9 | polyfill(__dirname, { 10 | vibrate() {} 11 | }) 12 | 13 | describe('api.vibrator', () => { 14 | 15 | it('wx.vibrateLong', () => { 16 | wx.vibrateLong() 17 | }) 18 | 19 | it('wx.vibrateShort', () => { 20 | wx.vibrateShort() 21 | }) 22 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/logic/block/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.block', () => { 4 | 5 | it('rewrite `block`', () => { 6 | const fixture = ` 7 | 8 | 9 | ` 10 | 11 | const expected = `
` 12 | 13 | rewriter.assertTemplateString(fixture, expected) 14 | }) 15 | 16 | }) -------------------------------------------------------------------------------- /src/weapp/transform/helper/style/declaration/padding/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'padding': (value, declaration, addDeclaration) => { 3 | // TODO padding 的 auto 会使用浏览器设定的值,直接忽略掉。 4 | // http://www.w3school.com.cn/jsref/prop_style_padding.asp 5 | if (~value.indexOf('auto')) { 6 | return 'I:' 7 | } 8 | }, 9 | 'padding-bottom': '', 10 | 'padding-left': '', 11 | 'padding-right': '', 12 | 'padding-top': '' 13 | } 14 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/basic/icon/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.icon', () => { 4 | 5 | it('rewrite `icon`', () => { 6 | const fixture = ` 7 | 8 | ` 9 | 10 | const expected = `` 11 | 12 | rewriter.assertTemplateString(fixture, expected) 13 | }) 14 | 15 | }) -------------------------------------------------------------------------------- /src/weapp/transform/helper/event/video/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | timeupdate: { // 快应用事件名 3 | detail: function (evt) { // 转换detail 4 | return { 5 | currentTime: evt.currenttime, 6 | duration: '' 7 | } 8 | } 9 | }, 10 | fullscreenchange: { 11 | detail: function (evt) { // 转换detail 12 | return { 13 | fullScreen: evt.fullscreen, 14 | direction: 'horizontal' 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/weapp/babel/transform.js: -------------------------------------------------------------------------------- 1 | import { transform } from 'babel-core' 2 | 3 | import plugins from './index' 4 | 5 | export default function transformCode (code, options) { 6 | return transform(code, { 7 | ast: false, 8 | babelrc: { 9 | presets: false 10 | }, 11 | plugins: [ 12 | ['babel-plugin-transform-class-properties'], 13 | ['babel-plugin-transform-object-rest-spread'], 14 | [plugins, options] 15 | ] 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/style/declaration/transform/transform.js: -------------------------------------------------------------------------------- 1 | const nameList = ['translate', 'translateX', 'translateY', 'scale', 'scaleX', 'scaleY', 'rotate', 'rotateX', 'rotateY'] 2 | 3 | export default { 4 | 'transform': (value, declaration, addDeclaration) => { 5 | const name = value.match(/\w+/)[0] 6 | if (!~nameList.indexOf(name)) { 7 | return 'I:' 8 | } 9 | if (~value.indexOf('%')) { 10 | return 'I:' 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/weapp/platform/Template.js: -------------------------------------------------------------------------------- 1 | import Base from './Base' 2 | 3 | export default function Template (options, { 4 | module, 5 | exports, 6 | /*eslint-disable camelcase*/ 7 | $app_require$ 8 | }) { 9 | Base(options, { 10 | type: 'Template', 11 | module, 12 | exports, 13 | $app_require$ 14 | }) 15 | 16 | if (exports.default) { 17 | exports.default = options 18 | } else if (module.exports) { 19 | module.exports = options 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/style/declaration/dimension/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('style.declaration.dimension', () => { 4 | 5 | it('rewrite `dimension`', () => { 6 | const fixture = ` 7 | .test{ 8 | width:10rpx; 9 | height:auto; 10 | width:20rpx!important; 11 | } 12 | ` 13 | const expected = `.test{width:10px;width:20px;display:flex;}` 14 | 15 | rewriter.assertStyleString(fixture, expected) 16 | }) 17 | 18 | }) -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/slider/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'slider', 3 | attr: { 4 | 'min': 'min', 5 | 'max': 'max', 6 | 'step': 'step', 7 | 'disabled': 'disabled', 8 | 'value': 'value', 9 | 'color': 'STYLE:color', 10 | 'selected-color': 'STYLE:selected-color', 11 | 'activeColor': 'STYLE:selected-color', 12 | 'backgroundColor': 'STYLE:color' 13 | }, 14 | event: { // 标签事件转换配置 15 | 'change': 'change' // 事件名称 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/open/web-view/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag[web-view]', () => { 4 | 5 | it('rewrite `web-view`', () => { 6 | const fixture = ` 7 | 8 | ` 9 | 10 | const expected = `` 11 | 12 | rewriter.assertTemplateString(fixture, expected) 13 | }) 14 | 15 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/form/switch/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.switch', () => { 4 | 5 | it('rewrite `switch`', () => { 6 | const fixture = ` 7 | 8 | ` 9 | 10 | const expected = `` 11 | 12 | rewriter.assertTemplateString(fixture, expected) 13 | }) 14 | 15 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/style/declaration/list/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('style.declaration.list', () => { 4 | 5 | it('rewrite `list`', () => { 6 | const fixture = ` 7 | .test{ 8 | list-style-image:url("/i/arrow.gif"); 9 | list-style-type:square; 10 | list-style-type:circle; 11 | list-style:square inside url('/i/arrow.gif'); 12 | } 13 | ` 14 | 15 | const expected = `.test{}` 16 | 17 | rewriter.assertStyleString(fixture, expected) 18 | }) 19 | 20 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/basic/process/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.process', () => { 4 | 5 | it('rewrite `process`', () => { 6 | const fixture = ` 7 | 8 | ` 9 | 10 | const expected = `` 11 | 12 | rewriter.assertTemplateString(fixture, expected) 13 | }) 14 | 15 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/media/image/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.image', () => { 4 | 5 | it('rewrite `image`', () => { 6 | const fixture = ` 7 | 8 | 9 | ` 10 | 11 | const expected = `` 12 | 13 | rewriter.assertTemplateString(fixture, expected) 14 | }) 15 | 16 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/style/declaration/box/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('style.declaration.box', () => { 4 | 5 | it('rewrite `box`', () => { 6 | const fixture = ` 7 | .test{ 8 | float:left; 9 | box-sizing:border-box; 10 | } 11 | .test2{ 12 | -webkit-box-align: center; 13 | box-align: start; 14 | } 15 | ` 16 | const expected = `.test{}.test2{align-items:center;align-items:flex-start;}` 17 | 18 | rewriter.assertStyleString(fixture, expected) 19 | }) 20 | 21 | }) -------------------------------------------------------------------------------- /src/weapp/transform/helper/event/textarea/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | change: { 3 | detail: function (evt) { 4 | return { 5 | value: evt.value, 6 | cursor: evt.value.length 7 | } 8 | } 9 | }, 10 | focus: { 11 | detail: function (evt) { 12 | return { 13 | value: '', 14 | height: '' 15 | } 16 | } 17 | }, 18 | blur: { 19 | detail: function (evt) { 20 | return { 21 | value: '', 22 | cursor: '' 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/weapp/wx/network/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | getNetworkType: { 3 | name: 'getType', 4 | returnValue (data) { 5 | return { 6 | networkType: data.type 7 | } 8 | } 9 | }, 10 | onNetworkStatusChange: { 11 | name: 'subscribe', 12 | args (callback) { 13 | return { 14 | callback: callback 15 | } 16 | }, 17 | returnValue (data) { 18 | // returnValue没有isConnected参数。 19 | return { 20 | networkType: data.type 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/basic/text/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.text', () => { 4 | 5 | it('rewrite `text`', () => { 6 | const fixture = `123123 7 | ` 8 | 9 | const expected = `123\r\n123` 10 | 11 | rewriter.assertTemplateString(fixture, expected) 12 | }) 13 | 14 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/view/view/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.view', () => { 4 | 5 | it('rewrite `view`', () => { 6 | const fixture = ` 7 | 8 | 9 | ` 10 | 11 | const expected = `
` 12 | 13 | rewriter.assertTemplateString(fixture, expected) 14 | }) 15 | 16 | }) -------------------------------------------------------------------------------- /src/weapp/platform/Page.js: -------------------------------------------------------------------------------- 1 | import Base from './Base' 2 | 3 | export default function Page (options, { 4 | wxs, 5 | path, 6 | module, 7 | exports, 8 | /*eslint-disable camelcase*/ 9 | $app_require$ 10 | }) { 11 | Base(options, { 12 | wxs, 13 | type: 'Page', 14 | path, 15 | module, 16 | exports, 17 | /*eslint-disable camelcase*/ 18 | $app_require$ 19 | }) 20 | if (exports.default) { 21 | exports.default = options 22 | } else if (module.exports) { 23 | module.exports = options 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/form/button/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.button', () => { 4 | 5 | it('rewrite `button`', () => { 6 | const fixture = ` 7 | 8 | ` 9 | 10 | const expected = `` 11 | 12 | rewriter.assertTemplateString(fixture, expected) 13 | }) 14 | 15 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/form/checkbox/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.checkbox', () => { 4 | 5 | it('rewrite `checkbox`', () => { 6 | const fixture = ` 7 | 10 | ` 11 | 12 | const expected = `
选中
` 13 | 14 | rewriter.assertTemplateString(fixture, expected) 15 | }) 16 | 17 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/form/label/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.label', () => { 4 | 5 | it('rewrite `label`', () => { 6 | const fixture = ` 7 | 10 | ` 11 | 12 | const expected = `
` 13 | 14 | rewriter.assertTemplateString(fixture, expected) 15 | }) 16 | 17 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/style/declaration/margin/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('style.declaration.margin', () => { 4 | 5 | it('rewrite `margin`', () => { 6 | const fixture = ` 7 | .test{ 8 | margin:0 auto; 9 | margin-top:10px; 10 | margin-bottom:10px; 11 | margin-left:10px; 12 | margin-right:10px; 13 | } 14 | ` 15 | 16 | const expected = `.test{margin-top:20px;margin-bottom:20px;margin-left:20px;margin-right:20px;}` 17 | 18 | rewriter.assertStyleString(fixture, expected) 19 | }) 20 | 21 | }) -------------------------------------------------------------------------------- /src/weapp/transform/page-rewriter/template-rewriter/content.js: -------------------------------------------------------------------------------- 1 | export default function rewriteContent (node, component, { 2 | addAttr 3 | }) { 4 | if (node.content) { 5 | if (!component.content) { // 不支持content节点 6 | node.children.push({ 7 | name: 'text', 8 | content: node.content, 9 | attributes: {}, 10 | children: [] 11 | }) 12 | delete node.content 13 | } else if (typeof component.content === 'string') { 14 | addAttr(component.content, node.content) 15 | delete node.content 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/style/declaration/padding/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('style.declaration.padding', () => { 4 | 5 | it('rewrite `padding`', () => { 6 | const fixture = ` 7 | .test{ 8 | padding:5px auto; 9 | padding-top:10px; 10 | padding-bottom:10px; 11 | padding-left:10px; 12 | padding-right:10px; 13 | } 14 | ` 15 | 16 | const expected = `.test{padding-top:20px;padding-bottom:20px;padding-left:20px;padding-right:20px;}` 17 | 18 | rewriter.assertStyleString(fixture, expected) 19 | }) 20 | 21 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/style/declaration/transition/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('style.declaration.transition', () => { 4 | 5 | it('rewrite `transition`', () => { 6 | const fixture = ` 7 | .test{ 8 | width: 100px; 9 | transition: test; 10 | transition-property: width; 11 | transition-duration: 5s; 12 | transition-timing-function: linear; 13 | transition-delay: 2s; 14 | } 15 | ` 16 | 17 | const expected = `.test{width:200px;}` 18 | 19 | rewriter.assertStyleString(fixture, expected) 20 | }) 21 | 22 | }) -------------------------------------------------------------------------------- /src/weapp/wx/router/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | navigateTo: { 3 | name: 'push', 4 | args (params) { 5 | return { 6 | uri: params.url 7 | } 8 | // 无success,fail,complete等回调函数。 9 | } 10 | }, 11 | redirectTo: { 12 | name: 'replace', 13 | args (params) { 14 | return { 15 | uri: params.url 16 | } 17 | // 无success,fail,complete等回调函数。 18 | } 19 | }, 20 | navigateBack: { 21 | name: 'back' 22 | // 无可传的参数 23 | }, 24 | switchTab: { 25 | name: 'replace' 26 | } 27 | // 无reLaunch方法。 28 | } 29 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import uglify from 'rollup-plugin-uglify' 2 | export default [{ 3 | input: 'src/weapp/platform/uniapp/index.js', 4 | output: { 5 | file: 'lib/weapp/platform/uniapp/index.js', 6 | format: 'iife' 7 | }, 8 | plugins: [uglify()] 9 | }, { 10 | input: 'src/weapp/platform/quickapp/index.js', 11 | output: { 12 | file: 'lib/weapp/platform/quickapp/index.js', 13 | format: 'iife' 14 | }, 15 | plugins: [uglify()] 16 | }, { 17 | input: 'src/weapp/wx/index.js', 18 | output: { 19 | file: 'test/weapp/wx/wx.js', 20 | format: 'iife' 21 | } 22 | }] -------------------------------------------------------------------------------- /src/weapp/wx/file/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | getSavedFileInfo: { 3 | name: 'get', 4 | args (params) { 5 | return { 6 | uri: params.filePath 7 | } 8 | }, 9 | returnValue (data) { 10 | return { 11 | createTime: data.lastModifiedTime, 12 | size: data.length 13 | } 14 | } 15 | }, 16 | removeSavedFile: { 17 | name: 'delete', 18 | args (params) { 19 | return { 20 | uri: params.filePath 21 | } 22 | } 23 | } 24 | // 未支持的方法有:saveFile、getSavedFileList、openDocument等。getFileInfo在文档列表中有,但是没有相应的说明。 25 | } 26 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/form/radio/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.radio', () => { 4 | 5 | it('rewrite `radio`', () => { 6 | const fixture = ` 7 | 10 | 11 | ` 12 | 13 | const expected = `
选中
` 14 | 15 | rewriter.assertTemplateString(fixture, expected) 16 | }) 17 | 18 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/style/declaration/font/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('style.declaration.font', () => { 4 | 5 | it('rewrite `font`', () => { 6 | const fixture = ` 7 | .test{ 8 | font-size:20px; 9 | font-weight:500; 10 | font-style:italic; 11 | font-family:serif; 12 | font-variant:small-caps; 13 | } 14 | .test1 { 15 | font-size: 20pt; 16 | } 17 | ` 18 | 19 | const expected = `.test{font-size:40px;font-weight:bold;font-style:italic;}.test1{font-size:20px;}` 20 | 21 | rewriter.assertStyleString(fixture, expected) 22 | }) 23 | 24 | }) -------------------------------------------------------------------------------- /src/weapp/transform/helper/event/packer.js: -------------------------------------------------------------------------------- 1 | import input from './input/index.js' 2 | import picker from './picker/index.js' 3 | import radio from './radio/index.js' 4 | import slider from './slider/index.js' 5 | import swiper from './swiper/index.js' 6 | import switchEvent from './switch/index.js' 7 | import tabs from './tabs/index.js' 8 | import textarea from './textarea/index.js' 9 | import video from './video/index.js' 10 | 11 | export default { 12 | input, 13 | picker, 14 | radio, 15 | slider, 16 | swiper, 17 | 'switch':switchEvent, 18 | tabs, 19 | textarea, 20 | video 21 | } 22 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/style/declaration/component/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'placeholder-color': '', // input 3 | 'columns': '', // list 4 | 'column-span': '', // list-item 5 | 'mask-color': '', // popup 6 | 'progress-color': '', // refresh 7 | 'indicator-color': '', // swiper 8 | 'indicator-selected-color': '', // swiper 9 | 'indicator-size': '', // swiper 10 | 'resize-mode': '', // image 11 | 'stroke-width': '', // progress 12 | 'star-background': '', // rating 13 | 'star-secondary': '', // rating 14 | 'star-foreground': '', // rating 15 | 'selected-color': '' // slider 16 | } 17 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/basic/rich-text/index.js: -------------------------------------------------------------------------------- 1 | import { isExpr } from '../../../../../../utils' 2 | export default { 3 | name: 'richtext', 4 | content: true, 5 | beforeAttr (node, { 6 | getAttr, 7 | addAttr, 8 | addClass 9 | }) { 10 | addAttr('type', 'html') 11 | let nodes = getAttr('nodes') 12 | if (isExpr(nodes)) { 13 | nodes = nodes.substr(2, nodes.length - 4) 14 | node.content = `{{$handleRichText(${nodes})}}` 15 | } else { 16 | node.content = `{{$handleRichText('ESCAPE:${escape(nodes)}')}}` 17 | } 18 | }, 19 | attr: { 20 | type: '' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/media/image/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'image', 3 | attr: { 4 | 'src': 'src', 5 | 'mode': (value, attr) => { 6 | switch (value) { 7 | case 'scaleToFill': 8 | return 'STYLE:resize-mode:stretch' 9 | case 'aspectFit': 10 | return 'STYLE:resize-mode:contain' 11 | case 'aspectFill': 12 | return 'STYLE:resize-mode:contain' 13 | case 'widthFix': 14 | return 'STYLE:resize-mode:cover' 15 | default: 16 | return 'STYLE:resize-mode:cover' 17 | } 18 | } 19 | }, 20 | event: {} 21 | } 22 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/style/selector/index.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | const chai = require('chai') 3 | const expect = chai.expect 4 | 5 | const rewriter = require(__dirname.replace('test', 'lib')).default 6 | 7 | describe('style.selector', () => { 8 | 9 | it('rewrite `selector`', () => { 10 | expect(rewriter('view')).eql('.u-w-view') 11 | expect(rewriter('.view')).eql('.view') 12 | expect(rewriter('#view')).eql('#view') 13 | expect(rewriter('#view button')).eql('#view .u-w-button') 14 | expect(rewriter('.view button')).eql('.view .u-w-button') 15 | }) 16 | 17 | }) -------------------------------------------------------------------------------- /test/weapp/transform/page-rewriter/template-rewriter/class.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../helper/util') 2 | 3 | describe('template.tag.class', () => { 4 | 5 | it('rewrite `class` 无class', () => { 6 | rewriter.assertTemplateString('', '
') 7 | }) 8 | it('rewrite `class` 静态class', () => { 9 | rewriter.assertTemplateString('', '
') 10 | }) 11 | it('rewrite `class` 动态class', () => { 12 | rewriter.assertTemplateString('', '
') 13 | }) 14 | 15 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/media/audio/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.audio', () => { 4 | 5 | it('rewrite `audio`', () => { 6 | const fixture = ` 7 | 10 | ` 11 | 12 | const expected = `` 13 | 14 | rewriter.assertTemplateString(fixture, expected) 15 | }) 16 | 17 | }) -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/view/scroll-view/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | beforeAttr (node, { 3 | getAttr, 4 | addAttr 5 | }) { 6 | for (let i = 0, len = node.children.length; i < len; i++) { 7 | node.children[i] = { 8 | name: 'list-item', 9 | content: node.content, 10 | attributes: { 11 | type: 'u-w-scroll-view-list-item-' + i 12 | }, 13 | children: [node.children[i]] 14 | } 15 | } 16 | }, 17 | name: 'list', 18 | attr: {}, 19 | event: { 20 | 'scrolltoupper': 'scrolltop', 21 | 'scrolltolower': 'scrollbottom', 22 | 'scroll': 'scroll' 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/weapp/wx/sensor/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // 监听距离感应数据---小程序不支持 3 | // 监听光线感应数据---小程序不支持 4 | onCompassChange: {// 不支持wx.startCompass(); 5 | name: 'subscribeCompass', 6 | args (callback) { 7 | return { 8 | callback: callback 9 | } 10 | } 11 | }, 12 | stopCompass: { 13 | name: 'unsubscribeCompass' 14 | }, 15 | onAccelerometerChange: {// 不支持wx.startAccelerometer(); 16 | name: 'subscribeAccelerometer', 17 | args (callback) { 18 | return { 19 | callback: callback 20 | } 21 | } 22 | }, 23 | stopAccelerometer: { 24 | name: 'unsubscribeAccelerometer' 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/navigator/navigator/index.js: -------------------------------------------------------------------------------- 1 | import { isExpr } from '../../../../../../utils' 2 | 3 | export default { 4 | name: 'div', 5 | beforeAttr (node, { 6 | getAttr, 7 | addAttr 8 | }) { 9 | if (getAttr('url')) { 10 | let openType = getAttr('open-type', 'navigate') 11 | if (isExpr(openType)) { 12 | openType = openType.substr(2, openType.length - 4) 13 | addAttr('bindtap', `$handleRouterEvent(${openType})`) 14 | } else { 15 | addAttr('bindtap', `$handleRouterEvent('${openType}')`) 16 | } 17 | } 18 | }, 19 | attr: { // 标签属性转换配置 20 | url: 'data-url' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/weapp/transform/page-rewriter/template-rewriter/directive.js: -------------------------------------------------------------------------------- 1 | import directives from '../../helper/directive' 2 | 3 | export default function rewriteDirective (name, attr, node, output, location) { 4 | // 转换指令 5 | const directive = directives[name] 6 | if (!directive) { 7 | output.logs.push({ 8 | reason: 'E: 不支持`' + name + '`指令转换', 9 | line: location.line, 10 | column: location.column 11 | }) 12 | } else { 13 | if (typeof directive === 'string') { 14 | attr[directive] = attr[name] 15 | delete attr[name] 16 | } else if (typeof directive === 'function') { 17 | directive(node) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/form/slider/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.slider', () => { 4 | 5 | it('rewrite `slider`', () => { 6 | const fixture = ` 7 | 8 | ` 9 | 10 | const expected = `` 11 | 12 | rewriter.assertTemplateString(fixture, expected) 13 | }) 14 | 15 | }) -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | error 3 | } from './utils' 4 | 5 | import migraters from './packer' 6 | 7 | module.exports = function migrate (input, out, { 8 | target = 'quickapp', 9 | sign = false, 10 | stat = false 11 | } = {}) { 12 | const migrater = migraters['weapp'] 13 | if (migrater) { 14 | if (migrater.validate(input)) { 15 | const options = migrater.config[target] 16 | options.sign = !!sign 17 | options.stat = !!stat 18 | options.target = target 19 | options.input = input 20 | options.output = out 21 | migrater.transform(input, out, options) 22 | } 23 | } else { 24 | error('目前仅支持weapp转换') 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/style/declaration/font/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'font-size': (value, declaration, addDeclaration) => { 3 | if (~value.indexOf('inherit')) { 4 | return 'I:' 5 | } 6 | // 直接替换成px 7 | if (~value.indexOf('pt')) { 8 | declaration.value = declaration.value.replace('pt', 'px') 9 | } 10 | }, 11 | 'font-weight': (value, declaration, addDeclaration) => { 12 | if (value === 400) { 13 | declaration.value = 'normal' 14 | } else if (value > 400) { 15 | declaration.value = 'bold' 16 | } else { 17 | return 'I:' 18 | } 19 | }, 20 | 'font-style': '', 21 | 'font-family': 'I:', 22 | 'font-variant': 'I:' 23 | } 24 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/style/declaration/flexbox/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('style.declaration.flexbox', () => { 4 | 5 | it('rewrite `flexbox`', () => { 6 | const fixture = ` 7 | .test{ 8 | justify-content:space-around; 9 | justify-content:space-between; 10 | } 11 | .test1{ 12 | flex: 1 2 auto; 13 | } 14 | .test2{ 15 | flex: 0 1 50%; 16 | } 17 | .test3 { 18 | flex: auto; 19 | } 20 | ` 21 | const expected = `.test{justify-content:space-between;justify-content:space-between;}.test1{flex-grow:1;flex-shrink:2;}.test2{flex-grow:0;flex-shrink:1;}.test3{}` 22 | 23 | rewriter.assertStyleString(fixture, expected) 24 | }) 25 | 26 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/style/declaration/position/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('style.declaration.position', () => { 4 | 5 | it('rewrite `position`', () => { 6 | const fixture = ` 7 | .test1{ 8 | top:10px; 9 | right:10px; 10 | display:inline-block; 11 | position:relative; 12 | overflow:scroll; 13 | vertical-align:middle; 14 | z-index:998; 15 | } 16 | .test2{ 17 | display:flex; 18 | position:static; 19 | top:10px; 20 | } 21 | ` 22 | 23 | const expected = `.test1{top:20px;right:20px;}.test2{display:flex;position:none;top:20px;flex-direction:row;}` 24 | 25 | rewriter.assertStyleString(fixture, expected) 26 | }) 27 | 28 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/style/declaration/text/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('style.declaration.text', () => { 4 | 5 | it('rewrite `text`', () => { 6 | const fixture = ` 7 | button{ 8 | color: #ff3333; 9 | line-height: 10px; 10 | text-align: center; 11 | text-decoration: overline; 12 | text-overflow: clip; 13 | white-space: nowrap; 14 | word-wrap: break-word; 15 | word-break: break-all; 16 | } 17 | ` 18 | 19 | const expected = `.u-w-button{color:#ff3333;line-height:20px;text-align:center;text-overflow:clip;align-items:center;justify-content:center;lines:1;}` 20 | 21 | rewriter.assertStyleString(fixture, expected) 22 | }) 23 | 24 | }) -------------------------------------------------------------------------------- /test/weapp/transform/page-rewriter/template-rewriter/style.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const expect = chai.expect 3 | 4 | const rewriter = require(__dirname.replace('test', 'lib') + '/style').default 5 | 6 | describe('template.tag.style', () => { 7 | 8 | it('rewrite `style`', () => { 9 | const attr = { 10 | style: 'border-top:1RPX solid red;color:#fff;padding-left:1EM;padding-top:1Px;padding-bottom:1rpx;padding-right:{{paddingRight}}' 11 | } 12 | rewriter('style', attr) 13 | expect(attr.style).eql('border-top-width:1px;border-style:solid;border-top-color:red;color:#fff;padding-left:32px;padding-top:2px;padding-bottom:1px;padding-right:{{paddingRight}}') 14 | }) 15 | 16 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/navigator/navigator/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.navigator', () => { 4 | 5 | it('rewrite `navigator`', () => { 6 | const fixture = ` 7 | 9 | ` 10 | 11 | const expected = `
` 12 | 13 | rewriter.assertTemplateString(fixture, expected) 14 | }) 15 | 16 | }) -------------------------------------------------------------------------------- /src/weapp/transform/helper/style/uniapp.css: -------------------------------------------------------------------------------- 1 | .u-w-view { 2 | flex-direction: column; 3 | } 4 | 5 | .u-w-tabbar-placeholder { 6 | height: 120px 7 | } 8 | 9 | .u-w-tabbar { 10 | position: fixed; 11 | width: 100%; 12 | height: 120px; 13 | border-top-width: 1px; 14 | border-color: #bbbbbb; 15 | background-color: #ffffff; 16 | flex-direction: row; 17 | } 18 | 19 | .u-w-tabbar-top { 20 | top: 0; 21 | border-bottom-width: 1px; 22 | } 23 | 24 | .u-w-tabbar-bottom { 25 | bottom: 0; 26 | border-top-width: 1px; 27 | } 28 | 29 | .u-w-tabbar-icon { 30 | width: 40px; 31 | height: 40px; 32 | } 33 | 34 | .u-w-tabbar-item { 35 | flex: 1; 36 | align-items: center; 37 | justify-content: center; 38 | } -------------------------------------------------------------------------------- /test/weapp/transform/helper/style/declaration/transform/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('style.declaration.transform', () => { 4 | 5 | it('rewrite `transform`', () => { 6 | const fixture = ` 7 | .test1{ 8 | transform: rotateX(50deg); 9 | } 10 | .test2{ 11 | transform: rotate(0deg); 12 | } 13 | .test3{ 14 | transform: translateX(50%); 15 | } 16 | .test4{ 17 | transform: scaleX(1.5); 18 | } 19 | .test5{ 20 | transform: translateZ(50px); 21 | } 22 | ` 23 | 24 | const expected = `.test1{transform:rotateX(50deg);}.test2{transform:rotate(0deg);}.test3{}.test4{transform:scaleX(1.5);}.test5{}` 25 | 26 | rewriter.assertStyleString(fixture, expected) 27 | }) 28 | 29 | }) -------------------------------------------------------------------------------- /src/weapp/platform/quickapp/index.js: -------------------------------------------------------------------------------- 1 | import '../regenerator' 2 | import App from '../App' 3 | import Page from '../Page' 4 | import Behavior from '../Behavior' 5 | import Template from '../Template' 6 | import Component from '../Component' 7 | 8 | import parseArgs from '../args' 9 | 10 | import * as polyfill from '../polyfill/index' 11 | 12 | import wx from '../wx' 13 | 14 | const _$global$_ = Object.getPrototypeOf(global) || global 15 | 16 | _$global$_.wx = wx 17 | 18 | _$global$_.App = App 19 | _$global$_.Page = Page 20 | _$global$_.Behavior = Behavior 21 | _$global$_.Template = Template 22 | _$global$_.Component = Component 23 | 24 | _$global$_._$$polyfill$$_ = polyfill 25 | 26 | _$global$_._$$parseArgs$$_ = parseArgs 27 | 28 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/logic/template/index.js: -------------------------------------------------------------------------------- 1 | import { isExpr } from '../../../../../../utils' 2 | export default { 3 | name (node) { 4 | if (node.attributes.is) { 5 | return 'import-' + node.attributes.is.toLowerCase() 6 | } 7 | return node.name 8 | }, 9 | attr: { 10 | is: '', 11 | data: (value, attr) => { 12 | if (isExpr(value)) { 13 | value = value.substr(2, value.length - 4) 14 | if (value.indexOf('...') === 0) { 15 | attr['data'] = '{{' + value.replace('...', '') + '}}' 16 | } else if (!~value.indexOf(':') && !~value.indexOf(',')) { 17 | attr['data'] = '{{' + value + ':' + value + '}}' 18 | } 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/form/input/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.input', () => { 4 | 5 | it('rewrite `input`', () => { 6 | const fixture = ` 7 | 8 | ` 9 | 10 | const expected = `` 11 | 12 | rewriter.assertTemplateString(fixture, expected) 13 | }) 14 | 15 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/view/swiper/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.swiper', () => { 4 | 5 | it('rewrite `swiper`', () => { 6 | const fixture = ` 7 | 9 | 10 | ` 11 | 12 | const expected = `` 13 | 14 | rewriter.assertTemplateString(fixture, expected) 15 | }) 16 | 17 | }) -------------------------------------------------------------------------------- /src/weapp/wx/media/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | chooseImage: { 3 | // 小程序根据sourceType来区分从相册选取还是通过相机拍摄,默认两者都有。 4 | name: 'pickImage', 5 | // args无count、sizeType、sourceType参数。 6 | returnValue (data) { 7 | return { 8 | tempFilePaths: [data.uri] 9 | } 10 | // returnValue无tempFiles,快应用只支持单选,因而取tempFilePaths的第一项。 11 | } 12 | }, 13 | chooseVideo: { 14 | name: 'pickVideo', 15 | // args无sourceType、compressed、maxDuration参数。 16 | returnValue (data) { 17 | return { 18 | tempFilePath: data.uri 19 | } 20 | // returnValue无duration,size,height,width参数。 21 | } 22 | } 23 | // 未支持的方法有:previewImage、getImageInfo、saveImageToPhotosAlbum、saveVideoToPhotosAlbum等。 24 | } 25 | -------------------------------------------------------------------------------- /src/weapp/wx/request/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | uploadFile: { 3 | name: 'upload', 4 | args (params) { 5 | const fileObj = { 6 | uri: params.filePath 7 | } 8 | return { 9 | url: params.url, 10 | header: params.header, 11 | files: [fileObj] 12 | } 13 | // args无name、formData参数,filePath被转换为文件数组中的一项。 14 | }, 15 | returnValue (data) { 16 | return { 17 | data: data.data, 18 | statusCode: data.code 19 | } 20 | } 21 | }, 22 | downloadFile: { 23 | name: 'download', 24 | returnValue (data) { 25 | return { 26 | statusCode: data.token 27 | } 28 | // returnValue没有tempFilePath参数。 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/weapp/transform/app-rewriter/index.js: -------------------------------------------------------------------------------- 1 | import transform from '../../babel/transform' 2 | 3 | export default function rewriter (code, pagePath, options) { 4 | const ret = transform(code, { 5 | page: pagePath, 6 | target: options.target 7 | }) 8 | 9 | const statCode = `/** 10 | * DCloud统计服务类似于快应用里的友盟或阿拉丁,可登录 http://dev.dcloud.net.cn 查看统计数据 11 | * 使用该服务可在一点看到所有渠道的运营数据,避免登陆不同渠道的后台,更方便的掌握业务运营状态。 12 | * 如不需要此服务,请注释掉本行代码 13 | */ 14 | require('./dcloud_stat.js');` 15 | 16 | const appCode = `require('./polyfill.js'); 17 | ${options.stat && statCode || ''} 18 | ` 19 | if (options.target === 'uniapp') { 20 | return `${appCode} 21 | ${ret.code} 22 | ` 23 | } 24 | return ` 25 | 29 | ` 30 | } 31 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/style/declaration/border/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('style.declaration.border', () => { 4 | 5 | it('rewrite `border`', () => { 6 | const fixture = ` 7 | .test{ 8 | border:1px solid #fff000; 9 | border-bottom: none; 10 | } 11 | .test2{ 12 | border-top:1rpx solid red; 13 | } 14 | .test3{ 15 | border-radius:50%; 16 | border-left:0; 17 | border-right:0; 18 | border: none; 19 | } 20 | ` 21 | const expected = `.test{border:2px solid #fff000;border-bottom-width:0;}.test2{border-top-width:1px;border-style:solid;border-top-color:red;}.test3{border-radius:375px;border:0;border-left-width:0;border-right-width:0;}` 22 | 23 | rewriter.assertStyleString(fixture, expected) 24 | }) 25 | 26 | }) -------------------------------------------------------------------------------- /test/weapp/transform/page-rewriter/style-rewriter/index.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const expect = chai.expect 3 | 4 | const util = require('../../../../util') 5 | 6 | const rewriter = require(__dirname.replace('test', 'lib')).default 7 | 8 | describe('style', () => { 9 | it('parse `@import`', () => { 10 | const wxss = ` 11 | @import "../../../common/lib/weui.wxss"; 12 | 13 | label { 14 | display: inline-block; 15 | min-width: 270rpx; 16 | margin-right: 20rpx; 17 | } 18 | form:after{ 19 | width: 100%; 20 | } 21 | .picker-text { 22 | 23 | } 24 | 25 | ` 26 | const ret = rewriter(wxss, { 27 | ext: { 28 | wxss: '.nss' 29 | } 30 | }) 31 | expect(ret.deps[0]).eql('../../../common/lib/weui.nss') 32 | }) 33 | 34 | }) -------------------------------------------------------------------------------- /src/weapp/wx/device/index.js: -------------------------------------------------------------------------------- 1 | const getSystemInfo = { 2 | name: 'getInfo', 3 | returnValue (data) { 4 | // uniapp没有pixelRatio、windowWidth、windowHeight、statusBarHeight、language、version、fontSizeSetting、SDKVersion 5 | return { 6 | 'brand': data.brand, 7 | 'model': data.model, 8 | 'screenWidth': data.screenWidth, 9 | 'screenHeight': data.screenHeight, 10 | 'system': data.osVersionCode, 11 | 'platform': data.platformVersionName, 12 | 'pixelRatio': '', 13 | 'windowWidth': '', 14 | 'windowHeight': '', 15 | 'statusBarHeight': '', 16 | 'language': '', 17 | 'version': '', 18 | 'fontSizeSetting': '', 19 | 'SDKVersion': '' 20 | } 21 | } 22 | } 23 | 24 | export default { 25 | getSystemInfo 26 | } 27 | -------------------------------------------------------------------------------- /test/weapp/wx/router/index.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const expect = chai.expect 3 | 4 | require('../util') 5 | 6 | /** 7 | * 模拟快应用router接口 8 | */ 9 | polyfill(__dirname, { 10 | push({ 11 | uri 12 | }) {}, 13 | replace({ 14 | uri 15 | }) {}, 16 | back() {} 17 | }) 18 | 19 | describe('api.router', () => { 20 | 21 | it('wx.navigateTo', () => { 22 | wx.navigateTo({ 23 | url: 'detail', 24 | success: () => {}, 25 | fail: () => {} 26 | }); 27 | }) 28 | 29 | it('wx.redirectTo', () => { 30 | wx.redirectTo({ 31 | url: 'search', 32 | success: () => {}, 33 | complete: () => {} 34 | }); 35 | }) 36 | 37 | it('wx.navigateBack', () => { 38 | wx.navigateBack({ 39 | delta: 1 40 | }); 41 | }) 42 | 43 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/style/declaration/animation/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('style.declaration.animation', () => { 4 | 5 | it('rewrite `animation`', () => { 6 | const fixture = ` 7 | .test{ 8 | animation: mymove 5s infinite ; 9 | animation-name:move; 10 | animation-direction:asd; 11 | animation-fill-mode:ss; 12 | animation-fill-mode:none; 13 | animation: circle infinite 1.5s linear; 14 | } 15 | ` 16 | const expected = `.test{animation-name:move;animation-fill-mode:none;animation-name:mymove;animation-duration:5s;animation-iteration-count:infinite;animation-name:circle;animation-iteration-count:infinite;animation-duration:1.5s;animation-timing-function:linear;}` 17 | 18 | rewriter.assertStyleString(fixture, expected) 19 | }) 20 | 21 | }) -------------------------------------------------------------------------------- /src/weapp/wx/storage/index.js: -------------------------------------------------------------------------------- 1 | const setStorage = { 2 | name: 'set', 3 | args (params) { 4 | return { 5 | value: params.data 6 | } 7 | }, 8 | returnValue () { 9 | return {} 10 | } 11 | } 12 | 13 | const getStorage = { 14 | name: 'get', 15 | returnValue (data) { 16 | return { 17 | data: data 18 | } 19 | } 20 | } 21 | 22 | const removeStorage = { 23 | name: 'delete', 24 | returnValue () { 25 | return {} 26 | } 27 | } 28 | const clearStorage = { 29 | name: 'clear' 30 | } 31 | 32 | export default { 33 | // 暂不支持wx.getStorageInfo() 34 | setStorage, 35 | setStorageSync: setStorage, 36 | getStorage, 37 | getStorageSync: getStorage, 38 | removeStorage, 39 | removeStorageSync: removeStorage, 40 | clearStorage, 41 | clearStorageSync: clearStorage 42 | } 43 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/checkbox/checkbox-group/index.js: -------------------------------------------------------------------------------- 1 | function setName (node, name) { 2 | const children = node.children 3 | if (!children.length) { 4 | return 5 | } 6 | for (let i = 0; i < children.length; i++) { 7 | if (children[i].name === 'checkbox') { 8 | children[i].attributes.name = name 9 | } else { 10 | setName(children[i], name) 11 | } 12 | } 13 | } 14 | 15 | export default { 16 | name: 'div', 17 | beforeAttr (node, { 18 | getAttr, 19 | addAttr 20 | }) { 21 | let name = 'checkbox' + new Date().getTime() // 一个group下的checkbox应该同一个name 22 | if (node.attributes.dtest && node.attributes.dtest === 'test') { 23 | name = 'test' 24 | } 25 | setName(node, name) 26 | }, 27 | afterAttr (node, { 28 | getAttr, 29 | addAttr 30 | }) { 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/basic/rich-text/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag[rich-text]', () => { 4 | 5 | it('rewrite `rich-text` expr', () => { 6 | const fixture = ` 7 | 8 | ` 9 | 10 | const expected = `{{$handleRichText(nodes)}}` 11 | 12 | rewriter.assertTemplateString(fixture, expected) 13 | }) 14 | 15 | it('rewrite `rich-text` string', () => { 16 | const fixture = ` 17 | 18 | ` 19 | 20 | const expected = `{{$handleRichText('ESCAPE:%3Cdiv%3E%3Ca%3Esdff%3C/a%3E%3C/div%3E')}}` 21 | 22 | rewriter.assertTemplateString(fixture, expected) 23 | }) 24 | }) -------------------------------------------------------------------------------- /src/weapp/platform/polyfill/refresh.js: -------------------------------------------------------------------------------- 1 | import { getCurrentPage } from '../App' 2 | import { isFn } from '../../../utils/type' 3 | 4 | export const startPullDownRefresh = ({ 5 | success, 6 | complete 7 | }) => { 8 | const currentPage = getCurrentPage() 9 | currentPage && (currentPage.pageIsRefreshing = true) 10 | isFn(success) && success({ 11 | errMsg: 'startPullDownRefresh:ok' 12 | }) 13 | isFn(complete) && complete({ 14 | errMsg: 'startPullDownRefresh:ok' 15 | }) 16 | } 17 | export const stopPullDownRefresh = ({ 18 | success, 19 | complete 20 | }) => { 21 | const currentPage = getCurrentPage() 22 | currentPage && (currentPage.pageIsRefreshing = false) 23 | isFn(success) && success({ 24 | errMsg: 'stopPullDownRefresh:ok' 25 | }) 26 | isFn(complete) && complete({ 27 | errMsg: 'stopPullDownRefresh:ok' 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/textarea/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'textarea', 3 | beforeAttr (node, { 4 | getAttr 5 | }) { 6 | if (~getAttr('placeholder-style', '').indexOf('color')) { 7 | if (node.attributes.style) { 8 | node.attributes.style = node.attributes.style + 'placeholder-color' + getAttr('placeholder-style').split('color')[1].split(';')[0] + ';' 9 | } else { 10 | node.attributes.style = 'placeholder-color' + getAttr('placeholder-style').split('color')[1].split(';')[0] + ';' 11 | } 12 | } 13 | }, 14 | attr: { // 标签属性转换配置 15 | 'placeholder': 'placeholder', // 提示文本的内容 16 | 'disabled': 'disabled' // 表明当前组件是否可用 17 | }, 18 | event: { 19 | 'linechange': '', 20 | 'confirm': '', 21 | 'focus': 'focus', 22 | 'blur': 'blur', 23 | 'input': 'change' 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/style/declaration/background/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('style.declaration.background', () => { 4 | 5 | it('rewrite `background`', () => { 6 | const fixture = ` 7 | .test{ 8 | background: linear-gradient(45deg, color-stop1, color-stop2); 9 | } 10 | .test2{ 11 | background:#fff000; 12 | background:url(../img.png); 13 | } 14 | .test3{ 15 | background:url(../img.png); 16 | } 17 | .test4{ 18 | background: linear-gradient(top, #222, #333); 19 | } 20 | ` 21 | const expected = `.test{background:linear-gradient(45deg, color-stop1, color-stop2);}.test2{background-color:#fff000;background-image:url(../img.png);}.test3{background-image:url(../img.png);}.test4{background:linear-gradient(to top, #222, #333);}` 22 | 23 | rewriter.assertStyleString(fixture, expected) 24 | }) 25 | 26 | }) -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/radio/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'input', 3 | beforeAttr (node, { 4 | getAttr, 5 | addAttr 6 | }) { 7 | if (!node.attributes.name) { 8 | let name = 'radio-' + new Date().getTime() // 一个group下的radio应该同一个name 9 | if (node.attributes.dtest === 'test') { 10 | name = 'test' 11 | } 12 | node.attributes.name = name 13 | } 14 | }, 15 | afterAttr (node, { 16 | addAttr 17 | }) { 18 | addAttr('type', 'radio') 19 | }, 20 | attr: { // 标签属性转换配置 21 | 'value': 'value', 22 | 'name': 'name', // 快应用专有的属性 23 | 'checked': 'checked', 24 | 'disabled': 'disabled', 25 | 'color': 'STYLE:color' 26 | }, 27 | event: { 28 | 'linechange': '', 29 | 'confirm': '', 30 | 'focus': 'focus', 31 | 'blur': 'blur', 32 | 'input': 'change' 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/weapp/platform/wx.js: -------------------------------------------------------------------------------- 1 | import { isFn } from '../../utils/type' 2 | import { fixedModuleName } from './util' 3 | import modules from './modules' 4 | import parseArgs from './args' 5 | export default new Proxy({}, { 6 | get (target, name) { 7 | // TODO 待处理 polyfill 中的模块方法 8 | const methodDef = modules[name] 9 | if (methodDef) { 10 | return function (args) { 11 | /*eslint-disable camelcase,no-undef*/ 12 | return $app_require$(fixedModuleName(methodDef['module']))[methodDef.name](parseArgs(args, { 13 | method: name 14 | })) 15 | } 16 | } 17 | return function ({ 18 | fail, 19 | complete 20 | } = {}) { 21 | const ret = { 22 | errMsg: name + ':fail' 23 | } 24 | isFn(fail) && fail(ret) 25 | isFn(complete) && complete(ret) 26 | console.error(`暂不支持wx.${name}调用`) 27 | } 28 | } 29 | }) 30 | -------------------------------------------------------------------------------- /test/weapp/babel/index.test.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const fs = require('fs-extra') 3 | const chai = require('chai') 4 | const expect = chai.expect 5 | 6 | const babel = require('babel-core') 7 | 8 | const plugins = require('../../../lib/weapp/babel').default 9 | 10 | describe('babel.import', () => { 11 | 12 | it('transform `import|require`', () => { 13 | const fixture = `const a = require('a.js'); 14 | const b = require('./b.js'); 15 | import c from 'c.js'; 16 | import './c.js';` 17 | 18 | const expected = `const a = require('./a.js'); 19 | const b = require('./b.js'); 20 | import c from './c.js'; 21 | import './c.js';` 22 | 23 | const ret = babel.transform(fixture, { 24 | plugins: [ 25 | [plugins, { 26 | page: 'pages/page', 27 | target: 'uniapp' 28 | }] 29 | ] 30 | }) 31 | expect(ret.code).eql(expected) 32 | 33 | }) 34 | 35 | }) -------------------------------------------------------------------------------- /test/weapp/transform/manifest-rewriter/index.test.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const fs = require('fs-extra') 3 | const chai = require('chai') 4 | const expect = chai.expect 5 | 6 | const rewriter = require(__dirname.replace('test', 'lib')).default 7 | 8 | describe('manifest', () => { 9 | 10 | it('rewrite `window`', () => { 11 | const inputPath = path.join(__dirname, '../../../../demo/weapp/input') 12 | const appJson = require('./app.json') 13 | appJson.page = {} 14 | const { 15 | manifest, 16 | components 17 | } = rewriter(appJson, inputPath) 18 | expect(manifest.display.backgroundColor).eql(appJson.window.backgroundColor) 19 | expect(manifest.display.titleBarBackgroundColor).eql(appJson.window.navigationBarBackgroundColor) 20 | expect(manifest.display.titleBarText).eql(appJson.window.navigationBarTitleText) 21 | console.log(components) 22 | }) 23 | 24 | }) -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/media/video/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'video', 3 | attr: { 4 | 'src': 'src', 5 | 'initial-time': 'I:', 6 | 'duration': 'I:', 7 | 'controls': 'I:', 8 | 'danmu-list': 'I:', 9 | 'danmu-btn': 'I:', 10 | 'enable-danmu': 'I:', 11 | 'autoplay': 'autoplay', 12 | 'loop': 'I:', 13 | 'muted': 'I:', 14 | 'page-gesture': 'I:', 15 | 'direction': 'I:', 16 | 'show-progress': 'I:', 17 | 'show-fullscreen-btn': 'I:', 18 | 'show-play-btn': 'I:', 19 | 'show-center-play-btn': 'I:', 20 | 'enable-progress-gesture': 'I:', 21 | 'objectfit': 'I:', 22 | 'poster': 'poster' 23 | }, 24 | event: { 25 | 'play': 'start', 26 | 'pause': 'pause', 27 | 'ended': 'finish', 28 | 'timeupdate': 'timeupdate', 29 | 'fullscreenchange': 'fullscreenchange', 30 | 'error': 'error', 31 | 'waiting': '' 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/event/index.js: -------------------------------------------------------------------------------- 1 | const evts = { 2 | 'touchstart': '', 3 | 'touchmove': '', 4 | 'touchcancel': '', 5 | 'touchend': '', 6 | 'tap': 'click', 7 | 'longpress': 'longpress', 8 | 'longtap': 'longpress', 9 | 'transitionend': '', 10 | 'animationstart': '', 11 | 'animationiteration': '', 12 | 'animationend': '' 13 | } 14 | 15 | export const initEvents = evts => { 16 | const events = {} 17 | Object.keys(evts).forEach(name => { 18 | events['bind' + name] = evts[name] 19 | events['bind:' + name] = evts[name] 20 | events['catch' + name] = evts[name] 21 | events['catch:' + name] = evts[name] 22 | events['capture-bind' + name] = evts[name] 23 | events['capture-bind:' + name] = evts[name] 24 | events['capture-catch' + name] = evts[name] 25 | events['capture-catch:' + name] = evts[name] 26 | }) 27 | return events 28 | } 29 | 30 | export default initEvents(evts) 31 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/index.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import fs from 'fs-extra' 3 | 4 | import { initEvents } from '../event' 5 | 6 | const tags = {} 7 | 8 | !(function parse (dir) { 9 | dir = dir || '.' 10 | const dirPath = path.join(__dirname, dir) 11 | fs.readdirSync(dirPath).forEach(file => { 12 | const filePath = path.join(dirPath, file) 13 | if (fs.statSync(filePath).isFile()) { 14 | if (path.extname(filePath) === '.js') { 15 | const tagName = path.basename(path.dirname(filePath)) 16 | if (tagName !== 'tag') { 17 | const component = require(filePath)['default'] 18 | if (component.event) { 19 | component.event = initEvents(component.event) 20 | } 21 | tags[tagName] = component 22 | } 23 | } 24 | } else { 25 | parse(path.join(dir, file)) 26 | } 27 | }) 28 | })('.') 29 | 30 | export default tags 31 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/event/picker/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | change: { // 快应用事件名 3 | detail: function (evt) { // 转换detail 4 | switch (evt.target.attr.type) { 5 | case 'time': 6 | evt.minute = evt.minute < 10 ? ('0' + evt.minute) : evt.minute 7 | evt.hour = evt.hour < 10 ? ('0' + evt.hour) : evt.hour 8 | return { 9 | value: evt.hour + ':' + evt.minute 10 | } 11 | case 'date': 12 | evt.month = evt.month < 10 ? ('0' + evt.month) : evt.month 13 | evt.day = evt.day < 10 ? ('0' + evt.day) : evt.day 14 | return { 15 | value: evt.year + '-' + evt.month + '-' + evt.day 16 | } 17 | case 'text': 18 | return { 19 | value: evt.newSelected 20 | } 21 | default: 22 | return { 23 | value: '' 24 | } 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/style/declaration/text/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'color': (value, declaration, addDeclaration) => { 3 | if (~value.indexOf('inherit')) { 4 | return 'I:' 5 | } 6 | }, 7 | 'line-height': '', 8 | 'text-align': (value, declaration, addDeclaration) => { 9 | addDeclaration('align-items', 'center') 10 | addDeclaration('justify-content', 'center') 11 | if (~value.indexOf('justify')) { 12 | return 'I:' 13 | } 14 | }, 15 | 'text-decoration': (value, declaration, addDeclaration) => { 16 | if (~['overline', 'blink'].indexOf(value)) { 17 | return 'I:' 18 | } 19 | }, 20 | 'text-overflow': (value, declaration, addDeclaration) => { 21 | // 在设置了行数的情况下生效 22 | if (value) { 23 | addDeclaration('lines', '1') 24 | } 25 | }, 26 | 'white-space': 'I:', 27 | 'word-wrap': 'I:', 28 | 'word-break': 'I:', 29 | 'text-align-last': 'I:', 30 | 'line-clamp': 'I:' 31 | } 32 | -------------------------------------------------------------------------------- /src/weapp/wx/packer.js: -------------------------------------------------------------------------------- 1 | import barcode from './barcode/index.js' 2 | import brightness from './brightness/index.js' 3 | import clipboard from './clipboard/index.js' 4 | import device from './device/index.js' 5 | import fetch from './fetch/index.js' 6 | import file from './file/index.js' 7 | import geolocation from './geolocation/index.js' 8 | import media from './media/index.js' 9 | import network from './network/index.js' 10 | import prompt from './prompt/index.js' 11 | import request from './request/index.js' 12 | import router from './router/index.js' 13 | import sensor from './sensor/index.js' 14 | import storage from './storage/index.js' 15 | import vibrator from './vibrator/index.js' 16 | 17 | export default { 18 | barcode, 19 | brightness, 20 | clipboard, 21 | device, 22 | fetch, 23 | file, 24 | geolocation, 25 | media, 26 | network, 27 | prompt, 28 | request, 29 | router, 30 | sensor, 31 | storage, 32 | vibrator 33 | } 34 | -------------------------------------------------------------------------------- /src/weapp/platform/polyfill/index.js: -------------------------------------------------------------------------------- 1 | /*eslint-disable camelcase,no-undef*/ 2 | const app = $app_require$('@app-module/system.app') 3 | 4 | export * from './refresh' 5 | export * from './storage' 6 | export * from './navigationbar' 7 | 8 | export async function getSystemInfoSync () { 9 | return new Promise((resolve, reject) => { 10 | app.getInfo({ 11 | success (data) { 12 | resolve({ 13 | 'brand': data.brand, 14 | 'model': data.model, 15 | 'screenWidth': data.screenWidth, 16 | 'screenHeight': data.screenHeight, 17 | 'system': data.osVersionCode, 18 | 'platform': data.platformVersionName, 19 | 'pixelRatio': '', 20 | 'windowWidth': '', 21 | 'windowHeight': '', 22 | 'statusBarHeight': '', 23 | 'language': '', 24 | 'version': '', 25 | 'fontSizeSetting': '', 26 | 'SDKVersion': '' 27 | }) 28 | } 29 | }) 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/form/textarea/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.textarea', () => { 4 | 5 | it('rewrite `textarea`', () => { 6 | const fixture = ` 7 | 11 | ` 12 | 13 | const expected = `` 14 | 15 | rewriter.assertTemplateString(fixture, expected) 16 | }) 17 | 18 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/form/picker/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.picker', () => { 4 | 5 | it('rewrite `picker`', () => { 6 | // const fixture = ` 7 | // 8 | // {{time}} 9 | // 10 | //` 11 | const fixture = ` 12 | 13 | {{date}} 14 | 15 | ` 16 | 17 | // const expected = `` 18 | const expected = `` 19 | 20 | rewriter.assertTemplateString(fixture, expected) 21 | }) 22 | 23 | }) -------------------------------------------------------------------------------- /src/weapp/platform/uniapp/index.js: -------------------------------------------------------------------------------- 1 | import '../regenerator' 2 | import App from '../App' 3 | import Page from '../Page' 4 | import Behavior from '../Behavior' 5 | import Template from '../Template' 6 | import Component from '../Component' 7 | 8 | import parseArgs from '../args' 9 | 10 | import { fixedModuleName } from '../util' 11 | 12 | import * as polyfill from '../polyfill/index' 13 | 14 | import wx from '../wx' 15 | 16 | const uni = Object.assign({}, polyfill) 17 | 18 | uni.parseArgs = parseArgs 19 | 20 | const _$global$_ = Object.getPrototypeOf(global) || global 21 | 22 | _$global$_.wx = wx 23 | 24 | _$global$_.App = App 25 | _$global$_.Page = Page 26 | _$global$_.Behavior = Behavior 27 | _$global$_.Template = Template 28 | _$global$_.Component = Component 29 | 30 | _$global$_.uni = new Proxy(uni, { 31 | get (target, name) { 32 | if (uni[name]) { 33 | return uni[name] 34 | } 35 | /*eslint-disable camelcase,no-undef*/ 36 | return $app_require$(fixedModuleName(name)) 37 | } 38 | }) 39 | -------------------------------------------------------------------------------- /test/weapp/wx/network/index.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const expect = chai.expect 3 | 4 | require('../util') 5 | 6 | /** 7 | * 模拟快应用network接口 8 | */ 9 | const errCode = 404; 10 | polyfill(__dirname, { 11 | getType({ 12 | success, 13 | fail, 14 | complete 15 | }) { 16 | success({ 17 | type: 'wifi' 18 | }) 19 | complete({ 20 | type: 'wifi' 21 | }) 22 | }, 23 | subscribe({ 24 | callback 25 | }) { 26 | callback({ 27 | type: 'wifi' 28 | }) 29 | } 30 | }) 31 | 32 | describe('api.network', () => { 33 | 34 | it('wx.getNetworkType', () => { 35 | wx.getNetworkType({ 36 | success: data => { 37 | expect(data.networkType).eql('wifi') 38 | }, 39 | complete: data => { 40 | expect(data.networkType).eql('wifi') 41 | } 42 | }) 43 | }) 44 | 45 | it('wx.onNetworkStatusChange', () => { 46 | wx.onNetworkStatusChange(data => { 47 | expect(data.networkType).eql('wifi') 48 | }) 49 | }) 50 | }) -------------------------------------------------------------------------------- /src/weapp/transform/page-rewriter/template-rewriter/index.js: -------------------------------------------------------------------------------- 1 | import parseWxml from './wxml' 2 | import rewriteNode from './node' 3 | export default function rewrite (code, pagePath, options, fs) { 4 | options = Object.assign({}, options) 5 | parseWxml(code, pagePath, options, fs, true) 6 | 7 | const { 8 | ret: { 9 | entry, 10 | deps 11 | } 12 | } = options 13 | 14 | let logs = [] 15 | const depNodes = [] 16 | const entryRet = rewriteNode(entry.nodes, options.usingComponents) 17 | logs = logs.concat(entryRet.logs) 18 | 19 | Object.keys(deps).forEach(dep => { 20 | const depRet = rewriteNode(deps[dep].nodes) 21 | logs = logs.concat(depRet.logs) 22 | depNodes.push({ 23 | path: dep, 24 | imports: depRet.imports, 25 | nodes: depRet.nodes, 26 | wxs: deps[dep]['wxs'] 27 | }) 28 | }) 29 | 30 | return { 31 | logs: logs, 32 | imports: entryRet.imports, 33 | nodes: entryRet.nodes, 34 | wxs: entry.wxs, 35 | deps: depNodes 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/weapp/platform/polyfill/navigationbar.js: -------------------------------------------------------------------------------- 1 | import { getCurrentPage } from '../App' 2 | import { isFn } from '../../../utils/type' 3 | 4 | export const setNavigationBarTitle = ({ 5 | title, 6 | success, 7 | complete 8 | }) => { 9 | const currentPage = getCurrentPage() 10 | currentPage && (currentPage.$page.setTitleBar({ 11 | text: title || '' 12 | })) 13 | isFn(success) && success({ 14 | errMsg: 'startPullDownRefresh:ok' 15 | }) 16 | isFn(complete) && complete({ 17 | errMsg: 'startPullDownRefresh:ok' 18 | }) 19 | } 20 | export const setNavigationBarColor = ({ 21 | frontColor, 22 | backgroundColor, 23 | success, 24 | complete 25 | }) => { 26 | const currentPage = getCurrentPage() 27 | currentPage && (currentPage.$page.setTitleBar({ 28 | textColor: frontColor || '', 29 | backgroundColor: backgroundColor || '' 30 | })) 31 | isFn(success) && success({ 32 | errMsg: 'stopPullDownRefresh:ok' 33 | }) 34 | isFn(complete) && complete({ 35 | errMsg: 'stopPullDownRefresh:ok' 36 | }) 37 | } 38 | -------------------------------------------------------------------------------- /test/weapp/wx/geolocation/index.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const expect = chai.expect 3 | 4 | require('../util') 5 | 6 | const errCode = 404 7 | 8 | polyfill(__dirname, { 9 | getLocation({ 10 | data, 11 | success, 12 | fail, 13 | complete 14 | }) { 15 | if(data === 'fail'){ 16 | fail('获取失败', errCode) 17 | }else{ 18 | success({latitude:'39.969137',longitude:'116.347384'}) 19 | complete({latitude:'39.969137',longitude:'116.347384'}) 20 | } 21 | } 22 | }) 23 | 24 | describe('api.geolocation', () => { 25 | it('wx.getLocation', () => { 26 | wx.getLocation({ 27 | success: function (res) { 28 | expect(res.latitude).eql('39.969137') 29 | }, 30 | complete:function (res) { 31 | expect(res.longitude).eql('116.347384') 32 | } 33 | }) 34 | wx.getLocation({ 35 | data:'fail', 36 | fail: function (data, code) { 37 | expect(code).eql(errCode) 38 | } 39 | }) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/radio/radio-group/index.js: -------------------------------------------------------------------------------- 1 | function setName (node, name, event) { 2 | const children = node.children 3 | if (!children.length) { 4 | return 5 | } 6 | for (let i = 0; i < children.length; i++) { 7 | if (children[i].name === 'radio') { 8 | children[i].attributes.name = name 9 | if (event) { 10 | children[i].attributes.bindinput = event 11 | } 12 | } else { 13 | setName(children[i], name, event) 14 | } 15 | } 16 | } 17 | 18 | export default { 19 | name: 'div', 20 | beforeAttr (node, { 21 | getAttr, 22 | addAttr 23 | }) { 24 | let event = '' 25 | if (node.attributes.bindchange) { 26 | event = node.attributes.bindchange 27 | } 28 | let name = 'radio' + new Date().getTime() // 一个group下的radio应该同一个name 29 | if (node.attributes.dtest && node.attributes.dtest === 'test') { 30 | name = 'test' 31 | } 32 | setName(node, name, event) 33 | }, 34 | afterAttr (node, { 35 | getAttr, 36 | addAttr 37 | }) {} 38 | } 39 | -------------------------------------------------------------------------------- /src/weapp/babel/uniapp/index.js: -------------------------------------------------------------------------------- 1 | const createArgsCallExpression = (t, arg, { 2 | state, 3 | wxMethod 4 | }) => { 5 | const objectExpression = t.objectExpression([ 6 | t.objectProperty(t.identifier('page'), t.stringLiteral(state.opts.page || '')), 7 | t.objectProperty(t.identifier('method'), t.stringLiteral(wxMethod)) 8 | ]) 9 | return t.callExpression(t.memberExpression(t.identifier('uni'), t.identifier('parseArgs')), [arg, objectExpression]) 10 | } 11 | 12 | export default function (t, args, { 13 | type, 14 | state, 15 | module, 16 | method, 17 | wxMethod 18 | }) { 19 | let callee 20 | if (type === 'custom') { 21 | callee = t.memberExpression(t.identifier('uni'), t.identifier(wxMethod)) 22 | } else { 23 | callee = t.memberExpression(t.memberExpression(t.identifier('uni'), t.identifier(module)), t.identifier(method)) 24 | if (!~wxMethod.indexOf('Sync') && args && args.length === 1) { 25 | args = [createArgsCallExpression(t, args[0], { 26 | state, 27 | wxMethod 28 | })] 29 | } 30 | } 31 | return t.callExpression(callee, args) 32 | } 33 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/picker/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'picker', 3 | beforeAttr (node, { 4 | getAttr, 5 | addClass 6 | }) { 7 | if (node.children) { // 清空 8 | node.children.splice(0, node.children.length) 9 | } 10 | if (!node.attributes.mode || node.attributes.mode === 'selector') { 11 | node.attributes.mode = 'text' 12 | if (node.attributes.range && node.attributes.value) { 13 | const arr = node.attributes.range.replace(/\}|\{/ig, '') 14 | const index = node.attributes.value.replace(/\}|\{/ig, '') 15 | node.attributes.value = '{{' + arr + '[' + index + ']}}' 16 | } 17 | } 18 | if (node.attributes.mode === 'multiSelector' || node.attributes.mode === 'region') { // 这两个是不支持的,暂时这样处理把 19 | node.attributes.mode = 'text' 20 | } 21 | }, 22 | attr: { 23 | 'mode': 'type', 24 | 'start': 'start', 25 | 'end': 'end', 26 | 'range': 'range', 27 | 'disabled': 'disabled', 28 | // 'range-key': 'ERROR:', 29 | 'value': 'value' 30 | }, 31 | event: { 32 | 'change': 'change' 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/weapp/wx/barcode/index.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const expect = chai.expect 3 | 4 | require('../util') 5 | 6 | /** 7 | * 模拟快应用barcode接口 8 | */ 9 | const errCode = 404; 10 | polyfill(__dirname, { 11 | scan({ 12 | success, 13 | complete 14 | }) { 15 | success({ 16 | result: 'hello' 17 | }) 18 | complete({ 19 | result: 'hello' 20 | }) 21 | }, 22 | scan({ 23 | fail 24 | }) { 25 | if (false) { 26 | fail('调用失败', errCode) 27 | } 28 | } 29 | }) 30 | 31 | describe('api.barcode', () => { 32 | 33 | it('wx.scanCode', () => { 34 | wx.scanCode({ 35 | onlyFromCamera: true, 36 | scanType: ['qrCode'], 37 | success: data => { 38 | expect(data.result).eql('hello') 39 | }, 40 | complete: data => { 41 | expect(data.result).eql('hello') 42 | } 43 | }) 44 | }) 45 | 46 | it('wx.scanCode', () => { 47 | wx.scanCode({ 48 | onlyFromCamera: true, 49 | scanType: ['qrCode'], 50 | fail: (data, code) => { 51 | expect(code).eql(404) 52 | } 53 | }) 54 | }) 55 | }) -------------------------------------------------------------------------------- /src/weapp/platform/richtext.js: -------------------------------------------------------------------------------- 1 | const walk = node => { 2 | let attrsCode = '' 3 | let childrenCode = '' 4 | const attributes = node.attrs 5 | if (attributes) { 6 | const attrs = Object.keys(attributes) 7 | if (attrs.length) { 8 | attrsCode = ' ' + attrs.map(name => `${name}="${attributes[name]}"`).join(' ') 9 | } 10 | } 11 | if (node.children) { 12 | childrenCode = node.children.map(childNode => walk(childNode)).join('') 13 | } 14 | return `<${node.name || node.type}${attrsCode}>${node.text || ''}${childrenCode}` 15 | } 16 | 17 | const serialize = nodes => { 18 | if (!Array.isArray(nodes)) { 19 | nodes = [nodes] 20 | } 21 | return nodes.map(node => walk(node)).join('\r\n') 22 | } 23 | 24 | export default function handleRichText (nodes) { 25 | if (nodes) { 26 | if (typeof nodes === 'string') { 27 | if (nodes.indexOf('ESCAPE:') === 0) { 28 | return unescape(nodes.substr(7)) 29 | } 30 | return nodes 31 | } else if (Array.isArray(nodes)) { 32 | return serialize(nodes) 33 | } 34 | } 35 | return '' 36 | } 37 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/form/checkbox/checkbox-group/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../../util') 2 | 3 | describe('template.tag.checkbox-group', () => { 4 | 5 | it('rewrite `checkbox-group`', () => { 6 | const fixture = ` 7 | 8 | 14 | 15 | ` 16 | 17 | const expected = `
{{item.name}}
` 18 | 19 | rewriter.assertTemplateString(fixture, expected) 20 | }) 21 | 22 | }) -------------------------------------------------------------------------------- /src/weapp/transform/helper/style/declaration/dimension/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'height': (value, declaration, addDeclaration) => { 3 | if (~value.indexOf('auto') || ~value.indexOf('inherit')) { 4 | addDeclaration('display', 'flex') // 部分应用利用height:0,height:auto来实现隐藏,显示 5 | // addDeclaration('flex-direction', 'row') 6 | return 'I:' 7 | } 8 | if (parseInt(value) === 0) { 9 | addDeclaration('display', 'none') // 部分应用利用height:0,height:auto来实现隐藏,显示 10 | return 'I:' 11 | } 12 | return '' 13 | }, 14 | 'max-height': 'I:', 15 | 'max-width': 'I:', 16 | 'min-height': 'I:', 17 | 'min-width': 'I:', 18 | 'width': (value, declaration, addDeclaration) => { 19 | if (~value.indexOf('auto') || ~value.indexOf('inherit')) { 20 | addDeclaration('display', 'flex') // 部分应用利用height:0,height:auto来实现隐藏,显示 21 | // addDeclaration('flex-direction', 'row') 22 | return 'I:' 23 | } 24 | if (parseInt(value) === 0) { 25 | addDeclaration('display', 'none') // 部分应用利用height:0,height:auto来实现隐藏,显示 26 | return 'I:' 27 | } 28 | return '' 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/button/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'input', 3 | content: 'value', // 如果input标签内部直接跟文本,则将文本转换为value属性值 4 | beforeAttr (node, { 5 | getAttr, 6 | addClass 7 | }) { 8 | // 处理size、type、plain属性。 9 | let typeClass = 'u-w-button-' + getAttr('type', 'default') 10 | if (getAttr('plain', false)) { 11 | typeClass += '-plain' 12 | } 13 | addClass(typeClass) 14 | // addClass('u-w-button-' + getAttr('type', 'default')) 15 | // 这里type和size的值有可能一样,所以忽略尺寸的default。 16 | if (getAttr('size', 'default') !== 'default') { 17 | addClass('u-w-button-' + getAttr('size', 'default')) 18 | } 19 | // disabled通过伪类选择器处理 20 | }, 21 | afterAttr (node, { 22 | addAttr 23 | }) { 24 | addAttr('type', 'button') // 为input动态增加type:button 25 | }, 26 | attr: { 27 | 'disabled': 'disabled', 28 | 'form-type': 'E:', 29 | 'open-type': 'E:', 30 | 'app-parameter': 'E:', 31 | 'session-from': 'E:', 32 | 'send-message-title': 'E:', 33 | 'send-message-path': 'E:', 34 | 'send-message-img': 'E:' 35 | }, 36 | event: { 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/weapp/wx/sensor/index.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const expect = chai.expect 3 | 4 | require('../util') 5 | 6 | /** 7 | * 模拟快应用sensor接口 8 | */ 9 | polyfill(__dirname, { 10 | subscribeCompass({ 11 | callback 12 | }) { 13 | callback({ 14 | direction:132 15 | }) 16 | }, 17 | unsubscribeCompass(){}, 18 | subscribeAccelerometer({ 19 | callback 20 | }) { 21 | callback({ 22 | x:1, 23 | y:2, 24 | z:3 25 | }) 26 | }, 27 | unsubscribeAccelerometer(){} 28 | }) 29 | 30 | describe('api.sensor', () => { 31 | 32 | it('wx.onCompassChange', () => { 33 | wx.onCompassChange(function(res) { 34 | expect(res.direction).eql(132) 35 | }) 36 | }) 37 | 38 | it('wx.stopCompass', () => { 39 | wx.stopCompass({ 40 | success:function(ret){ 41 | console.log(ret); 42 | } 43 | }) 44 | }) 45 | it('wx.onAccelerometerChange', () => { 46 | wx.onAccelerometerChange(function(res) { 47 | expect(res.x).eql(1) 48 | }) 49 | }) 50 | 51 | it('wx.stopAccelerometer', () => { 52 | wx.stopAccelerometer({ 53 | success:function(ret){ 54 | console.log(ret); 55 | } 56 | }) 57 | }) 58 | 59 | }) -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/view/swiper/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'swiper', // 转换后的标签名称 3 | beforeAttr (node, { 4 | getAttr, 5 | addAttr 6 | }) { 7 | // 小程序默认不显示指示点,但是快应用默认是显示的。 8 | const indicator = getAttr('indicator-dots') 9 | if (!indicator) { 10 | addAttr('indicator-dots', false) 11 | } 12 | }, 13 | attr: { // 标签属性转换配置 14 | 'indicator-dots': 'indicator', // 将小程序swiper标签的indicator-dots属性转换为indicator 15 | 'indicator-color': 'STYLE:indicator-color', // 将小程序swiper标签的indicator-color属性转换为style中的indicator-color 16 | 'indicator-active-color': 'STYLE:indicator-selected-color', 17 | 'autoplay': 'autoplay', 18 | 'current': 'index', 19 | 'current-item-id': 'E:请在转换后的swiper组件中配置`index`属性替换', // E:表示不支持该属性,且该属性会引发使用问题 20 | 'interval': 'interval', 21 | 'duration': 'I:', 22 | 'circular': 'I:', 23 | 'vertical': 'I:启用横向滚动替换', // I:表示不支持该属性,且该属性不会引发使用问题(可能样式会有差异) 24 | 'previous-margin': 'I:', 25 | 'next-margin': 'I:', 26 | 'display-multiple-items': 'I:', 27 | 'skip-hidden-item-layout': 'I:' 28 | }, 29 | event: { 30 | 'change': 'change' 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/style/declaration/box/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'box-sizing': 'I:', 3 | 'box-flex': 'I:', 4 | 'box-align': (value, declaration, addDeclaration) => { 5 | const boxAlign = { 6 | start: 'flex-start', 7 | end: 'flex-end', 8 | center: 'center', 9 | baseline: 'baseline', 10 | stretch: 'stretch' 11 | } 12 | addDeclaration('align-items', boxAlign[value]) 13 | return 'I:' 14 | }, 15 | 'box-orient': (value, declaration, addDeclaration) => { 16 | const boxOrient = { 17 | 'horizontal': 'row', 18 | 'vertical': 'row-reverse', 19 | 'inline-axis': 'row', 20 | 'block-axis': 'row-reverse', 21 | 'inherit': '' 22 | } 23 | if (value === 'inherit') { 24 | return 'I:' 25 | } 26 | // flex-direction 不支持 row-reverse 27 | if (!~boxOrient[value].indexOf('row-reverse')) { 28 | addDeclaration('flex-direction', boxOrient[value]) 29 | } 30 | return 'I:' 31 | }, 32 | 'float': 'E:', 33 | 'content': 'I:', 34 | 'overflow': 'I:', 35 | 'overflow-x': 'I:', 36 | 'overflow-y': 'I:', 37 | 'overflow-scrolling': 'I:' 38 | } 39 | -------------------------------------------------------------------------------- /src/weapp/platform/navigator.js: -------------------------------------------------------------------------------- 1 | import parseRouter from './router' 2 | import { getCurrentPage } from './App' 3 | 4 | export default function createHandleRouterEvent (/*eslint-disable camelcase*/ $app_require$, pagePath) { 5 | return function (openType, evt) { 6 | if (!pagePath) { 7 | const page = getCurrentPage() 8 | if (page) { 9 | pagePath = page._$path$_ 10 | } else { 11 | pagePath = '' 12 | } 13 | } 14 | /*eslint-disable camelcase*/ 15 | const router = $app_require$('@app-module/system.router') 16 | if (openType === 'navigateBack') { 17 | router.back() 18 | } else { 19 | const url = evt.target.attr && evt.target.attr.dataUrl 20 | if (url) { 21 | switch (openType) { 22 | case 'navigate': 23 | router.push(parseRouter(url, pagePath)) 24 | break 25 | case 'redirect': 26 | router.replace(parseRouter(url, pagePath)) 27 | break 28 | case 'switchTab': 29 | router.replace(parseRouter(url)) 30 | router.clear() 31 | break 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/checkbox/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'input', 3 | beforeAttr (node, { 4 | getAttr, 5 | addAttr 6 | }) { 7 | // let content = node.content; 8 | // if(content) { 9 | // let children = node.parent.children; 10 | // for(let i = 0; i < children.length; i++) { 11 | // if(children[i] == node) { 12 | // node.parent.children.splice((i+1), 0, { 13 | // name: 'text', 14 | // content: content, 15 | // attributes: { 16 | // class: 'u-w-text' 17 | // }, 18 | // children: [] 19 | // }) 20 | // delete node.content; 21 | // break; 22 | // } 23 | // } 24 | // } 25 | }, 26 | afterAttr (node, { 27 | addAttr 28 | }) { 29 | addAttr('type', 'checkbox') 30 | }, 31 | attr: { // 标签属性转换配置 32 | 'value': 'value', 33 | 'name': 'name', // 快应用专有的属性 34 | 'checked': 'checked', 35 | 'disabled': 'disabled', 36 | 'color': 'STYLE:color' 37 | }, 38 | event: { 39 | 'linechange': '', 40 | 'confirm': '', 41 | 'focus': 'focus', 42 | 'blur': 'blur', 43 | 'input': 'change' 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/weapp/transform/page-rewriter/template-rewriter/event.js: -------------------------------------------------------------------------------- 1 | import { isExpr } from '../../../../utils' 2 | const rewriteEventValue = (name, attr, eventName, stopPropagation = false, capture = false) => { 3 | let value = attr[name].trim() 4 | if (~value.indexOf('$handleRouterEvent')) { 5 | return 6 | } 7 | if (isExpr(value)) { 8 | value = value.substr(2, value.length - 4) 9 | attr[name] = `$handlePageEvent(${value},${stopPropagation},${capture})` 10 | } else { 11 | attr[name] = `$handlePageEvent('${value}',${stopPropagation},${capture})` 12 | } 13 | } 14 | export default function rewriteEvent (name, attr, events, node, output, location) { 15 | if (!events[name]) { 16 | output.logs.push({ 17 | reason: 'E: 不支持`' + name + '`事件转换', 18 | line: location.line, 19 | column: location.column 20 | }) 21 | node.$deleteAttrs[name] = attr[name] 22 | } else { 23 | let eventName = events[name] 24 | if (typeof eventName === 'string') { 25 | if (!eventName) { 26 | eventName = name 27 | } 28 | rewriteEventValue(name, attr, eventName) 29 | attr['on' + eventName] = attr[name] 30 | } 31 | } 32 | delete attr[name] 33 | } 34 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/tag/form/input/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'input', 3 | content: 'value', 4 | beforeAttr (node, { 5 | getAttr 6 | }) { 7 | if (~getAttr('placeholder-style', '').indexOf('color')) { 8 | if (node.attributes.style) { 9 | node.attributes.style = node.attributes.style + 'placeholder-color' + getAttr('placeholder-style').split('color')[1].split(';')[0] + ';' 10 | } else { 11 | node.attributes.style = 'placeholder-color' + getAttr('placeholder-style').split('color')[1].split(';')[0] + ';' 12 | } 13 | } 14 | if (getAttr('password') || getAttr('password') === '') { 15 | node.attributes.type = 'password' 16 | } 17 | if (getAttr('type') === 'digit') { 18 | node.attributes.type = 'number' 19 | } 20 | // 部分身份证信息中有英文,因而不能转成数字键盘。 21 | if (getAttr('type') === 'idcard') { 22 | node.attributes.type = 'text' 23 | } 24 | }, 25 | attr: { 26 | 'value': 'value', 27 | 'type': 'type', 28 | 'placeholder': 'placeholder', 29 | 'disabled': 'disabled' 30 | }, 31 | event: { 32 | 'input': 'change', 33 | 'focus': 'focus', 34 | 'blur': 'blur', 35 | 'confirm': '' 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/weapp/transform/page-rewriter/parser.js: -------------------------------------------------------------------------------- 1 | import sax from 'sax' 2 | 3 | export default function parse (xml) { 4 | const parser = sax.parser(false, { 5 | trim: true, 6 | lowercase: true, 7 | position: true 8 | }) 9 | let root 10 | let currentParent 11 | const stack = [] 12 | 13 | parser.onerror = function (e) { 14 | console.log(e) 15 | } 16 | 17 | parser.ontext = function (t) { 18 | currentParent && (currentParent.content = t.trim() || '') 19 | } 20 | 21 | parser.oncdata = function (t) { 22 | currentParent && (currentParent.content = t.trim() || '') 23 | } 24 | 25 | parser.onopentag = function (node) { 26 | node.children = [] 27 | node.location = { 28 | line: this.line, 29 | column: this.column 30 | } 31 | if (!root) { 32 | root = node 33 | } 34 | if (currentParent) { 35 | node.parent = currentParent 36 | currentParent.children.push(node) 37 | } 38 | currentParent = node 39 | stack.push(currentParent) 40 | } 41 | 42 | parser.onclosetag = function (tagName) { 43 | stack.length -= 1 44 | currentParent = stack[stack.length - 1] 45 | } 46 | 47 | parser.write(xml).close() 48 | 49 | return root 50 | } 51 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/directive/wx-for.js: -------------------------------------------------------------------------------- 1 | import { isExpr } from '../../../../utils' 2 | 3 | export default function rewriter (node) { 4 | if (!node.$forProcessed) { 5 | node.$forProcessed = true 6 | const attrs = node.attributes 7 | let wxFor = '' 8 | let wxForIndex = 'index' 9 | let wxForItem = 'item' 10 | let wxKey = '' 11 | Object.keys(attrs).forEach(name => { 12 | switch (name) { 13 | case 'wx:for': 14 | case 'wx:for-items': 15 | wxFor = attrs[name] 16 | delete attrs[name] 17 | break 18 | case 'wx:for-index': 19 | wxForIndex = attrs[name] 20 | delete attrs[name] 21 | break 22 | case 'wx:for-item': 23 | wxForItem = attrs[name] 24 | delete attrs[name] 25 | break 26 | case 'wx:key': 27 | wxKey = attrs[name] 28 | delete attrs[name] 29 | break 30 | } 31 | }) 32 | 33 | if (isExpr(wxFor)) { 34 | wxFor = wxFor.substr(2, wxFor.length - 4) 35 | } 36 | attrs['for'] = `{{(${wxForIndex},${wxForItem}) in ${wxFor}}}` 37 | if (wxKey && !~wxKey.indexOf('*')) { 38 | attrs['tid'] = wxKey 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /bin/uni-migration.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const path = require('path') 4 | const fs = require('fs-extra') 5 | const Program = require('commander') 6 | const migrate = require('../lib') 7 | const pkg = require('../package.json') 8 | 9 | Program 10 | .description('小程序转换工具') 11 | .usage('[options] [input_dir] output_dir') 12 | .option('-v, --version', '版本号') 13 | .option('--sign', '生成sign目录') 14 | .option('--stat', '生成dcloud_stat统计代码') 15 | .option('-p, --platform [platform]', '可选`quickapp`|`uniapp`,目前仅支持小程序向quickapp或uniapp转换') 16 | .parse(process.argv) 17 | 18 | if (Program.help === undefined) { 19 | Program.outputHelp() 20 | process.exit(0) 21 | } 22 | 23 | if (Program.version === undefined) { 24 | console.log(pkg.version) 25 | process.exit(0) 26 | } 27 | 28 | if (!Program.args.length) { 29 | Program.outputHelp() 30 | process.exit(0) 31 | } 32 | 33 | const platform = Program.platform || 'quickapp' 34 | 35 | const options = { 36 | target: platform, 37 | sign: !!Program.sign, 38 | stat: !!Program.stat 39 | } 40 | 41 | if (Program.args.length >= 2) { 42 | migrate(path.resolve(Program.args[0]), path.resolve(Program.args[1]), options) 43 | } else { 44 | migrate(path.resolve(), path.resolve(Program.args[0]), options) 45 | } -------------------------------------------------------------------------------- /test/weapp/wx/device/index.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const expect = chai.expect 3 | 4 | require('../util') 5 | 6 | /** 7 | * 模拟快应用storage接口 8 | */ 9 | const data = {} //临时存储 10 | 11 | const errCode = 404 12 | 13 | polyfill(__dirname, { 14 | getInfo({ 15 | data, 16 | success, 17 | fail, 18 | complete 19 | }) { 20 | if (data === 'fail') { 21 | fail('获取失败', errCode) 22 | } else { 23 | success({brand:'OPPO',model:'oppo r9s',pixelRatio:2,platformVersionName:'andriod'}) 24 | complete({brand:'OPPO',model:'oppo r9s',pixelRatio:2,platformVersionName:'andriod'}) 25 | } 26 | } 27 | }) 28 | 29 | describe('api.device', () => { 30 | it('wx.getSystemInfo', () => { 31 | wx.getSystemInfo({ 32 | success: function (data) { 33 | expect(data.platform).eql('andriod') 34 | }, 35 | complete: function (data) { 36 | expect(data.platform).eql('andriod') 37 | } 38 | }) 39 | wx.getSystemInfo({ 40 | data: 'fail', 41 | fail: function (data, code) { 42 | expect(code).eql(errCode) 43 | } 44 | }) 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /src/weapp/transform/helper/style/declaration/background/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'background': (value, declaration, addDeclaration) => { 3 | // TODO 只做了简单转换,把线性转了,把第一个值转成了color,image,还有很多属性没转 4 | if (~value.indexOf('linear-gradient')) { // 线性 5 | // 按照指定方向渐变时,必须有to在direction前。 6 | var DIR_REG = /linear\-gradient\((top|right|bottom|left)/ 7 | var ret = value.match(DIR_REG) 8 | if (ret) { 9 | declaration.value = value.replace(DIR_REG, 'linear-gradient(to ' + ret[1]) 10 | } 11 | return '' 12 | } 13 | const values = value.split(' ') 14 | if (~values[0].indexOf('url')) { 15 | addDeclaration('background-image', value) 16 | } else { 17 | // TODO 颜色值为transparent时忽略 18 | if (!~value.indexOf('transparent')) { 19 | addDeclaration('background-color', value) 20 | } 21 | } 22 | return 'I:' 23 | }, 24 | 'background-color': (value, declaration, addDeclaration) => { 25 | if (~value.indexOf('transparent')) { 26 | return 'I:' 27 | } 28 | }, 29 | 'background-image': '', 30 | 'background-size': '', 31 | 'background-repeat': 'I:', 32 | 'background-attachment': 'I:', 33 | 'background-position': 'I:', 34 | 'background-origin': 'I:', 35 | 'background-clip': 'I:' 36 | } 37 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/media/video/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag.video', () => { 4 | 5 | it('rewrite `video`', () => { 6 | const fixture = ` 7 | 12 | ` 13 | 14 | const expected = `` 15 | 16 | rewriter.assertTemplateString(fixture, expected) 17 | }) 18 | 19 | }) -------------------------------------------------------------------------------- /src/weapp/transform/helper/style/declaration/flexbox/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'flex': (value, declaration, addDeclaration) => { 3 | const props = ['grow', 'shrink', 'basis'] 4 | if (value.match(/\s+/g)) { 5 | const values = value.split(' ') 6 | values.forEach((item, index) => { 7 | // flex-basis的值不支持设置为auto,且只支持具体的数值,差异过大暂时忽略。 8 | if (props[index] !== 'basis') { 9 | addDeclaration('flex-' + props[index], item) 10 | } 11 | }) 12 | return 'I:' 13 | } else if (value === 'auto') { 14 | return 'I:' 15 | } else { 16 | return '' 17 | } 18 | }, 19 | 'flex-grow': '', 20 | 'flex-shrink': '', 21 | 'flex-basis': 'I:', 22 | 'flex-direction': (value, declaration, addDeclaration) => { 23 | if (~value.indexOf('row-reverse')) { 24 | return 'I:' 25 | } 26 | }, 27 | 'flex-wrap': '', 28 | 'justify-content': (value, declaration, addDeclaration) => { 29 | const content = ['flex-start', 'flex-end', 'center', 'space-between'] 30 | if (value === 'space-around') { 31 | declaration.value = 'space-between' 32 | return '' 33 | } 34 | if (~content.indexOf(value)) { // justify-content:space-around 35 | return '' 36 | } 37 | return 'I:' 38 | }, 39 | 'align-items': '', 40 | 'align-content': '' 41 | } 42 | -------------------------------------------------------------------------------- /test/weapp/wx/record/index.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const expect = chai.expect 3 | 4 | require('../util') 5 | 6 | /** 7 | * 模拟快应用storage接口 8 | */ 9 | const data = {} //临时存储 10 | 11 | const errCode = 404 12 | 13 | polyfill(__dirname, { 14 | startRecord({ 15 | text, 16 | success, 17 | fail, 18 | complete 19 | }) { 20 | if (text === 'fail') { 21 | fail('录音失败', errCode) 22 | } else { 23 | success({path:'/sdcard/record/test'}) 24 | complete({path:'/sdcard/record/test'}) 25 | } 26 | }, 27 | stopRecord({ 28 | 29 | }) { 30 | 31 | } 32 | }) 33 | 34 | describe('api.record', () => { 35 | 36 | it('wx.startRecord', () => { 37 | wx.startRecord({ 38 | success: function (res) { 39 | expect(res.tempFilePath).eql('/sdcard/record/test') 40 | }, 41 | complete: function (res) { 42 | expect(res.tempFilePath).eql('/sdcard/record/test') 43 | } 44 | }) 45 | wx.startRecord({ 46 | text: 'fail', 47 | fail: function (data, code) { 48 | expect(code).eql(errCode) 49 | } 50 | }) 51 | }) 52 | 53 | it('wx.stopRecord', () => { 54 | wx.stopRecord() 55 | }) 56 | 57 | }) 58 | -------------------------------------------------------------------------------- /src/weapp/platform/polyfill/storage.js: -------------------------------------------------------------------------------- 1 | /*eslint-disable camelcase,no-undef*/ 2 | const storage = $app_require$('@app-module/system.storage') 3 | 4 | export async function getStorageSync (key) { 5 | return new Promise((resolve, reject) => { 6 | storage.get({ 7 | key, 8 | success (data) { 9 | resolve(data) 10 | }, 11 | fail (data, code) { 12 | reject(data) 13 | } 14 | }) 15 | }) 16 | } 17 | export async function setStorageSync (key, value) { 18 | return new Promise((resolve, reject) => { 19 | storage.set({ 20 | key, 21 | value, 22 | success (data) { 23 | resolve(data) 24 | }, 25 | fail (data, code) { 26 | reject(data) 27 | } 28 | }) 29 | }) 30 | } 31 | export async function removeStorageSync (key) { 32 | return new Promise((resolve, reject) => { 33 | storage.delete({ 34 | key, 35 | success (data) { 36 | resolve(data) 37 | }, 38 | fail (data, code) { 39 | reject(data) 40 | } 41 | }) 42 | }) 43 | } 44 | export async function clearStorageSync () { 45 | return new Promise((resolve, reject) => { 46 | storage.clear({ 47 | success (data) { 48 | resolve(data) 49 | }, 50 | fail (data, code) { 51 | reject(data) 52 | } 53 | }) 54 | }) 55 | } 56 | -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | 3 | export const isWin = /^win/.test(process.platform) 4 | 5 | export const isExpr = v => /\{\{(.+?)\}\}/g.test(v) 6 | 7 | export const normalizePath = path => path && isWin && path.replace(/\\/g, '/') || path 8 | 9 | export const relativePath = (from, to) => { 10 | const ret = path.relative(from, to) 11 | return ret.indexOf('.') === 0 ? ret : ('./' + ret) 12 | } 13 | 14 | export const resolvePath = (dirname, filePath, base) => { 15 | if (filePath.indexOf('/') === 0) { 16 | return path.join(base, filePath) 17 | } 18 | return path.join(dirname, filePath) 19 | } 20 | 21 | export const comment = (msg, url) => 'uniapp comment: ' + msg + '.' + (url ? '[兼容写法参考](' + url + ')' : '') 22 | 23 | export const getMatches = (str, regex) => { 24 | const matches = [] 25 | let match 26 | 27 | if (regex.global) { 28 | regex.lastIndex = 0 29 | } else { 30 | regex = new RegExp(regex.source, 'g' + 31 | (regex.ignoreCase ? 'i' : '') + 32 | (regex.multiline ? 'm' : '') + 33 | (regex.sticky ? 'y' : '')) 34 | } 35 | /*eslint-disable no-cond-assign*/ 36 | while (match = regex.exec(str)) { 37 | matches.push(match) 38 | if (regex.lastIndex === match.index) { 39 | regex.lastIndex++ 40 | } 41 | } 42 | return matches 43 | } 44 | 45 | export * from './log' 46 | 47 | export * from './type' 48 | -------------------------------------------------------------------------------- /test/weapp/wx/fetch/index.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const expect = chai.expect 3 | 4 | require('../util') 5 | 6 | /** 7 | * 模拟快应用fetch接口 8 | */ 9 | const errCode = 404; 10 | polyfill(__dirname, { 11 | fetch({ 12 | url, 13 | data, 14 | header, 15 | method, 16 | success, 17 | fail, 18 | complete 19 | }) { 20 | success({ 21 | code: 200, 22 | data: '{"name": "xiaoming"}', 23 | headers: { 24 | 'Content-Type': 'text/plain' 25 | } 26 | }) 27 | complete({ 28 | code: 200, 29 | data: 'hello', 30 | headers: { 31 | 'Content-Type': 'text/plain' 32 | } 33 | }) 34 | } 35 | }) 36 | 37 | describe('api.fetch', () => { 38 | 39 | it('wx.request', () => { 40 | wx.request({ 41 | url: 'http://www.test.com/fetch', 42 | data: 'test', 43 | header: { 44 | 'Content-Type': 'text/plain' 45 | }, 46 | method: 'GET', 47 | success: data => { 48 | expect(data.data.name).eql('xiaoming') 49 | expect(data.statusCode).eql(200) 50 | expect(data.header['Content-Type']).eql('text/plain') 51 | }, 52 | complete: data => { 53 | expect(data.data).eql('hello') 54 | expect(data.statusCode).eql(200) 55 | expect(data.header['Content-Type']).eql('text/plain') 56 | } 57 | }) 58 | }) 59 | 60 | }) -------------------------------------------------------------------------------- /src/weapp/babel/quickapp/index.js: -------------------------------------------------------------------------------- 1 | const createArgsCallExpression = (t, arg, { 2 | state, 3 | wxMethod 4 | }) => { 5 | const objectExpression = t.objectExpression([ 6 | t.objectProperty(t.identifier('page'), t.stringLiteral(state.opts.page || '')), 7 | t.objectProperty(t.identifier('method'), t.stringLiteral(wxMethod)) 8 | ]) 9 | return t.callExpression(t.identifier('_$$parseArgs$$_'), [arg, objectExpression]) 10 | } 11 | 12 | export default function (t, args, { 13 | type, 14 | state, 15 | module, 16 | method, 17 | wxMethod 18 | }) { 19 | let callee 20 | if (type === 'custom') { 21 | callee = t.memberExpression(t.identifier('_$$' + module + '$$_'), t.identifier(wxMethod)) 22 | } else { 23 | if (~wxMethod.indexOf('Sync')) { 24 | callee = t.memberExpression(t.identifier('_$$' + module + '$$_'), t.identifier(wxMethod)) 25 | } else { 26 | const identifier = `_$${module}$_` 27 | if (!state.imports) { 28 | state.imports = {} 29 | } 30 | state.imports[identifier] = '@system.' + module 31 | 32 | callee = t.memberExpression(t.identifier(identifier), t.identifier(method)) 33 | } 34 | if (!~wxMethod.indexOf('Sync') && args && args.length === 1) { 35 | args = [createArgsCallExpression(t, args[0], { 36 | state, 37 | wxMethod 38 | })] 39 | } 40 | } 41 | return t.callExpression(callee, args) 42 | } 43 | -------------------------------------------------------------------------------- /test/weapp/wx/media/index.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const expect = chai.expect 3 | 4 | require('../util') 5 | 6 | /** 7 | * 模拟快应用media接口 8 | */ 9 | const errCode = 404; 10 | polyfill(__dirname, { 11 | pickImage({ 12 | success, 13 | fail, 14 | complete 15 | }) { 16 | success({ 17 | uri: '../images/test.jpg' 18 | }) 19 | complete({ 20 | uri: '../images/test.jpg' 21 | }) 22 | }, 23 | pickVideo({ 24 | success, 25 | fail, 26 | complete 27 | }) { 28 | success({ 29 | uri: '../videos/test.mp4' 30 | }) 31 | complete({ 32 | uri: '../videos/test.mp4' 33 | }) 34 | } 35 | }) 36 | 37 | describe('api.media', () => { 38 | 39 | it('wx.chooseImage', () => { 40 | wx.chooseImage({ 41 | success: data => { 42 | expect(data.tempFilePaths[0]).eql('../images/test.jpg') 43 | }, 44 | complete: data => { 45 | expect(data.tempFilePaths[0]).eql('../images/test.jpg') 46 | } 47 | }) 48 | }) 49 | 50 | it('wx.chooseVideo', () => { 51 | wx.chooseVideo({ 52 | success: data => { 53 | expect(data.tempFilePath).eql('../videos/test.mp4') 54 | // expect(data.errMsg).eql('chooseVideo:ok') 55 | }, 56 | complete: data => { 57 | expect(data.tempFilePath).eql('../videos/test.mp4') 58 | // expect(data.errMsg).eql('chooseVideo:ok') 59 | } 60 | }) 61 | }) 62 | 63 | }) -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/view/scroll-view/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../util') 2 | 3 | describe('template.tag[scroll-view]', () => { 4 | 5 | it('rewrite `scroll-view`', () => { 6 | const fixture = ` 7 | 10 | text1 11 | text2 12 | text3 13 | 14 | ` 15 | 16 | const expected = `
text1
text2
text3
` 17 | 18 | rewriter.assertTemplateString(fixture, expected) 19 | }) 20 | 21 | }) -------------------------------------------------------------------------------- /src/weapp/transform/helper/style/selector/index.js: -------------------------------------------------------------------------------- 1 | import cssWhat from 'css-what' 2 | const simpleSelectorRegex = /^[.#]?[A-Za-z0-9_\-:]+$/ 3 | const compoundSelectorRegex = /^([.#]?[A-Za-z0-9_-]+(\s+|\s*>\s*))+([.#]?[A-Za-z0-9_\-:]+)$/ 4 | export default function rewriter (selector, rule, output) { 5 | if (!(simpleSelectorRegex.test(selector) || compoundSelectorRegex.test(selector))) { 6 | output.logs.push({ 7 | reason: 'W:选择器`' + selector + '`不支持', 8 | line: rule.position.start.line, 9 | column: rule.position.start.column 10 | }) 11 | return false 12 | } 13 | if (~selector.indexOf(':before') || ~selector.indexOf(':after') || ~selector.indexOf(':last-child') || ~selector.indexOf(':first-child')) { 14 | output.logs.push({ 15 | reason: 'W:选择器`' + selector + '`不支持', 16 | line: rule.position.start.line, 17 | column: rule.position.start.column 18 | }) 19 | return false 20 | } 21 | selector = cssWhat(selector)[0].map(subselect => { 22 | if (subselect.type === 'tag') { 23 | return '.u-w-' + subselect.name 24 | } else if (subselect.type === 'descendant') { 25 | return ' ' 26 | } else if (subselect.type === 'attribute') { 27 | if (subselect.name === 'class') { 28 | return '.' + subselect.value 29 | } else if (subselect.name === 'id') { 30 | return '#' + subselect.value 31 | } 32 | } 33 | return '' 34 | }).join('') 35 | return selector 36 | } 37 | -------------------------------------------------------------------------------- /test/weapp/transform/helper/tag/form/radio/radio-group/index.test.js: -------------------------------------------------------------------------------- 1 | const rewriter = require('../../../../util') 2 | 3 | describe('template.tag.radio.radio-group', () => { 4 | 5 | it('rewrite `radio-group`', () => { 6 | const fixture = ` 7 | 8 | 14 | 20 | 21 | ` 22 | 23 | const expected = `
单选
单选
` 24 | 25 | rewriter.assertTemplateString(fixture, expected) 26 | }) 27 | 28 | }) -------------------------------------------------------------------------------- /test/weapp/wx/request/index.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const expect = chai.expect 3 | 4 | require('../util') 5 | 6 | /** 7 | * 模拟快应用request接口 8 | */ 9 | const errCode = 404; 10 | polyfill(__dirname, { 11 | upload({ 12 | url, 13 | header, 14 | method, 15 | files, 16 | success, 17 | fail, 18 | complete 19 | }) { 20 | success({ 21 | code: 200, 22 | data: 'hello' 23 | }) 24 | complete({ 25 | code: 200, 26 | data: 'hello' 27 | }) 28 | }, 29 | download({ 30 | url, 31 | header, 32 | success, 33 | fail, 34 | complete 35 | }) { 36 | success({ 37 | token: 'token123' 38 | }) 39 | complete({ 40 | token: 'token123' 41 | }) 42 | } 43 | }) 44 | 45 | describe('api.request', () => { 46 | 47 | it('wx.uploadFile', () => { 48 | wx.uploadFile({ 49 | url: 'http://www.test.com/upload', 50 | filePath: './files/file.txt', 51 | name: 'upload_file', 52 | header: {}, 53 | success: data => { 54 | expect(data.statusCode).eql(200) 55 | }, 56 | complete: data => { 57 | expect(data.statusCode).eql(200) 58 | } 59 | }) 60 | }) 61 | 62 | it('wx.downloadFile', () => { 63 | wx.downloadFile({ 64 | url: 'http://www.test.com/upload', 65 | header: {}, 66 | success: data => { 67 | expect(data.statusCode).eql('token123') 68 | }, 69 | complete: data => { 70 | expect(data.statusCode).eql('token123') 71 | } 72 | }) 73 | }) 74 | 75 | }) -------------------------------------------------------------------------------- /src/weapp/transform/page-rewriter/style-rewriter/index.js: -------------------------------------------------------------------------------- 1 | import css from 'css' 2 | 3 | import rewriteRule from '../../helper/style' 4 | 5 | export default function rewriter (code, options) { 6 | const logs = [] 7 | const deps = [] 8 | const ast = css.parse(code, { 9 | silent: true 10 | }) 11 | // catch syntax error 12 | if (ast.stylesheet.parsingErrors && ast.stylesheet.parsingErrors.length) { 13 | ast.stylesheet.parsingErrors.forEach(function (error) { 14 | logs.push({ 15 | line: error.line, 16 | column: error.column, 17 | reason: error.toString().replace('Error', 'ERROR') 18 | }) 19 | }) 20 | } 21 | 22 | if (ast && ast.type === 'stylesheet' && ast.stylesheet && 23 | ast.stylesheet.rules && ast.stylesheet.rules.length) { 24 | const rules = [] 25 | ast.stylesheet.rules.forEach(function (rule, index) { 26 | const type = rule.type 27 | if (type === 'import' && rule.import) { 28 | rule.import = rule.import.replace('.wxss', options.ext.wxss) 29 | deps.push(rule.import.replace(/['|"]/g, '')) 30 | rules.push(rule) 31 | } 32 | if (type === 'rule') { 33 | const newRule = rewriteRule(rule, { 34 | logs: logs 35 | }) 36 | if (newRule) { 37 | rules.push(newRule) 38 | } 39 | } else if (type === 'keyframes') { 40 | rules.push(rule) 41 | } 42 | }) 43 | ast.stylesheet.rules = rules 44 | } 45 | return { 46 | result: ast, 47 | logs: logs, 48 | deps: deps 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/weapp/platform/router.js: -------------------------------------------------------------------------------- 1 | const decodeRegexp = /\+/g 2 | const paramRegexp = /([^&=]+)=?([^&]*)/g 3 | const parseParams = function (queryString) { 4 | const params = {} 5 | if (queryString) { 6 | const queryStrings = queryString.split('?') 7 | if (queryStrings.length === 2) { 8 | queryString = queryStrings[1] 9 | } 10 | } 11 | if (queryString) { 12 | let e 13 | /*eslint-disable no-cond-assign*/ 14 | while (e = paramRegexp.exec(queryString)) { 15 | params[decode(e[1])] = decode(e[2]) 16 | } 17 | } 18 | return params 19 | } 20 | const decode = function (str) { 21 | return decodeURIComponent(str.replace(decodeRegexp, ' ')) 22 | } 23 | const absolute = (base, relative) => { 24 | if (relative.indexOf('/') === 0) { 25 | base = '' 26 | relative = relative.substr(1) 27 | } 28 | const stack = base.split('/') 29 | const parts = relative.split('/') 30 | stack.pop() 31 | for (let i = 0; i < parts.length; i++) { 32 | if (parts[i] === '.') { 33 | continue 34 | } 35 | if (parts[i] === '..') { 36 | stack.pop() 37 | } else { 38 | stack.push(parts[i]) 39 | } 40 | } 41 | stack.pop() 42 | return stack.join('/') 43 | } 44 | export default function parseRouter (url, base) { 45 | const parts = url.split('?') 46 | if (parts.length > 1) { 47 | return { 48 | uri: absolute(base || '', parts[0]), 49 | params: { 50 | pageQuery: parseParams(parts[1]) 51 | } 52 | } 53 | } else { 54 | return { 55 | uri: absolute(base || '', parts[0]), 56 | params: {} 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/weapp/transform/page-rewriter/import-rewriter/index.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import fs from 'fs-extra' 3 | import { pd as beautify } from 'pretty-data' 4 | 5 | import rewriteRoot from '../root' 6 | import serialize from '../serialize' 7 | import generateImportCode from '../import' 8 | 9 | import { 10 | relativePath, 11 | normalizePath 12 | } from '../../../../utils' 13 | 14 | export default function rewriter (pagePath, nodes, imports, styleCode, options) { 15 | if (!fs.existsSync(pagePath)) { 16 | const importTemplateCode = generateImportCode(imports, options) 17 | const templateCode = beautify.xml(rewriteRoot(serialize(nodes), true)) 18 | const folder = path.join(pagePath, '..') 19 | const files = ['polyfill' + options.ext.wxss, 'app' + options.ext.wxss] 20 | const importCode = files.map(file => { 21 | return `@import '${normalizePath(relativePath(folder, path.join(options.output, file)))}';` 22 | }).join('\r\n') 23 | 24 | return `${importTemplateCode} 25 | 28 | 32 | 51 | ` 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/weapp/transform/page-rewriter/parser.test.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const fs = require('fs-extra') 3 | const chai = require('chai') 4 | const expect = chai.expect 5 | 6 | const parse = require(__dirname.replace('test', 'lib') + '/parser').default 7 | 8 | describe('manifest', () => { 9 | it('template parser', () => { 10 | const template = ` 11 | 12 | 13 | 14 | 15 |