├── .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 |
8 |
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}${node.name || node.type}>`
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 = ``
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 |
26 | ${templateCode}
27 |
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 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | 点击按钮下载服务端示例图片
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | `
34 | const ret = parse(`${template}`)
35 | expect(ret.children.length).eql(3)
36 | expect(ret.children[2].children.length).eql(3)
37 | expect(ret.children[2].children[1].children.length).eql(2)
38 | expect(ret.children[2].children[1].children[1].children.length).eql(2)
39 | })
40 |
41 | it('template[import] parser', () => {
42 | const template = `
43 |
44 |
45 | {{text}}
46 |
47 | `
48 | const ret = parse(`${template}`)
49 | expect(ret.attributes.name).eql('item')
50 |
51 | })
52 |
53 | })
--------------------------------------------------------------------------------
/src/weapp/transform/helper/tag/form/button/button.css:
--------------------------------------------------------------------------------
1 | .u-w-button {
2 | font-size: 36px;
3 | color: #000000;
4 | background-color: #F8F8F8;
5 | border: 1px solid #CCCCCC;
6 | border-radius: 10px;
7 | height: 92px;
8 | padding-left: 28px;
9 | padding-right: 28px;
10 | }
11 |
12 | .u-w-button:disabled {
13 | opacity: 0.6;
14 | }
15 |
16 | .u-w-button-default {
17 | color: #000000;
18 | background-color: #F8F8F8;
19 | border: 1px solid #CCCCCC;
20 | }
21 |
22 | .u-w-button-default:disabled {
23 | background-color: #F7F7F7;
24 | }
25 |
26 | .u-w-button-default-plain {
27 | background-color: #FFFFFF;
28 | color: #353535;
29 | border: 1px solid #353535;
30 | }
31 |
32 | .u-w-button-primary {
33 | background-color: #1AAD19;
34 | color: #FFFFFF;
35 | border: 1px solid #1AAD19;
36 | }
37 |
38 | .u-w-button-primary-plain {
39 | background-color: #FFFFFF;
40 | color: #1AAD19;
41 | border: 1px solid #1AAD19;
42 | }
43 |
44 | .u-w-button-primary:disabled {
45 | background-color: #9ED99D;
46 | }
47 |
48 | .u-w-button-primary-plain:disabled {
49 | color: #000000;
50 | border: 1px solid #000000;
51 | }
52 |
53 | .u-w-button-warn {
54 | background-color: #E64340;
55 | color: #FFFFFF;
56 | border: 1px solid #E64340;
57 | }
58 |
59 | .u-w-button-warn-plain {
60 | background-color: #FFFFFF;
61 | color: #E64340;
62 | border: 1px solid #E64340;
63 | }
64 |
65 | .u-w-button-warn:disabled {
66 | background-color: #EC8B89;
67 | }
68 |
69 | .u-w-button-warn-plain:disabled {
70 | color: #000000;
71 | border: 1px solid #000000;
72 | }
73 |
74 | .u-w-button-mini {
75 | font-size: 26px;
76 | width: 120px;
77 | height: 60px;
78 | }
--------------------------------------------------------------------------------
/src/weapp/transform/helper/style/declaration/position/index.js:
--------------------------------------------------------------------------------
1 | import { getDeclarationValue } from '../../util'
2 |
3 | function setValue (value, declaration) {
4 | const valueList = ['inherit', 'auto']
5 | if (~valueList.indexOf(value)) {
6 | return 'I:'
7 | }
8 | if (~value.indexOf('%')) {
9 | value = 750 / 100 * parseInt(value) + 'px'
10 | declaration.value = value
11 | }
12 | return ''
13 | }
14 |
15 | export default {
16 | 'bottom': (value, declaration, addDeclaration) => {
17 | return setValue(value, declaration)
18 | },
19 | // 'display': '',
20 | 'display': (value, declaration, addDeclaration, rule) => {
21 | // TODO 暂时忽略掉不支持的情况
22 | if (!~['flex', 'none'].indexOf(value)) {
23 | return 'E:'
24 | }
25 | if (value === 'flex') { // 因全局设置了flex-direction:column,故,当display:flex且未指定direction,还原为默认值row
26 | if (!getDeclarationValue('flex-direction', rule)) {
27 | addDeclaration('flex-direction', 'row')
28 | }
29 | }
30 | },
31 | 'left': (value, declaration, addDeclaration) => {
32 | return setValue(value, declaration)
33 | },
34 | 'position': (value, declaration, addDeclaration) => {
35 | if (value === 'static') {
36 | declaration.value = 'none'
37 | } else if (value === 'absolute') {
38 | return 'E:'
39 | } else if (value !== 'fixed') {
40 | return 'I:'
41 | }
42 | },
43 | 'right': (value, declaration, addDeclaration) => {
44 | return setValue(value, declaration)
45 | },
46 | 'top': (value, declaration, addDeclaration) => {
47 | return setValue(value, declaration)
48 | },
49 | 'overflow': 'I:',
50 | 'vertical-align': 'I:',
51 | 'z-index': 'I:'
52 | }
53 |
--------------------------------------------------------------------------------
/src/utils/log.js:
--------------------------------------------------------------------------------
1 | import chalk from 'chalk'
2 |
3 | export const copy = (msg, loc, path) => console.log(chalk.green('COPY: ' + msg + (loc ? ('\t\n@' + loc.line + ':' + loc.column + ' in ' + path) : '')))
4 | export const info = (msg, loc, path) => console.log(chalk.green('INFO: ' + msg + (loc ? ('\t\n@' + loc.line + ':' + loc.column + ' in ' + path) : '')))
5 | export const warn = (msg, loc, path) => console.log(chalk.yellow.bold('WARN: ' + msg + (loc ? ('\t\n@' + loc.line + ':' + loc.column + ' in ' + path) : '')))
6 | export const ignore = (msg, loc, path) => console.log(chalk.yellow.bold('IGNORE: ' + msg + (loc ? ('\t\n@' + loc.line + ':' + loc.column + ' in ' + path) : '')))
7 | export const error = (msg, loc, path) => console.log(chalk.red.bold('ERROR: ' + msg + (loc ? ('\t\n@' + loc.line + ':' + loc.column + ' in ' + path) : '')))
8 |
9 | export const globalError = {
10 | flex: false,
11 | duplicate: false
12 | }
13 | export const logError = (logs, file) => {
14 | logs && logs.length && logs.forEach(log => {
15 | if (log.reason.indexOf('I:') === 0) {
16 | // ignore(log.reason.replace('I:', ''), log, file)
17 | } else if (log.reason.indexOf('W:') === 0) {
18 | warn(log.reason.replace('W:', ''), log, file)
19 | } else if (log.reason.indexOf('E:') === 0) {
20 | if (~log.reason.indexOf('`display:') || ~log.reason.indexOf('`position:') || ~log.reason.indexOf('`float:')) {
21 | globalError.flex = true // TODO 临时记录到全局最后提示
22 | } else {
23 | error(log.reason.replace('E:', ''), log, file)
24 | }
25 | } else {
26 | console.log(log.reason + '\t\n@' + log.line + ':' + log.column + ' in ' + file)
27 | }
28 | })
29 | return false // TODO ERROR时暂不影响整体编译
30 | }
31 |
--------------------------------------------------------------------------------
/test/weapp/babel/uniapp/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.uniapp', () => {
11 |
12 | it('transform `Page`', () => {
13 | const fixture = `Page({
14 | onReady () {
15 | const value = wx.getStorageSync('key')
16 | console.log(value)
17 | },
18 | onShow(){
19 | wx.request({
20 | url: 'test.php' //仅为示例,并非真实的接口地址
21 | })
22 | wx['request']({
23 | url: 'test.php' //仅为示例,并非真实的接口地址
24 | })
25 | }
26 | })`
27 |
28 | const expected = `Page({
29 | async onReady() {
30 | const value = await uni.getStorageSync('key');
31 | console.log(value);
32 | },
33 | onShow() {
34 | uni.fetch.fetch(uni.parseArgs({
35 | url: 'test.php' //仅为示例,并非真实的接口地址
36 | }, {
37 | page: 'pages/page',
38 | method: 'request'
39 | }));
40 | uni.fetch.fetch(uni.parseArgs({
41 | url: 'test.php' //仅为示例,并非真实的接口地址
42 | }, {
43 | page: 'pages/page',
44 | method: 'request'
45 | }));
46 | }
47 | }, {
48 | path: 'pages/page',
49 | module: module,
50 | exports: exports,
51 | $app_require$: $app_require$,
52 | wxs: typeof _$wxs$_ === 'undefined' ? {} : _$wxs$_
53 | });`
54 | const ret = babel.transform(fixture, {
55 | plugins: [
56 | [plugins, {
57 | page: 'pages/page',
58 | target: 'uniapp'
59 | }]
60 | ]
61 | })
62 | expect(ret.code).eql(expected)
63 |
64 | })
65 |
66 | })
--------------------------------------------------------------------------------
/src/weapp/platform/args.js:
--------------------------------------------------------------------------------
1 | import modules from './modules'
2 | import parseRouter from './router'
3 | import { getCurrentPage } from './App'
4 | import { isFn, isPlainObject } from '../../utils/type'
5 |
6 | const createCallback = (callback, processReturnValue, methodName) => ret => callback(processData(ret, processReturnValue, methodName))
7 |
8 | const processData = (data, processReturnValue, methodName) => {
9 | data = processReturnValue(data)
10 | if (isPlainObject(data) && !data.errMsg) {
11 | data.errMsg = `${methodName}:ok`
12 | }
13 | return data
14 | }
15 |
16 | export default function parseArgs (args, options) {
17 | const methodDef = modules[options.method]
18 | if (methodDef) {
19 | if (!isFn(methodDef.returnValue)) {
20 | methodDef.returnValue = data => data
21 | }
22 | if (isFn(args.success)) {
23 | args.success = createCallback(args.success, methodDef.returnValue, options.method)
24 | }
25 | if (isFn(args.complete)) {
26 | args.complete = createCallback(args.complete, methodDef.returnValue, options.method)
27 | }
28 |
29 | if (isFn(methodDef.args)) {
30 | Object.assign(args, methodDef.args(args, options))
31 | if (isFn(args.callback)) {
32 | args.callback = createCallback(args.callback, methodDef.returnValue, options.method)
33 | }
34 | }
35 | }
36 | if (~['navigateTo', 'redirectTo', 'switchTab'].indexOf(options.method) && args.uri) {
37 | if (options.method === 'switchTab') {
38 | args.uri = parseRouter(args.uri).uri
39 | } else {
40 | const curPage = getCurrentPage()
41 | if (curPage && curPage._$path$_) {
42 | args = Object.assign(args, parseRouter(args.uri, curPage._$path$_))
43 | }
44 | }
45 | }
46 | return args
47 | }
48 |
--------------------------------------------------------------------------------
/src/weapp/transform/helper/style/index.js:
--------------------------------------------------------------------------------
1 | import css from 'css'
2 |
3 | import rewriteSelector from './selector'
4 | import rewriteDeclaration from './declaration'
5 |
6 | import {
7 | addComment,
8 | addDeclaration,
9 | removeDeclaration
10 | } from './util'
11 |
12 | import {
13 | comment
14 | } from '../../../../utils'
15 |
16 | export default function rewriter (rule, output) {
17 | output.declaration = {
18 | deleted: [],
19 | inserted: []
20 | }
21 | const selectors = rule.selectors.map(selector => rewriteSelector(selector, rule, output)).filter(v => !!v)
22 |
23 | if (!selectors.length) {
24 | let commentCssCode = ''
25 | try {
26 | commentCssCode = css.stringify({
27 | stylesheet: {
28 | rules: [rule]
29 | }
30 | })
31 | } catch (e) {
32 | output.logs.push({
33 | reason: 'E:wxss转换失败',
34 | line: rule.position.start.line,
35 | column: rule.position.start.column
36 | })
37 | }
38 | return {
39 | type: 'comment',
40 | comment: `
41 | ${comment('unsupported selector', 'http://ask.dcloud.net.cn/article/13170')}
42 | ${commentCssCode}
43 | `
44 | }
45 | }
46 | rule.selectors = selectors
47 | rule.declarations.forEach(declaration => declaration.type === 'declaration' && rewriteDeclaration(declaration, rule, output))
48 | // delete
49 | output.declaration.deleted.forEach(declaration => removeDeclaration(declaration, rule))
50 | // insert declaration
51 | output.declaration.inserted.forEach(declaration => addDeclaration(declaration.property, declaration.value, rule))
52 | // insert comment(by delete)
53 | output.declaration.deleted.forEach(declaration => addComment(declaration.property, declaration.value, rule))
54 | return rule
55 | }
56 |
--------------------------------------------------------------------------------
/test/weapp/babel/quickapp/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.quickapp', () => {
11 |
12 | it('transform `Page`', () => {
13 | const fixture = `Page({
14 | onReady () {
15 | const value = wx.getStorageSync('key')
16 | console.log(value)
17 | },
18 | onShow(){
19 | wx.request({
20 | url: 'test.php' //仅为示例,并非真实的接口地址
21 | })
22 | wx['request']({
23 | url: 'test.php' //仅为示例,并非真实的接口地址
24 | })
25 | }
26 | })`
27 |
28 | const expected = `import _$fetch$_ from '@system.fetch';
29 | Page({
30 | async onReady() {
31 | const value = await _$$polyfill$$_.getStorageSync('key');
32 | console.log(value);
33 | },
34 | onShow() {
35 | _$fetch$_.fetch(_$$parseArgs$$_({
36 | url: 'test.php' //仅为示例,并非真实的接口地址
37 | }, {
38 | page: 'pages/page',
39 | method: 'request'
40 | }));
41 | _$fetch$_.fetch(_$$parseArgs$$_({
42 | url: 'test.php' //仅为示例,并非真实的接口地址
43 | }, {
44 | page: 'pages/page',
45 | method: 'request'
46 | }));
47 | }
48 | }, {
49 | path: 'pages/page',
50 | module: module,
51 | exports: exports,
52 | $app_require$: $app_require$,
53 | wxs: typeof _$wxs$_ === 'undefined' ? {} : _$wxs$_
54 | });`
55 |
56 | const ret = babel.transform(fixture, {
57 | plugins: [
58 | [plugins, {
59 | page: 'pages/page',
60 | target: 'quickapp'
61 | }]
62 | ]
63 | })
64 | expect(ret.code).eql(expected)
65 |
66 | })
67 |
68 | })
--------------------------------------------------------------------------------
/src/weapp/platform/Behavior.js:
--------------------------------------------------------------------------------
1 | import { isPlainObject } from '../../utils/type'
2 |
3 | const ASSET_TYPES = ['properties', 'data', 'methods', 'relations']
4 |
5 | const LIFECYCLE_HOOKS = ['created', 'attached', 'ready', 'moved', 'detached']
6 |
7 | const mergeData = (to, from) => {
8 | if (!from) return to
9 | Object.keys(from).forEach(key => {
10 | const toVal = to[key]
11 | const fromVal = from[key]
12 | if (isPlainObject(toVal) && isPlainObject(fromVal)) {
13 | mergeData(toVal, fromVal)
14 | } else {
15 | to[key] = fromVal
16 | }
17 | })
18 | return to
19 | }
20 |
21 | const mergeHook = (parentVal, childVal) => childVal ? (parentVal ? parentVal.concat(childVal) : (Array.isArray(childVal) ? childVal : [childVal])) : parentVal
22 |
23 | const mergeBehavior = (parent, child) => {
24 | const behavior = {}
25 |
26 | const mergeProp = prop => {
27 | if (~LIFECYCLE_HOOKS.indexOf(prop)) {
28 | behavior[prop] = mergeHook(parent[prop], child[prop])
29 | } else if (~ASSET_TYPES.indexOf(prop)) {
30 | behavior[prop] = mergeData(parent[prop] || {}, child[prop])
31 | } else {
32 | behavior[prop] = child[prop] === undefined ? parent[prop] : child[prop]
33 | }
34 | }
35 |
36 | Object.keys(parent).forEach(prop => mergeProp(prop))
37 |
38 | Object.keys(child).forEach(prop => !parent.hasOwnProperty(prop) && mergeProp(prop))
39 |
40 | return behavior
41 | }
42 |
43 | export default function Behavior (options) {
44 | let behaviors = options.behaviors
45 |
46 | if (!behaviors) {
47 | behaviors = []
48 | }
49 |
50 | let ret = {}
51 |
52 | behaviors = behaviors.filter(behavior => isPlainObject(behavior))
53 | behaviors.forEach(behavior => {
54 | ret = mergeBehavior(ret, behavior)
55 | })
56 |
57 | return mergeBehavior(ret, options)
58 | }
59 |
--------------------------------------------------------------------------------
/src/weapp/transform/resource-rewriter/index.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import fs from 'fs-extra'
3 |
4 | import rewriteScript from '../page-rewriter/script-rewriter'
5 |
6 | import { logError, normalizePath } from '../../../utils'
7 |
8 | const ext = ['.wxml', '.wxss']
9 | export default function rewriter (input, out, ignoreFiles, dir, options) {
10 | dir = dir || '.'
11 | const dirPath = path.join(input, dir)
12 | fs.readdirSync(dirPath).forEach(file => {
13 | const filePath = path.join(dirPath, file)
14 | const relativePath = normalizePath(path.join(dir, file))
15 | if (fs.statSync(filePath).isFile()) {
16 | if (!~ignoreFiles.indexOf(relativePath) && !~ext.indexOf(path.extname(filePath))) {
17 | if (path.extname(filePath) === '.wxs') {
18 | file = file.replace('.wxs', options.ext.wxs)
19 | }
20 | // js,njs
21 | if (~['.js', '.njs'].indexOf(path.extname(file))) {
22 | const scriptRet = rewriteScript(fs.readFileSync(filePath, 'utf-8'), '', options)
23 | logError(scriptRet.logs, filePath)
24 | if (scriptRet.result) {
25 | fs.outputFileSync(path.join(out, dir, file), scriptRet.result, {
26 | override: true
27 | })
28 | } else {
29 | logError([{
30 | reason: 'E:js转换失败',
31 | line: 1,
32 | column: 1
33 | }], filePath)
34 | }
35 | } else {
36 | fs.copySync(filePath, path.join(out, dir, file))
37 | }
38 | }
39 | } else {
40 | rewriter(input, out, ignoreFiles, relativePath, options)
41 | }
42 | })
43 |
44 | options.stat && fs.copySync(path.join(__dirname, '../../../dcloud_stat'), out)
45 | options.sign && fs.copySync(path.join(__dirname, '../../../sign'), path.join(out, 'sign'))
46 | }
47 |
--------------------------------------------------------------------------------
/src/weapp/transform/page-rewriter/serialize.js:
--------------------------------------------------------------------------------
1 | import {
2 | comment
3 | } from '../../../utils'
4 |
5 | const names = ['checked', 'disabled']
6 |
7 | const createAttrsCode = attrs => {
8 | let attrsCode = ''
9 | const attrKeys = Object.keys(attrs)
10 | if (attrKeys.length) {
11 | attrsCode = ' ' + attrKeys.map(name => {
12 | if (!attrs[name] && ~names.indexOf(name)) {
13 | return `${name}="true"`
14 | }
15 | return name === 'else' ? `${name}` : `${name}="${attrs[name]}"`
16 | }).join(' ')
17 | }
18 | return attrsCode
19 | }
20 |
21 | const createNodeCode = (witchComment, name, children, content, attrsCode) => `<${name}${attrsCode}>${content || ''}${children.map(childNode => walk(childNode, witchComment)).join('')}${name}>`
22 |
23 | const createDeleteNodeCode = (name, attrsCode) => '<' + name + '>' + attrsCode
24 |
25 | const walk = (node, witchComment) => {
26 | const attrsCode = createAttrsCode(node.attributes)
27 |
28 | const nodeCode = createNodeCode(witchComment, node.name, node.children, node.content, attrsCode)
29 |
30 | if (witchComment && node.$delete) { // 不支持的节点,整个注释
31 | return ``
33 | }
34 |
35 | const deleteAttrsCode = createAttrsCode(node.$deleteAttrs || {})
36 |
37 | if (witchComment && deleteAttrsCode) {
38 | const deleteNodeCode = createDeleteNodeCode(node.$name, deleteAttrsCode)
39 | return `${nodeCode}`
40 | }
41 |
42 | return nodeCode
43 | }
44 |
45 | export default function serialize (nodes, witchComment = true) {
46 | if (!Array.isArray(nodes)) {
47 | nodes = [nodes]
48 | }
49 | return nodes.map(node => walk(node, witchComment)).join('\r\n')
50 | }
51 |
--------------------------------------------------------------------------------
/src/weapp/transform/helper/style/util.js:
--------------------------------------------------------------------------------
1 | import {
2 | comment
3 | } from '../../../../utils'
4 | /**
5 | * 在rule中删除指定declaration
6 | */
7 | export const removeDeclaration = (declaration, rule) => rule.declarations.splice(rule.declarations.findIndex(v => v.property === declaration.property && v.value === declaration.value), 1)
8 | /**
9 | * 在rule中增加一条declaration
10 | */
11 | export const addDeclaration = (property, value, rule) => rule.declarations.push({
12 | type: 'declaration',
13 | property,
14 | value
15 | })
16 | /**
17 | * 在rule中增加一条comment
18 | */
19 | export const addComment = (property, value, rule) => rule.declarations.push({
20 | type: 'comment',
21 | comment: `${property}:${value}; ${comment('unsupported style', 'http://ask.dcloud.net.cn/article/13170')}`
22 | })
23 |
24 | export const getDeclarationValue = (property, rule) => {
25 | const declarations = rule.declarations.filter(declaration => declaration.property === property)
26 | return declarations.length && declarations[0] || false
27 | }
28 |
29 | const defaultFontSize = 32
30 |
31 | const processDeclarationValueUnit = v => {
32 | v = v.replace('!important', '')
33 | const lowerCaseV = v.toLowerCase()
34 | if (~lowerCaseV.indexOf('rpx')) {
35 | return lowerCaseV.replace('rpx', 'px')
36 | } else if (~lowerCaseV.indexOf('px')) {
37 | const numberV = parseFloat(lowerCaseV)
38 | if (!isNaN(numberV)) {
39 | return numberV * 2 + 'px'
40 | }
41 | } else if (~lowerCaseV.indexOf('em')) {
42 | const numberV = parseFloat(lowerCaseV)
43 | if (!isNaN(numberV)) {
44 | return numberV * defaultFontSize + 'px'
45 | }
46 | }
47 | return v
48 | }
49 |
50 | export const processDeclarationValue = value => {
51 | if (typeof value === 'string') {
52 | return value.split(/\s+/).map(v => processDeclarationValueUnit(v)).join(' ')
53 | }
54 | return value
55 | }
56 |
--------------------------------------------------------------------------------
/test/weapp/transform/page-rewriter/template-rewriter/wxml/include.test.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const chai = require('chai')
3 | const expect = chai.expect
4 |
5 | const parse = require(__dirname.replace('test', 'lib') + '/include').default
6 |
7 | const fs = {
8 | existsSync(path) {
9 | return true
10 | },
11 | readFileSync(path) {
12 | if (~path.indexOf('view.wxml')) {
13 | return viewXml
14 | } else if (~path.indexOf('head.wxml')) {
15 | return headXml
16 | } else if (~path.indexOf('foot.wxml')) {
17 | return footXml
18 | }
19 | throw new Error('`' + path + '` 不存在')
20 | }
21 | }
22 |
23 | const viewXml = `
24 |
25 |
26 |
27 |
28 |
29 |
30 | {{index}}: {{msg}}
31 | Time: {{time}}
32 |
33 | `
34 |
35 | const headXml = `
36 |
37 |
38 | {{title}}
39 |
40 | {{desc}}
41 |
42 | `
43 | const footXml = `
44 |
47 | `
48 | describe('template.include', () => {
49 |
50 | it('parse `include`', () => {
51 | const pagePath = path.join(__dirname, '../../../../../demo/weapp/input/page/component/pages/view/view.wxml')
52 | const ret = parse(viewXml, pagePath, {}, fs)
53 | expect(ret.nodes.length).eql(2)
54 | expect(ret.nodes[0].attributes.class).eql('page-head')
55 | expect(ret.nodes[0].children[0].name).eql('navigator')
56 | expect(ret.nodes[1].children[0].name).eql('text')
57 | })
58 |
59 | })
--------------------------------------------------------------------------------
/test/weapp/wx/brightness/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 | setValue({
15 | text,//测试使用
16 | value,
17 | success,
18 | fail,
19 | complete
20 | }) {
21 | if (text === 'fail') {
22 | fail('设置失败', errCode)
23 | } else {
24 | success()
25 | complete()
26 | }
27 | },
28 | getValue({
29 | text,//测试使用
30 | success,
31 | fail,
32 | complete
33 | }) {
34 | if (text === 'fail') {
35 | fail('获取失败', errCode)
36 | } else {
37 | success({value:255})
38 | complete({value:255})
39 | }
40 | }
41 | })
42 |
43 | describe('api.brightness', () => {
44 |
45 | it('wx.setScreenBrightness', () => {
46 | wx.setScreenBrightness({
47 | value: 1,
48 | success: function (data) {
49 |
50 | },
51 | complete: function (data) {
52 |
53 | }
54 | })
55 | wx.setScreenBrightness({
56 | text: 'fail',
57 | fail: function (data, code) {
58 | expect(code).eql(errCode)
59 | }
60 | })
61 | })
62 |
63 | it('wx.getScreenBrightness', () => {
64 | wx.getScreenBrightness({
65 | success: function (res) {
66 | expect(res.value).eql('1')
67 | },
68 | complete: function (res) {
69 |
70 | }
71 | })
72 | wx.getScreenBrightness({
73 | text: 'fail',
74 | fail: function (data, code) {
75 | expect(code).eql(errCode)
76 | }
77 | })
78 | })
79 |
80 | })
81 |
--------------------------------------------------------------------------------
/src/weapp/platform/Component.js:
--------------------------------------------------------------------------------
1 | import Base from './Base'
2 | import Behavior from './Behavior'
3 | import { isFn } from '../../utils/type'
4 |
5 | const invokeHook = function (name) {
6 | if (Array.isArray(this[name])) {
7 | this[name].forEach(method => method.call(this))
8 | }
9 | }
10 |
11 | export default function Component (options, {
12 | wxs,
13 | path,
14 | module,
15 | exports,
16 | /*eslint-disable camelcase*/
17 | $app_require$
18 | }) {
19 | options = Behavior(options)
20 |
21 | Base(options, {
22 | wxs,
23 | type: 'Component',
24 | path,
25 | module,
26 | exports,
27 | $app_require$
28 | })
29 |
30 | options.props = []
31 | if (options.properties) {
32 | Object.keys(options.properties).forEach(name => options.props.push(name))
33 | delete options.properties
34 | }
35 |
36 | if (options.methods) {
37 | Object.keys(options.methods).forEach(method => {
38 | options[method] = options.methods[method]
39 | })
40 | delete options.methods
41 | }
42 |
43 | const onReady = options.onReady
44 | options.onReady = function () {
45 | isFn(onReady) && onReady.call(this)
46 | invokeHook.call(this, 'created')
47 | invokeHook.call(this, 'attached')
48 | invokeHook.call(this, 'ready')
49 | }
50 |
51 | const onDestroy = options.onDestroy
52 | options.onDestroy = function () {
53 | isFn(onDestroy) && onDestroy.call(this)
54 | invokeHook.call(this, 'detached')
55 | }
56 |
57 | options.hasBehavior = function (behavior) {
58 | // TODO
59 | }
60 |
61 | options.triggerEvent = function (type, detail, {
62 | bubbles = false,
63 | composed = false,
64 | capturePhase = false
65 | } = {}) {
66 | this.$dispatch(type, detail)
67 | }
68 |
69 | if (exports.default) {
70 | exports.default = options
71 | } else if (module.exports) {
72 | module.exports = options
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/weapp/wx/prompt/index.js:
--------------------------------------------------------------------------------
1 | export default {
2 | // 暂不支持wx.showLoading(),wx.hideLoading(),wx.hideToast();
3 | showToast: { // 无icon,image,mask等参数
4 | name: 'showToast',
5 | args (params) {
6 | return {
7 | message: params.title,
8 | duration: params.duration > 2000 ? 1 : 0
9 | }
10 | }
11 | },
12 | showModal: {
13 | name: 'showDialog',
14 | args (params) {
15 | const result = {
16 | title: params.title,
17 | message: params.content,
18 | buttons: [{
19 | text: '确定',
20 | color: ''
21 | }, {
22 | text: '取消',
23 | color: ''
24 | }]
25 | }
26 | if (!params.title) {
27 | delete result.title
28 | }
29 | if (!params.content) {
30 | delete params.content
31 | }
32 | if (!params.showCancel && typeof params.showCancel === 'boolean') {
33 | result.buttons.pop()
34 | }
35 | if (result.buttons[1] && params.cancelText) {
36 | result.buttons[1].text = params.cancelText
37 | }
38 | if (result.buttons[1] && params.cancelColor) {
39 | result.buttons[1].color = params.cancelColor
40 | }
41 | if (params.confirmText) {
42 | result.buttons[0].text = params.confirmText
43 | }
44 | if (params.confirmColor) {
45 | result.buttons[0].color = params.confirmColor
46 | }
47 | return result
48 | },
49 | returnValue (data) {
50 | if (data.index === 0) {
51 | return {
52 | confirm: true,
53 | cancel: false
54 | }
55 | } else {
56 | return {
57 | confirm: false,
58 | cancel: true
59 | }
60 | }
61 | }
62 | },
63 | showActionSheet: {
64 | name: 'showContextMenu',
65 | returnValue (data) {
66 | return {
67 | tapIndex: data.index
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/weapp/transform/manifest-rewriter/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "package": "com.example.demo",
3 | "name": "应用名称",
4 | "icon": "logo.png",
5 | "versionName": "",
6 | "versionCode": 1,
7 | "minPlatformVersion": 1000,
8 | "features": [
9 | {
10 | "name": "system.share"
11 | }, {
12 | "name": "system.prompt"
13 | }, {
14 | "name": "system.webview"
15 | }, {
16 | "name": "system.notification"
17 | }, {
18 | "name": "system.vibrator"
19 | }, {
20 | "name": "system.request"
21 | }, {
22 | "name": "system.fetch"
23 | }, {
24 | "name": "system.storage"
25 | }, {
26 | "name": "system.file"
27 | }, {
28 | "name": "system.barcode"
29 | }, {
30 | "name": "system.sensor"
31 | }, {
32 | "name": "system.clipboard"
33 | }, {
34 | "name": "system.geolocation"
35 | }, {
36 | "name": "system.shortcut"
37 | }, {
38 | "name": "system.calendar"
39 | }, {
40 | "name": "system.network"
41 | }, {
42 | "name": "system.device"
43 | }, {
44 | "name": "system.media"
45 | }, {
46 | "name": "service.push"
47 | }, {
48 | "name": "service.pay"
49 | }, {
50 | "name": "service.wxpay",
51 | "params": {}
52 | }, {
53 | "name": "service.alipay"
54 | }, {
55 | "name": "service.share",
56 | "params": {}
57 | }
58 | ],
59 | "permissions": [
60 | {
61 | "origin": "*"
62 | }
63 | ],
64 | "config": {
65 | "logLevel": "log",
66 | "designWidth": 750,
67 | "data": {}
68 | },
69 | "router": {
70 | "entry": "",
71 | "pages": {}
72 | },
73 | "display": {
74 | "backgroundColor": "#ffffff",
75 | "fullScreen": false,
76 | "titleBar": true,
77 | "titleBarBackgroundColor": "",
78 | "titleBarTextColor": "",
79 | "titleBarText": "",
80 | "menu": false,
81 | "pages": {}
82 | }
83 | }
--------------------------------------------------------------------------------
/src/weapp/platform/App.js:
--------------------------------------------------------------------------------
1 | import { isFn } from '../../utils/type'
2 |
3 | const currentPages = []
4 |
5 | export const getCurrentPage = function () {
6 | return currentPages.length && currentPages[currentPages.length - 1]
7 | }
8 |
9 | export const getCurrentPages = function () {
10 | return currentPages
11 | }
12 |
13 | export const setCurrentPage = function (page) {
14 | const index = currentPages.indexOf(this)
15 | if (~index) { // 已存在则删除
16 | currentPages.splice(index, 1)
17 | }
18 | currentPages.push(page)
19 | }
20 |
21 | export const removeCurrentPage = function () {
22 | currentPages.pop()
23 | }
24 |
25 | const initGetApp = (app, extraData) => {
26 | Object.keys(extraData).forEach(prop => {
27 | app[prop] = extraData[prop]
28 | })
29 | return () => app
30 | }
31 |
32 | export default function App (options, {
33 | module,
34 | exports,
35 | /*eslint-disable camelcase*/
36 | $app_require$
37 | }) {
38 | // 将非function,非data的数据移动到data中
39 | const dataProps = []
40 | Object.keys(options).forEach(prop => {
41 | if (prop !== 'data' && prop !== 'manifest' && !isFn(options[prop])) {
42 | dataProps.push(prop)
43 | }
44 | })
45 | const extraData = {}
46 | dataProps.forEach(prop => {
47 | extraData[prop] = options[prop]
48 | delete options[prop]
49 | })
50 | options.onCreate = function () {
51 | (Object.getPrototypeOf(global) || global).getApp = initGetApp(this, extraData)
52 |
53 | const args = {
54 | path: '',
55 | scene: 1001,
56 | query: {}
57 | }
58 | isFn(this.onLaunch) && this.onLaunch(args)
59 | isFn(this.onShow) && this.onShow(args)
60 |
61 | /*eslint-disable camelcase,no-undef*/
62 | typeof dc_stat !== 'undefined' && (dc_stat.report())
63 | }
64 |
65 | options.getCurrentPages = getCurrentPages
66 |
67 | if (exports.default) {
68 | exports.default = options
69 | } else if (module.exports) {
70 | module.exports = options
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/test/weapp/wx/clipboard/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 | set({
15 | text,
16 | success,
17 | fail,
18 | complete
19 | }) {
20 | if (text === 'fail') {
21 | fail('剪切失败', errCode)
22 | } else {
23 | success(text)
24 | complete(text)
25 | }
26 | },
27 | get({
28 | data,
29 | success,
30 | fail,
31 | complete
32 | }) {
33 | if (data === 'fail') {
34 | fail('剪切失败', errCode)
35 | } else {
36 | success({
37 | text: 'value'
38 | })
39 | complete({
40 | text: 'value'
41 | })
42 | }
43 | }
44 | })
45 |
46 | describe('api.clipboard', () => {
47 |
48 | it('wx.setClipboardData', () => {
49 | wx.setClipboardData({
50 | data: 'value',
51 | success: function (data) {
52 | expect(data).eql('value')
53 | },
54 | complete: function (data) {
55 | expect(data).eql('value')
56 | }
57 | })
58 | wx.setClipboardData({
59 | data: 'fail',
60 | fail: function (data, code) {
61 | expect(code).eql(errCode)
62 | }
63 | })
64 | })
65 |
66 | it('wx.getClipboardData', () => {
67 | wx.getClipboardData({
68 | success: function (res) {
69 | expect(res.data).eql('value')
70 | },
71 | complete: function (res) {
72 | expect(res.data).eql('value')
73 | }
74 | })
75 | wx.getClipboardData({
76 | data: 'fail',
77 | fail: function (data, code) {
78 | expect(code).eql(errCode)
79 | }
80 | })
81 | })
82 |
83 | })
84 |
--------------------------------------------------------------------------------
/src/weapp/babel/wx.js:
--------------------------------------------------------------------------------
1 | export default {"scanCode":{"module":"barcode","method":"scan"},"setScreenBrightness":{"module":"brightness","method":"setValue"},"getScreenBrightness":{"module":"brightness","method":"getValue"},"setClipboardData":{"module":"clipboard","method":"set"},"getClipboardData":{"module":"clipboard","method":"get"},"getSystemInfo":{"module":"device","method":"getInfo"},"request":{"module":"fetch","method":"fetch"},"getSavedFileInfo":{"module":"file","method":"get"},"removeSavedFile":{"module":"file","method":"delete"},"getLocation":{"module":"geolocation","method":"getLocation"},"chooseImage":{"module":"media","method":"pickImage"},"chooseVideo":{"module":"media","method":"pickVideo"},"getNetworkType":{"module":"network","method":"getType"},"onNetworkStatusChange":{"module":"network","method":"subscribe"},"showToast":{"module":"prompt","method":"showToast"},"showModal":{"module":"prompt","method":"showDialog"},"showActionSheet":{"module":"prompt","method":"showContextMenu"},"uploadFile":{"module":"request","method":"upload"},"downloadFile":{"module":"request","method":"download"},"navigateTo":{"module":"router","method":"push"},"redirectTo":{"module":"router","method":"replace"},"navigateBack":{"module":"router","method":"back"},"switchTab":{"module":"router","method":"replace"},"onCompassChange":{"module":"sensor","method":"subscribeCompass"},"stopCompass":{"module":"sensor","method":"unsubscribeCompass"},"onAccelerometerChange":{"module":"sensor","method":"subscribeAccelerometer"},"stopAccelerometer":{"module":"sensor","method":"unsubscribeAccelerometer"},"setStorage":{"module":"storage","method":"set"},"setStorageSync":{"module":"storage","method":"set"},"getStorage":{"module":"storage","method":"get"},"getStorageSync":{"module":"storage","method":"get"},"removeStorage":{"module":"storage","method":"delete"},"removeStorageSync":{"module":"storage","method":"delete"},"clearStorage":{"module":"storage","method":"clear"},"clearStorageSync":{"module":"storage","method":"clear"},"vibrateLong":{"module":"vibrator","method":"vibrate"},"vibrateShort":{"module":"vibrator","method":"vibrate"}}
--------------------------------------------------------------------------------
/src/weapp/transform/helper/style/declaration/animation/index.js:
--------------------------------------------------------------------------------
1 | function setValue (index, value, addDeclaration) {
2 | const keyDate = ['animation-duration', 'animation-timing-function', 'animation-delay', 'animation-iteration-count']
3 | const valueData = {
4 | 'animation-duration': /^\d*\.?\d+(s|ms)$/,
5 | 'animation-timing-function': /^(linear|ease|ease-in|ease-out|ease-in-out)$/,
6 | 'animation-delay': /^\d*\.?\d+(s|ms)$/,
7 | 'animation-iteration-count': /^(infinite|\d+)$/
8 | }
9 | if (valueData[keyDate[index]].test(value)) {
10 | addDeclaration(keyDate[index], value)
11 | } else if (valueData[keyDate[1]].test(value)) {
12 | addDeclaration(keyDate[1], value)
13 | } else if (valueData[keyDate[3]].test(value)) {
14 | addDeclaration(keyDate[3], value)
15 | } else if (valueData[keyDate[0]].test(value)) {
16 | addDeclaration(keyDate[0], value)
17 | }
18 | }
19 |
20 | export default {
21 | 'animation': (value, declaration, addDeclaration) => {
22 | if (~value.indexOf('steps')) {
23 | value = value.replace(/steps.+end\)/, 'linear')
24 | // console.log("不支持steps()样式");
25 | }
26 | const list = value.split(/\s+/)
27 | addDeclaration('animation-name', list[0])
28 | for (let i = 1, len = list.length; i < len; i++) {
29 | setValue(i - 1, list[i], addDeclaration)
30 | }
31 | return 'I:'
32 | },
33 | 'animation-name': '',
34 | 'animation-duration': '',
35 | 'animation-timing-function': (value, declaration, addDeclaration) => {
36 | const cont = ['linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out']
37 | if (~cont.indexOf(value)) {
38 | return ''
39 | }
40 | return 'I:'
41 | },
42 | 'animation-delay': '',
43 | 'animation-iteration-count': (value, declaration, addDeclaration) => {
44 | if (value === 'infinite') {
45 | return 'I:'
46 | }
47 | return ''
48 | },
49 | 'animation-direction': 'I:',
50 | 'animation-fill-mode': (value, declaration, addDeclaration) => {
51 | const list = ['none', 'forwards']
52 | if (~list.indexOf(value)) {
53 | return ''
54 | }
55 | return 'I:'
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/weapp/transform/page-rewriter/template-rewriter/attr.js:
--------------------------------------------------------------------------------
1 | export default function rewriteAttr (name, attr, component, node, output, location) {
2 | const value = attr[name]
3 |
4 | let formatAttr = component.attr[name]
5 | if (typeof formatAttr === 'function') {
6 | formatAttr = formatAttr(value, attr)
7 | }
8 | if (formatAttr) {
9 | if (formatAttr.indexOf('STYLE:') === 0) {
10 | let styles = []
11 | if (attr.style) {
12 | styles = attr.style.split(';')
13 | }
14 | let styleAttrs = formatAttr.split('STYLE:')[1]
15 | if (!styleAttrs) {
16 | styleAttrs = name
17 | }
18 | styleAttrs.split(',').forEach(styleAttr => {
19 | if (~styleAttr.indexOf(':')) {
20 | const arr = styleAttr.split(':')
21 | styles.push(`${arr[0]}:${arr[1]}`)
22 | } else {
23 | styles.push(`${styleAttr}:${attr[name]}`)
24 | }
25 | })
26 | attr.style = styles.join(';')
27 | delete attr[name]
28 | } else if (formatAttr.indexOf('I:') === 0) {
29 | const msg = 'I: 组件`' + node.name + '`不支持`' + name + '`属性,自动忽略该配置'
30 | output.logs.push({
31 | reason: (formatAttr.length === 2 ? msg : (msg + ',' + formatAttr.replace('I:'))),
32 | line: location.line,
33 | column: location.column
34 | })
35 | delete attr[name]
36 | } else if (formatAttr.indexOf('W:') === 0) {
37 | const msg = 'W: 组件`' + node.name + '`不支持`' + name + '`属性'
38 | output.logs.push({
39 | reason: (formatAttr.length === 2 ? msg : (msg + ',' + formatAttr.replace('W:'))),
40 | line: location.line,
41 | column: location.column
42 | })
43 | } else if (formatAttr.indexOf('E:') === 0) {
44 | const msg = 'E: 组件`' + node.name + '`不支持`' + name + '`属性配置'
45 | output.logs.push({
46 | reason: (formatAttr.length === 2 ? msg : (msg + ',' + formatAttr.replace('E:'))),
47 | line: location.line,
48 | column: location.column
49 | })
50 | node.$deleteAttrs[name] = value
51 | delete attr[name]
52 | } else {
53 | delete attr[name]
54 | attr[formatAttr] = value
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/test/weapp/platform/test.js:
--------------------------------------------------------------------------------
1 | require('./util')
2 | const b1 = Behavior({
3 | properties: {
4 | myBehaviorProperty: {
5 | type: Number
6 | }
7 | },
8 | data: {
9 | myBehaviorData: {
10 | test: 2
11 | },
12 | myBehaviorData1: {
13 | test: 2
14 | }
15 | },
16 | attached: function () {
17 | console.log('b1 attached')
18 | },
19 | methods: {
20 | myBehaviorMethod: function () {}
21 | }
22 | })
23 | const b2 = Behavior({
24 | properties: {
25 | myBehaviorProperty: {
26 | type: String
27 | },
28 | myBehaviorProperty1: {
29 | type: Number
30 | }
31 | },
32 | data: {
33 | myBehaviorData: {
34 | test: 1
35 | }
36 | },
37 | created: function () {
38 | console.log('b2 created')
39 | },
40 | attached: function () {
41 | console.log('b2 attached')
42 | },
43 | methods: {
44 | myBehaviorMethod2: function () {}
45 | }
46 | })
47 | const c1 = Component({
48 | behaviors: [b1, b2],
49 | properties: {
50 | myProperty: { // 属性名
51 | type: String, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型)
52 | value: '', // 属性初始值(可选),如果未指定则会根据类型选择一个
53 | observer: function (newVal, oldVal) {} // 属性被改变时执行的函数(可选),也可以写成在methods段中定义的方法名字符串, 如:'_propertyChange'
54 | },
55 | myProperty2: String // 简化的定义方式
56 | },
57 | data: {}, // 私有数据,可用于模版渲染
58 |
59 | // 生命周期函数,可以为函数,或一个在methods段中定义的方法名
60 | attached: function () {
61 | console.log('c1 attached')
62 | },
63 | moved: function () {},
64 | detached: function () {
65 | console.log('c1 detached')
66 | },
67 |
68 | methods: {
69 | onMyButtonTap: function () {
70 | this.setData({
71 | // 更新属性和数据的方法与更新页面数据的方法类似
72 | })
73 | },
74 | _myPrivateMethod: function () {
75 | // 内部方法建议以下划线开头
76 | this.replaceDataOnPath(['A', 0, 'B'], 'myPrivateData') // 这里将 data.A[0].B 设为 'myPrivateData'
77 | this.applyDataUpdates()
78 | },
79 | _propertyChange: function (newVal, oldVal) {
80 |
81 | }
82 | }
83 | }, {
84 | path: 'page/common/component/test',
85 | module: module,
86 | exports: exports,
87 | $app_require$: {},
88 | wxs: typeof _$wxs$_ === 'undefined' ? {} : _$wxs$_
89 | })
90 | module.exports.onReady()
91 | module.exports.onDestroy()
92 |
--------------------------------------------------------------------------------
/test/weapp/wx/prompt/index.test.js:
--------------------------------------------------------------------------------
1 | const chai = require('chai')
2 | const expect = chai.expect
3 |
4 | require('../util')
5 |
6 | /**
7 | * 模拟快应用prompt接口
8 | */
9 |
10 | polyfill(__dirname, {
11 | showToast({
12 | message,
13 | duration
14 | }) {
15 | expect(message).eql('成功');
16 | expect(duration).eql(0);
17 | },
18 | showDialog({
19 | title,
20 | message,
21 | buttons,
22 | success,
23 | cancel,
24 | complete
25 | }) {
26 | if(title == "确定") {
27 | success({
28 | index: 0
29 | })
30 | }
31 | if(title == "取消") {
32 | success({
33 | index: 1
34 | })
35 | }
36 | },
37 | showContextMenu({
38 | itemList,
39 | itemColor,
40 | success,
41 | cancel,
42 | complete
43 | }) {
44 | success({
45 | index: 0
46 | })
47 | complete({
48 | index: 0
49 | })
50 | }
51 | })
52 |
53 | describe('api.prompt', () => {
54 | it("wx.showToast", () => {
55 | wx.showToast({
56 | title: '成功',
57 | icon: 'success',
58 | duration: 2000
59 | });
60 | })
61 |
62 | it("wx.showModal", () => {
63 | wx.showModal({
64 | title: '确定',
65 | content: '这是一个模态弹窗',
66 | success: function(res) {
67 | expect(res.confirm).eql(true)
68 | expect(res.cancel).eql(false)
69 | }
70 | });
71 | wx.showModal({
72 | title: "弹窗标题",
73 | content: "弹窗内容,告知当前状态、信息和解决方法,描述文字尽量控制在三行内",
74 | showCancel: false,
75 | confirmText: "确定"
76 | });
77 | wx.showModal({
78 | title: "取消",
79 | content: "弹窗内容,告知当前状态、信息和解决方法,描述文字尽量控制在三行内",
80 | showCancel: false,
81 | confirmText: "确定",
82 | success: function(res) {
83 | expect(res.confirm).eql(false)
84 | expect(res.cancel).eql(true)
85 | }
86 | });
87 | wx.showModal({
88 | content: "弹窗内容,告知当前状态、信息和解决方法,描述文字尽量控制在三行内",
89 | confirmText: "确定1",
90 | cancelText: "取消2",
91 | cancelColor: "#FFF000"
92 | })
93 | })
94 | it("wx.showActionSheet", () => {
95 | wx.showActionSheet({
96 | itemList: ['A', 'B', 'C'],
97 | success: function(res) {
98 | expect(res.tapIndex).eql(0)
99 | },
100 | complete: function(res) {
101 | expect(res.tapIndex).eql(0)
102 | },
103 | fail: function(res) {
104 | console.log(res)
105 | }
106 | })
107 | })
108 | })
--------------------------------------------------------------------------------
/src/weapp/transform/page-rewriter/tabs.js:
--------------------------------------------------------------------------------
1 | const rewriteTabbar = (itemOptions, tabBarOptions, selected) => {
2 | let iconCode = ''
3 | let textCode = ''
4 | let iconPath = itemOptions.iconPath
5 | let selectedIconPath = itemOptions.selectedIconPath
6 | if (iconPath && iconPath.indexOf('./') === 0) {
7 | iconPath = iconPath.substr(2)
8 | }
9 | if (selectedIconPath && selectedIconPath.indexOf('./') === 0) {
10 | selectedIconPath = selectedIconPath.substr(2)
11 | }
12 | if (selected) {
13 | if (selectedIconPath) {
14 | iconCode = ``
15 | }
16 | if (itemOptions.text) {
17 | textCode = `${itemOptions.text}`
18 | }
19 | } else {
20 | if (iconPath) {
21 | iconCode = ``
22 | }
23 | if (itemOptions.text) {
24 | textCode = `${itemOptions.text}`
25 | }
26 | }
27 | return `
28 | ${iconCode}
29 | ${textCode}
30 |
`
31 | }
32 | export default function rewriteTabs (code, tabBarOptions, pageIndex) {
33 | if (tabBarOptions.position === 'top') {
34 | return `
35 |
36 |
37 | ${tabBarOptions.list.map((itemOptions, index) => rewriteTabbar(itemOptions, tabBarOptions, index === pageIndex)).join('')}
38 |
39 |
40 | ${code}
41 |
`
42 | }
43 | return `
44 | ${code}
45 |
46 |
47 | ${tabBarOptions.list.map((itemOptions, index) => rewriteTabbar(itemOptions, tabBarOptions, index === pageIndex)).join('')}
48 |
49 |
50 |
`
51 | }
52 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uni-migration",
3 | "version": "0.0.2",
4 | "description": "uni-migration",
5 | "main": "index.js",
6 | "scripts": {
7 | "clear": "rm -rf lib/*",
8 | "copy": "cp ./src/weapp/transform/manifest-rewriter/manifest.json ./lib/weapp/transform/manifest-rewriter/ && cp -r ./tools/dcloud_stat/ ./lib/dcloud_stat/ && cp -r ./tools/sign/ ./lib/sign/",
9 | "test": "mocha ./test/**/*.test.js",
10 | "lint": "eslint src --fix",
11 | "dev": "concurrently \"npm run watch:pack\" \"npm run watch:babel\" \"npm run watch:rollup\"",
12 | "build": "npm run pack && node ./node_modules/babel-cli/bin/babel.js src --out-dir lib && npm run buildplatform && npm run copy",
13 | "pack": "node packer.js",
14 | "buildplatform": "rollup -c rollup.config.js",
15 | "prebuild": "npm run clear && npm run lint",
16 | "prepublish": "npm run build",
17 | "watch:pack": "node packer.js --watch",
18 | "watch:babel": "node ./node_modules/babel-cli/bin/babel.js --watch src --out-dir lib",
19 | "watch:rollup": "rollup --watch -c rollup.config.js"
20 | },
21 | "bin": {
22 | "uni-migration": "bin/uni-migration.js"
23 | },
24 | "author": "fxy060608@gmail.com",
25 | "files": [
26 | "index.js",
27 | "lib",
28 | "bin"
29 | ],
30 | "license": "Apache-2.0",
31 | "dependencies": {
32 | "babel-core": "^6.26.0",
33 | "babel-plugin-transform-class-properties": "^6.24.1",
34 | "babel-plugin-transform-object-rest-spread": "^6.26.0",
35 | "chalk": "^2.3.1",
36 | "commander": "^2.15.1",
37 | "css": "^2.2.1",
38 | "css-what": "^2.1.0",
39 | "fs-extra": "^5.0.0",
40 | "pretty-data": "^0.40.0",
41 | "sax": "^1.2.4"
42 | },
43 | "devDependencies": {
44 | "babel-cli": "^6.26.0",
45 | "babel-eslint": "^8.2.2",
46 | "babel-preset-es2015": "^6.24.1",
47 | "babel-preset-minify": "^0.3.0",
48 | "chai": "^4.1.2",
49 | "eslint": "^4.19.1",
50 | "eslint-plugin-vue-libs": "^2.1.0",
51 | "mocha": "^5.0.1",
52 | "rollup": "^0.56.5",
53 | "rollup-plugin-uglify": "^3.0.0"
54 | },
55 | "babel": {
56 | "presets": [
57 | "es2015",
58 | [
59 | "minify", {
60 | "mangle": false
61 | }
62 | ]
63 | ],
64 | "ignore": [
65 | "src/weapp/wx",
66 | "src/weapp/platform"
67 | ]
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/weapp/transform/page-rewriter/template-rewriter/wxml/include.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import rewriteWxs from './cdata'
3 | import parseXml from '../../parser'
4 |
5 | import {
6 | logError
7 | } from '../../../../../utils'
8 |
9 | const ignores = ['wxs', 'import', 'template']
10 | const walk = (node, codeIncludePath, options, fs) => {
11 | if (~ignores.indexOf(node.name)) {
12 | return true
13 | }
14 | if (node.name === 'include' && node.attributes && node.attributes.src) {
15 | const includePath = path.join(path.join(codeIncludePath, '..'), node.attributes.src)
16 | options.location = node.location
17 | const ret = parseIncludeFile(includePath, codeIncludePath, options, fs)
18 | if (ret.nodes.length) {
19 | return ret.nodes
20 | } else {
21 | return true
22 | }
23 | }
24 | let length = node.children.length
25 | while (length--) {
26 | const nodes = walk(node.children[length], codeIncludePath, options, fs)
27 | if (nodes) {
28 | if (Array.isArray(nodes)) { // 多重复一个节点检测
29 | node.children.splice(length, 1, ...nodes)
30 | } else {
31 | node.children.splice(length, 1)
32 | }
33 | }
34 | }
35 | }
36 |
37 | export function parseIncludeFile (includePath, codePagePath, options, fs) {
38 | const location = options.location || {
39 | line: 1,
40 | column: 1
41 | }
42 |
43 | if (fs.existsSync(includePath)) {
44 | return parseInclude(fs.readFileSync(includePath, 'utf-8'), includePath, options, fs)
45 | } else {
46 | logError([{
47 | reason: 'E:`' + includePath + '`不存在',
48 | line: location.line,
49 | column: location.column
50 | }], codePagePath || '')
51 | }
52 |
53 | return {
54 | nodes: []
55 | }
56 | }
57 |
58 | export default function parseInclude (code, codeIncludePath, options, fs) {
59 | let viewNodes = []
60 |
61 | if (typeof code === 'string') {
62 | viewNodes = parseXml(`${rewriteWxs(code)}`).children
63 | } else {
64 | viewNodes = code
65 | }
66 |
67 | let length = viewNodes.length
68 | while (length--) {
69 | const nodes = walk(viewNodes[length], codeIncludePath, options, fs)
70 | if (nodes) {
71 | if (Array.isArray(nodes)) { // 多重复一个节点检测
72 | viewNodes.splice(length, 1, ...nodes)
73 | } else {
74 | viewNodes.splice(length, 1)
75 | }
76 | }
77 | }
78 |
79 | return {
80 | nodes: viewNodes
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/test/weapp/wx/storage/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 | set({
15 | key,
16 | value,
17 | success,
18 | fail,
19 | complete
20 | }) {
21 | if(key === 'fail') {
22 | fail('插入失败', errCode)
23 | } else {
24 | data[key] = value
25 | success(value)
26 | complete(value)
27 | }
28 | },
29 | get({
30 | key,
31 | success,
32 | fail,
33 | complete
34 | }) {
35 | if(key === 'fail') {
36 | fail('获取失败', errCode)
37 | } else {
38 | success(data[key])
39 | complete(data[key])
40 | }
41 | },
42 | delete({
43 | key,
44 | success,
45 | fail,
46 | complete
47 | }) {
48 | if(key === 'fail') {
49 | fail('删除失败', errCode)
50 | } else {
51 | success(data[key])
52 | complete(data[key])
53 | }
54 | },
55 | clear({
56 | success,
57 | fail,
58 | complete
59 | }) {}
60 | })
61 |
62 | describe('api.storage', () => {
63 |
64 | it('wx.setStorage', () => {
65 | wx.setStorage({
66 | key: 'key',
67 | data: 'value',
68 | success: function(data) {
69 | expect(data.errMsg).eql('setStorage:ok')
70 | },
71 | complete: function(data) {
72 | expect(data.errMsg).eql('setStorage:ok')
73 | }
74 | })
75 | wx.setStorage({
76 | key: 'fail',
77 | data: 'value',
78 | fail: function(data, code) {
79 | expect(code).eql(errCode)
80 | }
81 | })
82 | })
83 |
84 | it('wx.getStorage', () => {
85 | wx.getStorage({
86 | key: 'key',
87 | success: function(res) {
88 | expect(res.data).eql('value')
89 | },
90 | complete: function(res) {
91 | expect(res.data).eql('value')
92 | }
93 | })
94 | wx.getStorage({
95 | key: 'fail',
96 | fail: function(data, code) {
97 | expect(code).eql(errCode)
98 | }
99 | })
100 | })
101 |
102 | it('wx.removeStorage', () => {
103 | wx.removeStorage({
104 | key: 'key',
105 | success: function(data) {
106 | expect(data.errMsg).eql('removeStorage:ok')
107 | },
108 | complete: function(data) {
109 | expect(data.errMsg).eql('removeStorage:ok')
110 | }
111 | })
112 | wx.removeStorage({
113 | key: 'fail',
114 | fail: function(data, code) {
115 | expect(code).eql(errCode)
116 | }
117 | })
118 | })
119 |
120 | it('wx.clearStorage', () => {
121 | wx.clearStorage()
122 | })
123 | })
--------------------------------------------------------------------------------
/src/weapp/wx/wx.js:
--------------------------------------------------------------------------------
1 | import modules from '../../../src/weapp/wx/packer'
2 | import { isPlainObject } from '../../../src/utils/type'
3 |
4 | const wx = {}
5 |
6 | const createCallback = (callback, methodDef, methodName) => {
7 | return ret => {
8 | const data = processData(ret, methodDef.returnValue, methodName, true)
9 | if (isPlainObject(data) && !data.errMsg) {
10 | data.errMsg = `${methodName}:ok`
11 | }
12 | callback(data)
13 | }
14 | }
15 |
16 | const processData = (data, def, methodName, isReturn) => {
17 | if (typeof def === 'function') {
18 | data = def(data)
19 | }
20 | return data
21 | }
22 |
23 | const processAsync = (moduleName, methodName, def) => {
24 | return {
25 | enumerable: true,
26 | configurable: true,
27 | get: function proxyGetter () {
28 | const methodDef = def[methodName]
29 | if (typeof methodDef === 'function') {
30 | return methodDef
31 | } else {
32 | return (args) => {
33 | args = args || {}
34 | args = Object.assign(args, processData(args, methodDef.args))
35 |
36 | if (typeof args.success === 'function') {
37 | args.success = createCallback(args.success, methodDef, methodName)
38 | }
39 | if (typeof args.complete === 'function') {
40 | args.complete = createCallback(args.complete, methodDef, methodName)
41 | }
42 | if (typeof args.callback === 'function') {
43 | args.callback = createCallback(args.callback, methodDef, methodName)
44 | }
45 | /*eslint-disable no-undef*/
46 | return uni[moduleName][methodDef.name](args)
47 | }
48 | }
49 | }
50 | }
51 | }
52 |
53 | const processSync = (moduleName, methodName, def) => {
54 | return {
55 | enumerable: true,
56 | configurable: true,
57 | get: function proxyGetter () {
58 | const methodDef = def[methodName]
59 | return async function (args) {
60 | args = args || {}
61 | args = processData(args, methodDef.args)
62 | /*eslint-disable no-undef*/
63 | return processData(uni[moduleName][methodDef.name](args), methodDef.returnValue)
64 | }
65 | }
66 | }
67 | }
68 |
69 | Object.keys(modules).forEach(moduleName => {
70 | const moduleDef = modules[moduleName]
71 | Object.keys(moduleDef).forEach(methodName => {
72 | if (~methodName.indexOf('Sync')) {
73 | Object.defineProperty(wx, methodName, processSync(moduleName, methodName, moduleDef))
74 | } else {
75 | Object.defineProperty(wx, methodName, processAsync(moduleName, methodName, moduleDef))
76 | }
77 | })
78 | })
79 |
80 | export default wx
81 |
--------------------------------------------------------------------------------
/src/weapp/transform/page-rewriter/template-rewriter/wxml/fragment.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import rewriteWxs from './cdata'
3 | import parseXml from '../../parser'
4 | import { parseIncludeFile } from './include'
5 | import { resolvePath } from '../../../../../utils'
6 |
7 | const walk = (node, codePagePath, ret, options, fs) => {
8 | const dirname = path.join(codePagePath, '..')
9 | const name = node.name
10 | if (name === 'wxs') { // wxs存储并删除
11 | node.attributes.module && ret.wxs.push({
12 | name: node.attributes.module,
13 | src: node.attributes.src,
14 | content: node.content,
15 | location: node.location
16 | })
17 | return true
18 | } else if (name === 'import') { // import存储并删除
19 | node.attributes.src && ret.imports.push({
20 | name: node.attributes.name || '',
21 | src: resolvePath(dirname, node.attributes.src, options.input),
22 | template: !!node.attributes.template,
23 | location: node.location
24 | })
25 | return true
26 | } else if (name === 'include') {
27 | if (node.attributes.src) {
28 | options.location = node.location
29 | const {
30 | nodes
31 | } = parseIncludeFile(resolvePath(dirname, node.attributes.src, options.input), codePagePath, options, fs)
32 | return nodes
33 | }
34 | } else if (name === 'template' && node.attributes.name) { // template name存储并删除
35 | ret.templates.push({
36 | name: node.attributes.name,
37 | nodes: node.children,
38 | location: node.location
39 | })
40 | return true
41 | }
42 | let length = node.children.length
43 | while (length--) {
44 | const nodes = walk(node.children[length], codePagePath, ret, options, fs)
45 | if (nodes) {
46 | if (Array.isArray(nodes)) { // 多重复一个节点检测
47 | node.children.splice(length, 1, ...nodes)
48 | } else {
49 | node.children.splice(length, 1)
50 | }
51 | }
52 | }
53 | }
54 | export default function parseFragment (code, codePagePath, options, fs) {
55 | const ret = {
56 | wxs: [],
57 | views: [], // 视图节点
58 | imports: [], // import引入
59 | templates: [] // template定义
60 | }
61 |
62 | let viewNodes = []
63 |
64 | if (typeof code === 'string') {
65 | viewNodes = parseXml(`${rewriteWxs(code)}`).children
66 | } else {
67 | viewNodes = code
68 | }
69 | let length = viewNodes.length
70 | while (length--) {
71 | const nodes = walk(viewNodes[length], codePagePath, ret, options, fs)
72 | if (nodes) {
73 | if (Array.isArray(nodes)) { // 多重复一个节点检测
74 | viewNodes.splice(length, 1, ...nodes)
75 | } else {
76 | viewNodes.splice(length, 1)
77 | }
78 | }
79 | }
80 |
81 | ret.views = viewNodes
82 |
83 | return ret
84 | }
85 |
--------------------------------------------------------------------------------
/src/weapp/transform/page-rewriter/template-rewriter/style.js:
--------------------------------------------------------------------------------
1 | import { isExpr, getMatches } from '../../../../utils'
2 | import { processDeclarationValue } from '../../helper/style/util'
3 |
4 | import { declarations } from '../../helper/style/declaration'
5 |
6 | const processInlineDeclaration = (declaration, output, location) => {
7 | const ret = []
8 | if (declaration.property.indexOf('-webkit-') === 0) {
9 | declaration.property = declaration.property.replace('-webkit-', '')
10 | }
11 | declaration.value = processDeclarationValue(declaration.value)
12 |
13 | if (declarations.hasOwnProperty(declaration.property)) {
14 | let processDeclaration = declarations[declaration.property]
15 | if (typeof processDeclaration === 'function') {
16 | processDeclaration = processDeclaration(declaration.value, declaration, function (property, value) {
17 | ret.push(property + ':' + value)
18 | }, {
19 | declarations: []
20 | })
21 | }
22 | if (Array.isArray(processDeclaration)) { // 直接增加一组
23 | processDeclaration.forEach(declaration => {
24 | ret.push(declaration.property + ':' + declaration.value)
25 | })
26 | } else if (typeof processDeclaration === 'object') { // 直接增加一条
27 | ret.push(processDeclaration.property + ':' + processDeclaration.value)
28 | } else if (typeof processDeclaration === 'string') {
29 | if (processDeclaration.indexOf('I:') === 0) { // 删除
30 | return ret
31 | } else if (processDeclaration.indexOf('W:') === 0) { // 警告
32 | return ret
33 | } else if (processDeclaration.indexOf('E:') === 0) { // 错误
34 | const msg = 'E: 内联样式`' + declaration.property + '`不支持`' + declaration.value + '`'
35 | output && output.logs.push({
36 | reason: (processDeclaration.length === 2 ? msg : (msg + ',' + processDeclaration.replace('E:'))),
37 | line: location.line,
38 | column: location.column
39 | })
40 | return ret
41 | }
42 | }
43 | ret.push(declaration.property + ':' + declaration.value)
44 | }
45 | return ret
46 | }
47 |
48 | export default function rewriteStyle (name, attr, output, location) {
49 | let value = attr[name]
50 | if (value) {
51 | const matches = getMatches(value, /([\w-]+)\s*:\s*([^;]+)/)
52 | if (matches.length) {
53 | let ret = []
54 | matches.forEach(match => {
55 | if (match.length === 3) {
56 | if (!isExpr(match[2])) {
57 | // 静态内联样式转换
58 | ret = ret.concat(processInlineDeclaration({
59 | property: match[1],
60 | value: match[2]
61 | }))
62 | } else {
63 | ret.push(match[1] + ':' + match[2])
64 | }
65 | }
66 | })
67 | value = ret.join(';')
68 | }
69 | }
70 | attr[name] = value
71 | }
72 |
--------------------------------------------------------------------------------
/src/weapp/transform/helper/style/declaration/index.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import fs from 'fs-extra'
3 |
4 | import {
5 | processDeclarationValue
6 | } from '../util'
7 |
8 | export const declarations = {}
9 |
10 | !(function parse (dir) {
11 | dir = dir || '.'
12 | const dirPath = path.join(__dirname, dir)
13 | fs.readdirSync(dirPath).forEach(file => {
14 | const filePath = path.join(dirPath, file)
15 | if (fs.statSync(filePath).isFile()) {
16 | if (path.extname(filePath) === '.js') {
17 | Object.assign(declarations, require(filePath)['default'])
18 | }
19 | } else {
20 | parse(path.join(dir, file))
21 | }
22 | })
23 | })('.')
24 |
25 | export default function rewriter (declaration, rule, output) {
26 | if (!declaration.position) {
27 | declaration.position = {
28 | start: {
29 | line: 1,
30 | column: 1
31 | },
32 | end: {
33 | line: 1,
34 | column: 1
35 | }
36 | }
37 | }
38 | if (declaration.property.indexOf('-webkit-') === 0) {
39 | declaration.property = declaration.property.replace('-webkit-', '')
40 | }
41 | declaration.value = processDeclarationValue(declaration.value)
42 |
43 | if (declarations.hasOwnProperty(declaration.property)) {
44 | let processDeclaration = declarations[declaration.property]
45 | if (typeof processDeclaration === 'function') {
46 | processDeclaration = processDeclaration(declaration.value, declaration, function (property, value) {
47 | output.declaration.inserted.push({
48 | property,
49 | value
50 | })
51 | }, rule)
52 | }
53 | if (Array.isArray(processDeclaration)) { // 直接增加一组
54 | output.declaration.inserted.concat(processDeclaration)
55 | } else if (typeof processDeclaration === 'object') { // 直接增加一条
56 | output.declaration.inserted.push(processDeclaration)
57 | } else if (typeof processDeclaration === 'string') {
58 | if (processDeclaration.indexOf('I:') === 0) { // 删除
59 | output.declaration.deleted.push(declaration)
60 | } else if (processDeclaration.indexOf('W:') === 0) { // 警告
61 | output.declaration.deleted.push(declaration)
62 | } else if (processDeclaration.indexOf('E:') === 0) { // 错误
63 | output.declaration.deleted.push(declaration)
64 | const msg = 'E: 样式`' + declaration.property + ':' + declaration.value + '`不支持'
65 | output.logs.push({
66 | reason: msg,
67 | line: declaration.position.start.line,
68 | column: declaration.position.start.column
69 | })
70 | }
71 | }
72 | } else {
73 | output.declaration.deleted.push(declaration)
74 | // output.logs.push({
75 | // reason: 'E:缺少`' + declaration.property + '`转换器',
76 | // line: declaration.position.start.line,
77 | // column: declaration.position.start.column
78 | // })
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/test/weapp/transform/helper/util.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const fs = require('fs-extra')
3 | const chai = require('chai')
4 | const expect = chai.expect
5 | const css = require('css')
6 |
7 | const LOG = require('../../../../lib/utils')
8 |
9 | const options = require('../../../../lib/weapp/config')['uniapp']
10 |
11 | const template = require('../../../../lib/weapp/transform/page-rewriter/template-rewriter').default
12 | const serialize = require('../../../../lib/weapp/transform/page-rewriter/serialize').default
13 |
14 | const style = require('../../../../lib/weapp/transform/page-rewriter/style-rewriter').default
15 |
16 | const logError = logs => {
17 | let hasError = false
18 | logs && logs.length && logs.forEach(log => {
19 | if (log.reason.indexOf('W:') === 0) {
20 | //LOG.warn(log.reason.replace('W:', '') + '\t\n@' + log.line + ':' + log.column)
21 | } else if (log.reason.indexOf('I:') === 0) {
22 | //LOG.ignore(log.reason.replace('I:', '') + '\t\n@' + log.line + ':' + log.column)
23 | } else if (log.reason.indexOf('E:') === 0) {
24 | hasError = true
25 | LOG.error(log.reason.replace('E:', '') + '\t\n@' + log.line + ':' + log.column)
26 | } else {
27 | console.log(log.reason + '\t\n@' + log.line + ':' + log.column)
28 | }
29 | })
30 | return false
31 | }
32 | const pagePath = path.join(__dirname)
33 | const config = {
34 | ext: {
35 | wxml: '.nml',
36 | wxss: '.nss',
37 | app: '.njs'
38 | },
39 | input: path.join(__dirname, '../../../../../demo/weapp/input'),
40 | output: path.join(__dirname, '../../../../../demo/weapp/output/src')
41 | }
42 | module.exports = {
43 | rewriteTemplate(code) {
44 | let templateCode = ''
45 | const templateRet = template(code, pagePath, config, fs)
46 | if (logError(templateRet.logs)) {
47 | return false
48 | }
49 | if (templateRet.nodes) {
50 | templateCode = serialize(templateRet.nodes,false)
51 | } else {
52 | logError([{
53 | reason: 'E:模板转换失败',
54 | line: 1,
55 | column: 1
56 | }])
57 | return false
58 | }
59 | return {
60 | code: templateCode,
61 | ast: templateRet.result || {}
62 | }
63 | },
64 | assertTemplateString(fixture, expected) {
65 | const ret = this.rewriteTemplate(fixture)
66 | expect(ret.code).eql(expected)
67 | },
68 | rewriteStyle(code) {
69 | let styleCode = ''
70 | const styleRet = style(code, options)
71 | if (logError(styleRet.logs)) {
72 | return false
73 | }
74 | if (styleRet.result) {
75 | styleCode = css.stringify(styleRet.result, {
76 | compress: true
77 | })
78 | } else {
79 | logError([{
80 | reason: 'E:样式转换失败',
81 | line: 1,
82 | column: 1
83 | }])
84 | return false
85 | }
86 | return {
87 | code: styleCode,
88 | ast: styleRet.result || {}
89 | }
90 | },
91 | assertStyleString(fixture, expected) {
92 | const ret = this.rewriteStyle(fixture)
93 | expect(ret.code).eql(expected)
94 | }
95 | }
--------------------------------------------------------------------------------
/test/weapp/platform/behavior.test.js:
--------------------------------------------------------------------------------
1 | const chai = require('chai')
2 | const expect = chai.expect
3 |
4 | require('./util')
5 |
6 | describe('platform', () => {
7 |
8 | it('`Behavior`', () => {
9 | const b1 = Behavior({
10 | properties: {
11 | myBehaviorProperty: {
12 | type: Number
13 | }
14 | },
15 | data: {
16 | myBehaviorData: {
17 | test: 2
18 | },
19 | myBehaviorData1: {
20 | test: 2
21 | }
22 | },
23 | attached: function () {
24 | console.log('b1 attached')
25 | },
26 | methods: {
27 | myBehaviorMethod: function () {}
28 | }
29 | })
30 | const b2 = Behavior({
31 | properties: {
32 | myBehaviorProperty: {
33 | type: String
34 | },
35 | myBehaviorProperty1: {
36 | type: Number
37 | }
38 | },
39 | data: {
40 | myBehaviorData: {
41 | test: 1
42 | }
43 | },
44 | created: function () {
45 | console.log('b2 created')
46 | },
47 | attached: function () {
48 | console.log('b2 attached')
49 | },
50 | methods: {
51 | myBehaviorMethod2: function () {}
52 | }
53 | })
54 |
55 | const module = {
56 | exports: {}
57 | }
58 | const c1 = Component({
59 | behaviors: [b1, b2],
60 | properties: {
61 | myProperty: { // 属性名
62 | type: String, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型)
63 | value: '', // 属性初始值(可选),如果未指定则会根据类型选择一个
64 | observer: function (newVal, oldVal) {} // 属性被改变时执行的函数(可选),也可以写成在methods段中定义的方法名字符串, 如:'_propertyChange'
65 | },
66 | myProperty2: String // 简化的定义方式
67 | },
68 | data: {}, // 私有数据,可用于模版渲染
69 |
70 | // 生命周期函数,可以为函数,或一个在methods段中定义的方法名
71 | attached: function () {
72 | console.log('c1 attached')
73 | },
74 | moved: function () {},
75 | detached: function () {
76 | console.log('c1 detached')
77 | },
78 |
79 | methods: {
80 | onMyButtonTap: function () {
81 | this.setData({
82 | // 更新属性和数据的方法与更新页面数据的方法类似
83 | })
84 | },
85 | _myPrivateMethod: function () {
86 | // 内部方法建议以下划线开头
87 | this.replaceDataOnPath(['A', 0, 'B'], 'myPrivateData') // 这里将 data.A[0].B 设为 'myPrivateData'
88 | this.applyDataUpdates()
89 | },
90 | _propertyChange: function (newVal, oldVal) {
91 |
92 | }
93 | }
94 | }, {
95 | path: 'page/common/component/test',
96 | module: module,
97 | exports: exports,
98 | $app_require$: {},
99 | wxs: typeof _$wxs$_ === 'undefined' ? {} : _$wxs$_
100 | })
101 | expect(b2.properties.myBehaviorProperty.type).eql(String)
102 | expect(b2.data.myBehaviorData.test).eql(1)
103 | expect(module.exports.attached.length).eql(3)
104 | })
105 |
106 | })
--------------------------------------------------------------------------------
/src/weapp/transform/helper/style/declaration/border/index.js:
--------------------------------------------------------------------------------
1 | function valueType (value) {
2 | const styles = ['none', 'hidden', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset']
3 | // 需要考虑到0px简写为0的情况,否则会当作color处理。
4 | if (/px/ig.test(value) || parseInt(value) === 0 || value === 'none') {
5 | return 'width'
6 | } else if (~styles.indexOf(value)) {
7 | return 'style'
8 | } else {
9 | return 'color'
10 | }
11 | }
12 |
13 | function setStyle (direction, value, addDeclaration) {
14 | const values = value.split(' ')
15 | for (let i = 0, length = values.length; i < length; i++) {
16 | const borderProperty = `border-${direction}-${valueType(values[i])}`
17 | if (values[i] === 'none') {
18 | values[i] = '0'
19 | }
20 | if (/\S+style$/.test(borderProperty)) {
21 | addDeclaration('border-style', values[i])
22 | } else {
23 | addDeclaration(borderProperty, values[i])
24 | }
25 | }
26 | return 'I:'
27 | }
28 |
29 | function setWidth (value, declaration) {
30 | const styles = ['thin', 'medium', 'thick', 'inherit']
31 | const values = ['1px', '2px', '3px', '1px']
32 | var valueList = value.split(' ')
33 | value = valueList[0]
34 | if (~styles.indexOf(value)) {
35 | const index = styles.indexOf(value)
36 | console.log(index)
37 | value = values[index]
38 | }
39 | if (~value.indexOf('%')) {
40 | value = 750 / 100 * parseInt(value) + 'px'
41 | }
42 | declaration.value = value
43 | }
44 |
45 | export default {
46 | 'border': (value, declaration, addDeclaration) => {
47 | if (value === 'none') {
48 | declaration.value = 0
49 | }
50 | return ''
51 | },
52 | 'border-color': '',
53 | 'border-style': '',
54 | 'border-width': (value, declaration, addDeclaration) => { // width也不支持百分数,后期在转换
55 | setWidth(value, declaration)
56 | },
57 | 'border-radius': (value, declaration, addDeclaration) => { // width也不支持百分数,后期在转换
58 | if (~value.indexOf('%')) {
59 | // 其实应当按照当前组件的宽高为基准计算,但这里拿不到,暂时这样处理下。
60 | value = 750 / 100 * parseInt(value) + 'px'
61 | declaration.value = value
62 | }
63 | },
64 | 'border-top': (value, declaration, addDeclaration) => {
65 | return setStyle('top', value, addDeclaration)
66 | },
67 | 'border-bottom': (value, declaration, addDeclaration) => {
68 | return setStyle('bottom', value, addDeclaration)
69 | },
70 | 'border-left': (value, declaration, addDeclaration) => {
71 | return setStyle('left', value, addDeclaration)
72 | },
73 | 'border-right': (value, declaration, addDeclaration) => {
74 | return setStyle('right', value, addDeclaration)
75 | },
76 | 'border-left-width': (value, declaration, addDeclaration) => {
77 | setWidth(value, declaration)
78 | },
79 | 'border-right-width': (value, declaration, addDeclaration) => {
80 | setWidth(value, declaration)
81 | },
82 | 'border-top-width': (value, declaration, addDeclaration) => {
83 | setWidth(value, declaration)
84 | },
85 | 'border-bottom-width': (value, declaration, addDeclaration) => {
86 | setWidth(value, declaration)
87 | },
88 | 'border-left-color': '',
89 | 'border-right-color': '',
90 | 'border-top-color': '',
91 | 'border-bottom-color': '',
92 | 'border-left-radius': '',
93 | 'border-right-radius': '',
94 | 'border-top-radius': '',
95 | 'border-bottom-radius': '',
96 | 'border-top-style': 'I:',
97 | 'border-bottom-style': 'I:',
98 | 'border-left-style': 'I:',
99 | 'border-right-style': 'I:'
100 | }
101 |
--------------------------------------------------------------------------------