babel-plugin-transform-taroapi 3.7.0-alpha.8 → 3.7.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`babel-plugin-transform-taroapi should canIUse support scheme with numeric attributes! 1`] = `
|
|
4
|
+
"import { canIUse as _canUse } from '@tarojs/taro-h5';
|
|
5
|
+
// 入参带有数字属性的对象路径
|
|
6
|
+
true;
|
|
7
|
+
true;"
|
|
8
|
+
`;
|
|
9
|
+
|
|
10
|
+
exports[`babel-plugin-transform-taroapi should canIUse support! 1`] = `
|
|
11
|
+
"import { canIUse as _canUse } from '@tarojs/taro-h5';
|
|
12
|
+
// 对象的属性或方法
|
|
13
|
+
false;
|
|
14
|
+
false;
|
|
15
|
+
false;
|
|
16
|
+
false;
|
|
17
|
+
|
|
18
|
+
// 接口参数、回调或者返回值
|
|
19
|
+
true;
|
|
20
|
+
false;
|
|
21
|
+
false;
|
|
22
|
+
false;
|
|
23
|
+
false;
|
|
24
|
+
true;
|
|
25
|
+
|
|
26
|
+
// 组件的属性
|
|
27
|
+
true;
|
|
28
|
+
true;
|
|
29
|
+
true;"
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
exports[`babel-plugin-transform-taroapi should canIUse work or skip! 1`] = `
|
|
33
|
+
"import Taro from '@tarojs/taro-h5';
|
|
34
|
+
function canIUse() {}
|
|
35
|
+
false;
|
|
36
|
+
false;
|
|
37
|
+
canIUse('showToast.object.image');"
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
exports[`babel-plugin-transform-taroapi should leave other apis untouched 1`] = `
|
|
41
|
+
"import Taro from '@tarojs/taro-h5';
|
|
42
|
+
Taro.noop;"
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
exports[`babel-plugin-transform-taroapi should move static apis under "Taro" 1`] = `
|
|
46
|
+
"import Taro from '@tarojs/taro-h5';
|
|
47
|
+
Taro.noop;
|
|
48
|
+
Taro.noop();"
|
|
49
|
+
`;
|
|
50
|
+
|
|
51
|
+
exports[`babel-plugin-transform-taroapi should not go wrong when using an api twice 1`] = `
|
|
52
|
+
"import Taro, { createAnimation as _createAnimation } from '@tarojs/taro-h5';
|
|
53
|
+
const animation = _createAnimation({
|
|
54
|
+
duration: dura * 1000,
|
|
55
|
+
timingFunction: 'linear'
|
|
56
|
+
});
|
|
57
|
+
const resetAnimation = _createAnimation({
|
|
58
|
+
duration: 0,
|
|
59
|
+
timingFunction: 'linear'
|
|
60
|
+
});"
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
exports[`babel-plugin-transform-taroapi should not import taro duplicity 1`] = `
|
|
64
|
+
"import Taro, { createAnimation as _createAnimation, initPxTransform as _initPxTransform } from '@tarojs/taro-h5';
|
|
65
|
+
Taro.Component;
|
|
66
|
+
_createAnimation();
|
|
67
|
+
_initPxTransform();"
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
exports[`babel-plugin-transform-taroapi should preserve assignments in left hands 1`] = `
|
|
71
|
+
"import Taro, { createAnimation as _createAnimation, request as _request } from '@tarojs/taro-h5';
|
|
72
|
+
let animation;
|
|
73
|
+
animation = _createAnimation({
|
|
74
|
+
transformOrigin: "50% 50%",
|
|
75
|
+
duration: 1000,
|
|
76
|
+
timingFunction: "ease",
|
|
77
|
+
delay: 0
|
|
78
|
+
});
|
|
79
|
+
_request();
|
|
80
|
+
Taro.request = '';
|
|
81
|
+
Taro['request'] = '';"
|
|
82
|
+
`;
|
|
83
|
+
|
|
84
|
+
exports[`babel-plugin-transform-taroapi should preserve default imports 1`] = `
|
|
85
|
+
"import Taro from '@tarojs/taro-h5';
|
|
86
|
+
console.log(Taro);"
|
|
87
|
+
`;
|
|
88
|
+
|
|
89
|
+
exports[`babel-plugin-transform-taroapi should support rename of imported names 1`] = `
|
|
90
|
+
"// import { inject as mobxInject, observer as mobxObserver } from '@tarojs/mobx'
|
|
91
|
+
import Taro from '@tarojs/taro-h5';
|
|
92
|
+
export class Connected extends Taro.Component {}"
|
|
93
|
+
`;
|
|
94
|
+
|
|
95
|
+
exports[`babel-plugin-transform-taroapi should work! 1`] = `
|
|
96
|
+
"import Taro, { setStorage as _setStorage, initPxTransform as _initPxTransform, getStorage as _getStorage } from '@tarojs/taro-h5';
|
|
97
|
+
_initPxTransform(Taro.param);
|
|
98
|
+
_initPxTransform();
|
|
99
|
+
_initPxTransform();
|
|
100
|
+
_getStorage();
|
|
101
|
+
_setStorage();
|
|
102
|
+
export { Taro };"
|
|
103
|
+
`;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import * as babel from '@babel/core'
|
|
2
|
+
import * as t from '@babel/types'
|
|
3
|
+
|
|
4
|
+
import plugin from '../src'
|
|
5
|
+
import * as definition from './__mocks__/harmony-definition.json'
|
|
6
|
+
|
|
7
|
+
type ImportType = babel.types.ImportSpecifier | babel.types.ImportDefaultSpecifier | babel.types.ImportNamespaceSpecifier
|
|
8
|
+
|
|
9
|
+
const packageName = '@tarojs/taro-h5'
|
|
10
|
+
const pluginOptions = [
|
|
11
|
+
plugin,
|
|
12
|
+
{
|
|
13
|
+
packageName,
|
|
14
|
+
definition,
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
const getNamedImports = (importSpecifiers: (t.ImportSpecifier | t.ImportDefaultSpecifier | t.ImportNamespaceSpecifier)[]) => {
|
|
18
|
+
return importSpecifiers.reduce((prev, curr) => {
|
|
19
|
+
if (t.isImportSpecifier(curr)) {
|
|
20
|
+
prev.add(((curr as t.ImportSpecifier).imported as babel.types.Identifier).name)
|
|
21
|
+
}
|
|
22
|
+
return prev
|
|
23
|
+
}, new Set())
|
|
24
|
+
}
|
|
25
|
+
const babelTransform = (code = '') => babel.transform(code, { ast: true, configFile: false, plugins: [pluginOptions] })
|
|
26
|
+
|
|
27
|
+
describe('babel-plugin-transform-taroapi', () => {
|
|
28
|
+
test('should work!', function () {
|
|
29
|
+
const code = `
|
|
30
|
+
import Taro, { setStorage, initPxTransform, param } from '${packageName}';
|
|
31
|
+
initPxTransform(param)
|
|
32
|
+
Taro.initPxTransform()
|
|
33
|
+
Taro.initPxTransform()
|
|
34
|
+
Taro['getStorage']()
|
|
35
|
+
setStorage()
|
|
36
|
+
export { Taro }
|
|
37
|
+
`
|
|
38
|
+
const result = babelTransform(code)
|
|
39
|
+
expect(result?.code).toMatchSnapshot()
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
test('should leave other apis untouched', function () {
|
|
43
|
+
const code = `
|
|
44
|
+
import Taro from '${packageName}'
|
|
45
|
+
Taro.noop
|
|
46
|
+
`
|
|
47
|
+
const result = babelTransform(code)
|
|
48
|
+
expect(result?.code).toMatchSnapshot()
|
|
49
|
+
|
|
50
|
+
const ast = result?.ast as t.File
|
|
51
|
+
const body = ast.program.body as [t.ImportDeclaration, t.ExpressionStatement]
|
|
52
|
+
expect(t.isImportDeclaration(body[0])).toBeTruthy()
|
|
53
|
+
expect(t.isExpressionStatement(body[1])).toBeTruthy()
|
|
54
|
+
const defaultImport = body[0].specifiers.find(v => t.isImportDefaultSpecifier(v)) as ImportType
|
|
55
|
+
expect(defaultImport).toBeTruthy()
|
|
56
|
+
|
|
57
|
+
const taroName = defaultImport.local.name
|
|
58
|
+
const namedImports = getNamedImports(body[0].specifiers)
|
|
59
|
+
expect(namedImports).toEqual(new Set())
|
|
60
|
+
expect(t.isMemberExpression(body[1].expression)).toBeTruthy()
|
|
61
|
+
|
|
62
|
+
const obj = t.memberExpression(
|
|
63
|
+
t.identifier(taroName),
|
|
64
|
+
t.identifier('noop'),
|
|
65
|
+
)
|
|
66
|
+
delete obj.optional
|
|
67
|
+
|
|
68
|
+
expect((body[1].expression as t.MemberExpression)).toMatchObject(obj)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('should move static apis under "Taro"', function () {
|
|
72
|
+
const code = `
|
|
73
|
+
import { noop } from '${packageName}';
|
|
74
|
+
noop;
|
|
75
|
+
noop();
|
|
76
|
+
`
|
|
77
|
+
|
|
78
|
+
const result = babelTransform(code)
|
|
79
|
+
expect(result?.code).toMatchSnapshot()
|
|
80
|
+
|
|
81
|
+
const ast = result?.ast as t.File
|
|
82
|
+
const body = ast.program.body as [t.ImportDeclaration, t.ExpressionStatement]
|
|
83
|
+
expect(t.isImportDeclaration(body[0])).toBeTruthy()
|
|
84
|
+
expect(t.isExpressionStatement(body[1])).toBeTruthy()
|
|
85
|
+
const defaultImport = body[0].specifiers.find(v => t.isImportDefaultSpecifier(v))
|
|
86
|
+
expect(defaultImport).toBeTruthy()
|
|
87
|
+
|
|
88
|
+
const taroName = defaultImport!.local.name
|
|
89
|
+
let memberExpression: any = body[1].expression
|
|
90
|
+
if (t.isCallExpression(body[1])) {
|
|
91
|
+
memberExpression = ((body[1] as t.ExpressionStatement).expression as t.CallExpression).callee
|
|
92
|
+
}
|
|
93
|
+
expect(memberExpression).toMatchObject(t.memberExpression(
|
|
94
|
+
t.identifier(taroName),
|
|
95
|
+
t.identifier('noop')
|
|
96
|
+
))
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
test('should not import taro duplicity', function () {
|
|
100
|
+
const code = `
|
|
101
|
+
import { Component } from '${packageName}';
|
|
102
|
+
import Taro from '${packageName}';
|
|
103
|
+
Component
|
|
104
|
+
Taro.createAnimation()
|
|
105
|
+
Taro.initPxTransform()
|
|
106
|
+
`
|
|
107
|
+
|
|
108
|
+
const result = babelTransform(code)
|
|
109
|
+
expect(result?.code).toMatchSnapshot()
|
|
110
|
+
const ast = result?.ast as t.File
|
|
111
|
+
const body = ast.program.body as [t.ImportDeclaration, t.ExpressionStatement, t.ExpressionStatement]
|
|
112
|
+
expect(t.isImportDeclaration(body[0])).toBeTruthy()
|
|
113
|
+
expect(t.isExpressionStatement(body[1])).toBeTruthy()
|
|
114
|
+
expect(t.isExpressionStatement(body[2])).toBeTruthy()
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
test('should not go wrong when using an api twice', function () {
|
|
118
|
+
const code = `
|
|
119
|
+
import Taro from '${packageName}';
|
|
120
|
+
const animation = Taro.createAnimation({
|
|
121
|
+
duration: dura * 1000,
|
|
122
|
+
timingFunction: 'linear'
|
|
123
|
+
})
|
|
124
|
+
const resetAnimation = Taro.createAnimation({
|
|
125
|
+
duration: 0,
|
|
126
|
+
timingFunction: 'linear'
|
|
127
|
+
})
|
|
128
|
+
`
|
|
129
|
+
expect(() => {
|
|
130
|
+
const result = babelTransform(code)
|
|
131
|
+
expect(result?.code).toMatchSnapshot()
|
|
132
|
+
}).not.toThrowError()
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
test('should preserve default imports', function () {
|
|
136
|
+
const code = `
|
|
137
|
+
import Taro from '${packageName}'
|
|
138
|
+
console.log(Taro)
|
|
139
|
+
`
|
|
140
|
+
const result = babelTransform(code)
|
|
141
|
+
expect(result?.code).toMatchSnapshot()
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
test('should preserve assignments in left hands', function () {
|
|
145
|
+
const code = `
|
|
146
|
+
import Taro from '${packageName}'
|
|
147
|
+
let animation
|
|
148
|
+
animation = Taro.createAnimation({
|
|
149
|
+
transformOrigin: "50% 50%",
|
|
150
|
+
duration: 1000,
|
|
151
|
+
timingFunction: "ease",
|
|
152
|
+
delay: 0
|
|
153
|
+
});
|
|
154
|
+
Taro.request()
|
|
155
|
+
Taro.request = ''
|
|
156
|
+
Taro['request'] = ''
|
|
157
|
+
`
|
|
158
|
+
const result = babelTransform(code)
|
|
159
|
+
expect(result?.code).toMatchSnapshot()
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
test('should support rename of imported names', function () {
|
|
163
|
+
const code = `
|
|
164
|
+
// import { inject as mobxInject, observer as mobxObserver } from '@tarojs/mobx'
|
|
165
|
+
import { Component as TaroComponent } from '${packageName}';
|
|
166
|
+
export class Connected extends TaroComponent {}
|
|
167
|
+
`
|
|
168
|
+
const result = babelTransform(code)
|
|
169
|
+
expect(result?.code).toMatchSnapshot()
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
test('should canIUse work or skip!', function () {
|
|
173
|
+
const code = `
|
|
174
|
+
import Taro from '${packageName}'
|
|
175
|
+
function canIUse() {}
|
|
176
|
+
Taro.canIUse('showToast.object.image')
|
|
177
|
+
Taro['canIUse']('showToast.object.image')
|
|
178
|
+
canIUse('showToast.object.image')
|
|
179
|
+
`
|
|
180
|
+
const result = babelTransform(code)
|
|
181
|
+
expect(result?.code).toMatchSnapshot()
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
test('should canIUse support!', function () {
|
|
185
|
+
const code = `
|
|
186
|
+
import { canIUse as canUse } from '${packageName}';
|
|
187
|
+
// 对象的属性或方法
|
|
188
|
+
canUse('console.log')
|
|
189
|
+
canUse('CameraContext.onCameraFrame')
|
|
190
|
+
canUse('CameraFrameListener.start')
|
|
191
|
+
canUse('Image.src')
|
|
192
|
+
|
|
193
|
+
// 接口参数、回调或者返回值
|
|
194
|
+
canUse('openBluetoothAdapter')
|
|
195
|
+
canUse('getSystemInfoSync.return.safeArea.left')
|
|
196
|
+
canUse('getSystemInfo.success.screenWidth')
|
|
197
|
+
canUse('showToast.object.image')
|
|
198
|
+
canUse('onCompassChange.callback.direction')
|
|
199
|
+
canUse('request.object.method.GET')
|
|
200
|
+
|
|
201
|
+
// 组件的属性
|
|
202
|
+
canUse('live-player')
|
|
203
|
+
canUse('text.selectable')
|
|
204
|
+
canUse('button.open-type.contact')
|
|
205
|
+
`
|
|
206
|
+
const result = babelTransform(code)
|
|
207
|
+
expect(result?.code).toMatchSnapshot()
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
test('should canIUse support scheme with numeric attributes!', function () {
|
|
211
|
+
const code = `
|
|
212
|
+
import { canIUse as canUse } from '${packageName}';
|
|
213
|
+
// 入参带有数字属性的对象路径
|
|
214
|
+
canUse('live-pusher.audio-reverb-type.4')
|
|
215
|
+
canUse('live-pusher.aspect.9:16')
|
|
216
|
+
`
|
|
217
|
+
const result = babelTransform(code)
|
|
218
|
+
expect(result?.code).toMatchSnapshot()
|
|
219
|
+
})
|
|
220
|
+
})
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ const plugin = function (babel) {
|
|
|
11
11
|
function canIUse(definition, scheme = '') {
|
|
12
12
|
if (!scheme)
|
|
13
13
|
return false;
|
|
14
|
-
const o = (0, lodash_1.
|
|
14
|
+
const o = (0, lodash_1.setWith)({}, scheme, true, Object);
|
|
15
15
|
return (0, lodash_1.isMatchWith)(definition, o, (a, b) => {
|
|
16
16
|
if (a === '*' || b === true)
|
|
17
17
|
return true;
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isMatchWith,
|
|
1
|
+
import { isMatchWith, setWith } from 'lodash'
|
|
2
2
|
|
|
3
3
|
import type * as BabelCore from '@babel/core'
|
|
4
4
|
|
|
@@ -22,7 +22,7 @@ const plugin = function (babel: typeof BabelCore): BabelCore.PluginObj<IState> {
|
|
|
22
22
|
|
|
23
23
|
function canIUse (definition, scheme = '') {
|
|
24
24
|
if (!scheme) return false
|
|
25
|
-
const o =
|
|
25
|
+
const o = setWith({}, scheme, true, Object)
|
|
26
26
|
return isMatchWith(definition, o, (a, b) => {
|
|
27
27
|
if (a === '*' || b === true) return true
|
|
28
28
|
})
|
|
@@ -60,7 +60,7 @@ const plugin = function (babel: typeof BabelCore): BabelCore.PluginObj<IState> {
|
|
|
60
60
|
this.apis = apis
|
|
61
61
|
},
|
|
62
62
|
visitor: {
|
|
63
|
-
ImportDeclaration (ast) {
|
|
63
|
+
ImportDeclaration (ast: BabelCore.NodePath<any>) {
|
|
64
64
|
if (ast.node.source.value !== this.packageName) return
|
|
65
65
|
|
|
66
66
|
ast.node.specifiers.forEach(node => {
|
|
@@ -91,7 +91,7 @@ const plugin = function (babel: typeof BabelCore): BabelCore.PluginObj<IState> {
|
|
|
91
91
|
}
|
|
92
92
|
})
|
|
93
93
|
},
|
|
94
|
-
MemberExpression (ast) {
|
|
94
|
+
MemberExpression (ast: BabelCore.NodePath<any>) {
|
|
95
95
|
/* 处理Taro.xxx */
|
|
96
96
|
const isTaro = t.isIdentifier(ast.node.object, { name: taroName })
|
|
97
97
|
const property = ast.node.property
|
|
@@ -110,7 +110,7 @@ const plugin = function (babel: typeof BabelCore): BabelCore.PluginObj<IState> {
|
|
|
110
110
|
|
|
111
111
|
// 同一api使用多次, 读取变量名
|
|
112
112
|
if (this.apis.has(propertyName)) {
|
|
113
|
-
const parentNode = ast.parent
|
|
113
|
+
const parentNode = ast.parent as BabelCore.types.AssignmentExpression
|
|
114
114
|
const isAssignment = t.isAssignmentExpression(parentNode) && parentNode.left === ast.node
|
|
115
115
|
|
|
116
116
|
if (!isAssignment) {
|
|
@@ -129,7 +129,7 @@ const plugin = function (babel: typeof BabelCore): BabelCore.PluginObj<IState> {
|
|
|
129
129
|
needDefault = true
|
|
130
130
|
}
|
|
131
131
|
},
|
|
132
|
-
CallExpression (ast) {
|
|
132
|
+
CallExpression (ast: BabelCore.NodePath<any>) {
|
|
133
133
|
if (!ast.scope.hasReference(this.canIUse)) return
|
|
134
134
|
const callee = ast.node.callee
|
|
135
135
|
if (t.isMemberExpression(callee) && t.isIdentifier(callee.object, { name: taroName })) {
|
|
@@ -188,7 +188,7 @@ const plugin = function (babel: typeof BabelCore): BabelCore.PluginObj<IState> {
|
|
|
188
188
|
ast.node.specifiers = namedImports
|
|
189
189
|
}
|
|
190
190
|
},
|
|
191
|
-
CallExpression (ast) {
|
|
191
|
+
CallExpression (ast: BabelCore.NodePath<any>) {
|
|
192
192
|
if (!invokedApis.has(that.canIUse)) return
|
|
193
193
|
const callee = ast.node.callee
|
|
194
194
|
const { name } = t.identifier(invokedApis.get(that.canIUse)!)
|