babel-plugin-transform-taroapi 3.7.0-alpha.2 → 3.7.0-alpha.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.
- package/__tests__/__snapshots__/index.spec.ts.snap +40 -10
- package/__tests__/index.spec.ts +185 -144
- package/dist/index.js +83 -16
- package/{jest.config.js → jest.config.ts} +5 -1
- package/package.json +4 -1
- package/src/index.ts +99 -20
- package/types.d.ts +0 -5
|
@@ -1,17 +1,47 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
|
-
exports[`should
|
|
3
|
+
exports[`babel-plugin-transform-taroapi should canIUse support! 1`] = `
|
|
4
|
+
"import { canIUse as _canUse } from '@tarojs/taro-h5';
|
|
5
|
+
// 对象的属性或方法
|
|
6
|
+
false;
|
|
7
|
+
false;
|
|
8
|
+
false;
|
|
9
|
+
false;
|
|
10
|
+
|
|
11
|
+
// 接口参数、回调或者返回值
|
|
12
|
+
true;
|
|
13
|
+
false;
|
|
14
|
+
false;
|
|
15
|
+
false;
|
|
16
|
+
false;
|
|
17
|
+
true;
|
|
18
|
+
|
|
19
|
+
// 组件的属性
|
|
20
|
+
true;
|
|
21
|
+
true;
|
|
22
|
+
false;"
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
exports[`babel-plugin-transform-taroapi should canIUse work or skip! 1`] = `
|
|
26
|
+
"import Taro from '@tarojs/taro-h5';
|
|
27
|
+
function canIUse() {}
|
|
28
|
+
false;
|
|
29
|
+
false;
|
|
30
|
+
canIUse('showToast.object.image');"
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
exports[`babel-plugin-transform-taroapi should leave other apis untouched 1`] = `
|
|
4
34
|
"import Taro from '@tarojs/taro-h5';
|
|
5
35
|
Taro.noop;"
|
|
6
36
|
`;
|
|
7
37
|
|
|
8
|
-
exports[`should move static apis under "Taro" 1`] = `
|
|
38
|
+
exports[`babel-plugin-transform-taroapi should move static apis under "Taro" 1`] = `
|
|
9
39
|
"import Taro from '@tarojs/taro-h5';
|
|
10
40
|
Taro.noop;
|
|
11
41
|
Taro.noop();"
|
|
12
42
|
`;
|
|
13
43
|
|
|
14
|
-
exports[`should not go wrong when using an api twice 1`] = `
|
|
44
|
+
exports[`babel-plugin-transform-taroapi should not go wrong when using an api twice 1`] = `
|
|
15
45
|
"import Taro, { createAnimation as _createAnimation } from '@tarojs/taro-h5';
|
|
16
46
|
const animation = _createAnimation({
|
|
17
47
|
duration: dura * 1000,
|
|
@@ -23,14 +53,14 @@ const resetAnimation = _createAnimation({
|
|
|
23
53
|
});"
|
|
24
54
|
`;
|
|
25
55
|
|
|
26
|
-
exports[`should not import taro
|
|
27
|
-
"import Taro, { createAnimation as _createAnimation, initPxTransform as _initPxTransform } from
|
|
56
|
+
exports[`babel-plugin-transform-taroapi should not import taro duplicity 1`] = `
|
|
57
|
+
"import Taro, { createAnimation as _createAnimation, initPxTransform as _initPxTransform } from '@tarojs/taro-h5';
|
|
28
58
|
Taro.Component;
|
|
29
59
|
_createAnimation();
|
|
30
60
|
_initPxTransform();"
|
|
31
61
|
`;
|
|
32
62
|
|
|
33
|
-
exports[`should preserve assignments in
|
|
63
|
+
exports[`babel-plugin-transform-taroapi should preserve assignments in left hands 1`] = `
|
|
34
64
|
"import Taro, { createAnimation as _createAnimation, request as _request } from '@tarojs/taro-h5';
|
|
35
65
|
let animation;
|
|
36
66
|
animation = _createAnimation({
|
|
@@ -44,18 +74,18 @@ Taro.request = '';
|
|
|
44
74
|
Taro['request'] = '';"
|
|
45
75
|
`;
|
|
46
76
|
|
|
47
|
-
exports[`should preserve default imports 1`] = `
|
|
77
|
+
exports[`babel-plugin-transform-taroapi should preserve default imports 1`] = `
|
|
48
78
|
"import Taro from '@tarojs/taro-h5';
|
|
49
79
|
console.log(Taro);"
|
|
50
80
|
`;
|
|
51
81
|
|
|
52
|
-
exports[`should support rename of imported names 1`] = `
|
|
82
|
+
exports[`babel-plugin-transform-taroapi should support rename of imported names 1`] = `
|
|
53
83
|
"// import { inject as mobxInject, observer as mobxObserver } from '@tarojs/mobx'
|
|
54
|
-
import Taro from
|
|
84
|
+
import Taro from '@tarojs/taro-h5';
|
|
55
85
|
export class Connected extends Taro.Component {}"
|
|
56
86
|
`;
|
|
57
87
|
|
|
58
|
-
exports[`should work! 1`] = `
|
|
88
|
+
exports[`babel-plugin-transform-taroapi should work! 1`] = `
|
|
59
89
|
"import Taro, { setStorage as _setStorage, initPxTransform as _initPxTransform, getStorage as _getStorage } from '@tarojs/taro-h5';
|
|
60
90
|
_initPxTransform(Taro.param);
|
|
61
91
|
_initPxTransform();
|
package/__tests__/index.spec.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import * as babel from '@babel/core'
|
|
2
2
|
import * as t from '@babel/types'
|
|
3
|
-
import * as
|
|
3
|
+
import * as definition from '@tarojs/plugin-platform-h5/dist/definition.json'
|
|
4
4
|
|
|
5
5
|
import plugin from '../src'
|
|
6
6
|
|
|
7
7
|
type ImportType = babel.types.ImportSpecifier | babel.types.ImportDefaultSpecifier | babel.types.ImportNamespaceSpecifier
|
|
8
8
|
|
|
9
|
+
const packageName = '@tarojs/taro-h5'
|
|
9
10
|
const pluginOptions = [
|
|
10
11
|
plugin,
|
|
11
12
|
{
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
packageName,
|
|
14
|
+
definition,
|
|
14
15
|
}
|
|
15
16
|
]
|
|
16
17
|
const getNamedImports = (importSpecifiers: (t.ImportSpecifier | t.ImportDefaultSpecifier | t.ImportNamespaceSpecifier)[]) => {
|
|
@@ -21,148 +22,188 @@ const getNamedImports = (importSpecifiers: (t.ImportSpecifier | t.ImportDefaultS
|
|
|
21
22
|
return prev
|
|
22
23
|
}, new Set())
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const ast = result.ast as t.File
|
|
49
|
-
const body = ast.program.body as [t.ImportDeclaration, t.ExpressionStatement]
|
|
50
|
-
expect(t.isImportDeclaration(body[0])).toBeTruthy()
|
|
51
|
-
expect(t.isExpressionStatement(body[1])).toBeTruthy()
|
|
52
|
-
const defaultImport = body[0].specifiers.find(v => t.isImportDefaultSpecifier(v)) as ImportType
|
|
53
|
-
expect(defaultImport).toBeTruthy()
|
|
54
|
-
|
|
55
|
-
const taroName = defaultImport.local.name
|
|
56
|
-
const namedImports = getNamedImports(body[0].specifiers)
|
|
57
|
-
expect(namedImports).toEqual(new Set())
|
|
58
|
-
expect(t.isMemberExpression(body[1].expression)).toBeTruthy()
|
|
59
|
-
|
|
60
|
-
const obj = t.memberExpression(
|
|
61
|
-
t.identifier(taroName),
|
|
62
|
-
t.identifier('noop'),
|
|
63
|
-
)
|
|
64
|
-
delete obj.optional
|
|
65
|
-
|
|
66
|
-
expect((body[1].expression as t.MemberExpression)).toMatchObject(obj)
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('should move static apis under "Taro"', function () {
|
|
70
|
-
const code = `
|
|
71
|
-
import { noop } from '@tarojs/taro-h5';
|
|
72
|
-
noop;
|
|
73
|
-
noop();
|
|
74
|
-
`
|
|
75
|
-
|
|
76
|
-
const result = babel.transform(code, { ast: true, configFile: false, plugins: [pluginOptions] })
|
|
77
|
-
expect(result?.code).toMatchSnapshot()
|
|
78
|
-
|
|
79
|
-
const ast = result?.ast as t.File
|
|
80
|
-
const body = ast.program.body as [t.ImportDeclaration, t.ExpressionStatement]
|
|
81
|
-
expect(t.isImportDeclaration(body[0])).toBeTruthy()
|
|
82
|
-
expect(t.isExpressionStatement(body[1])).toBeTruthy()
|
|
83
|
-
const defaultImport = body[0].specifiers.find(v => t.isImportDefaultSpecifier(v))
|
|
84
|
-
expect(defaultImport).toBeTruthy()
|
|
85
|
-
|
|
86
|
-
const taroName = defaultImport!.local.name
|
|
87
|
-
let memberExpression: any = body[1].expression
|
|
88
|
-
if (t.isCallExpression(body[1])) {
|
|
89
|
-
memberExpression = ((body[1] as t.ExpressionStatement).expression as t.CallExpression).callee
|
|
90
|
-
}
|
|
91
|
-
expect(memberExpression).toMatchObject(t.memberExpression(
|
|
92
|
-
t.identifier(taroName),
|
|
93
|
-
t.identifier('noop')
|
|
94
|
-
))
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('should not import taro duplicatly', function () {
|
|
98
|
-
const code = `
|
|
99
|
-
import { Component } from "@tarojs/taro-h5";
|
|
100
|
-
import Taro from '@tarojs/taro-h5';
|
|
101
|
-
Component
|
|
102
|
-
Taro.createAnimation()
|
|
103
|
-
Taro.initPxTransform()
|
|
104
|
-
`
|
|
105
|
-
|
|
106
|
-
const result = babel.transform(code, { ast: true, configFile: false, plugins: [pluginOptions] })
|
|
107
|
-
expect(result?.code).toMatchSnapshot()
|
|
108
|
-
const ast = result?.ast as t.File
|
|
109
|
-
const body = ast.program.body as [t.ImportDeclaration, t.ExpressionStatement, t.ExpressionStatement]
|
|
110
|
-
expect(t.isImportDeclaration(body[0])).toBeTruthy()
|
|
111
|
-
expect(t.isExpressionStatement(body[1])).toBeTruthy()
|
|
112
|
-
expect(t.isExpressionStatement(body[2])).toBeTruthy()
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
it('should not go wrong when using an api twice', function () {
|
|
116
|
-
const code = `
|
|
117
|
-
import Taro from '@tarojs/taro-h5';
|
|
118
|
-
const animation = Taro.createAnimation({
|
|
119
|
-
duration: dura * 1000,
|
|
120
|
-
timingFunction: 'linear'
|
|
121
|
-
})
|
|
122
|
-
const resetAnimation = Taro.createAnimation({
|
|
123
|
-
duration: 0,
|
|
124
|
-
timingFunction: 'linear'
|
|
125
|
-
})
|
|
126
|
-
`
|
|
127
|
-
expect(() => {
|
|
128
|
-
const result = babel.transform(code, { ast: true, configFile: false, plugins: [pluginOptions] })
|
|
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)
|
|
129
48
|
expect(result?.code).toMatchSnapshot()
|
|
130
|
-
}).not.toThrowError()
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('should preserve default imports', function () {
|
|
134
|
-
const code = `
|
|
135
|
-
import Taro from '@tarojs/taro-h5'
|
|
136
|
-
console.log(Taro)
|
|
137
|
-
`
|
|
138
|
-
const result = babel.transform(code, { ast: true, configFile: false, plugins: [pluginOptions] })
|
|
139
|
-
expect(result?.code).toMatchSnapshot()
|
|
140
|
-
})
|
|
141
49
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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()
|
|
159
80
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
+
})
|
|
168
209
|
})
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const lodash_1 = require("lodash");
|
|
3
4
|
const plugin = function (babel) {
|
|
4
5
|
const t = babel.types;
|
|
5
6
|
// 这些变量需要在每个 program 里重置
|
|
@@ -7,13 +8,43 @@ const plugin = function (babel) {
|
|
|
7
8
|
let taroName;
|
|
8
9
|
let needDefault;
|
|
9
10
|
let referTaro;
|
|
11
|
+
function canIUse(definition, scheme = '') {
|
|
12
|
+
if (!scheme)
|
|
13
|
+
return false;
|
|
14
|
+
const o = (0, lodash_1.set)({}, scheme, true);
|
|
15
|
+
return (0, lodash_1.isMatchWith)(definition, o, (a, b) => {
|
|
16
|
+
if (a === '*' || b === true)
|
|
17
|
+
return true;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function replaceCanIUse(ast, definition) {
|
|
21
|
+
const args = ast.node.arguments;
|
|
22
|
+
if (args.length < 1)
|
|
23
|
+
return;
|
|
24
|
+
// Note: 暂不考虑其他类型的参数映射
|
|
25
|
+
if (t.isStringLiteral(args[0])) {
|
|
26
|
+
const isSupported = canIUse(definition, args[0].value);
|
|
27
|
+
ast.replaceInline(t.booleanLiteral(isSupported));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
10
30
|
return {
|
|
11
31
|
name: 'babel-plugin-transform-taro-api',
|
|
32
|
+
pre() {
|
|
33
|
+
const { opts = {} } = this;
|
|
34
|
+
const { apis = new Set(), bindingName = 'Taro', packageName = '@tarojs/taro-h5', definition = {} } = opts;
|
|
35
|
+
this.definition = Object.assign(Object.assign(Object.assign({}, definition.apis), definition.components), { [this.canIUse]: '*' });
|
|
36
|
+
this.bindingName = bindingName;
|
|
37
|
+
this.packageName = packageName;
|
|
38
|
+
this.canIUse = 'canIUse';
|
|
39
|
+
if (apis.size < 1) {
|
|
40
|
+
apis.add(this.canIUse);
|
|
41
|
+
Object.keys(definition.apis || {}).forEach(key => apis.add(key));
|
|
42
|
+
}
|
|
43
|
+
this.apis = apis;
|
|
44
|
+
},
|
|
12
45
|
visitor: {
|
|
13
|
-
ImportDeclaration(ast
|
|
14
|
-
|
|
15
|
-
const apis = state.opts.apis;
|
|
16
|
-
if (ast.node.source.value !== packageName)
|
|
46
|
+
ImportDeclaration(ast) {
|
|
47
|
+
if (ast.node.source.value !== this.packageName)
|
|
17
48
|
return;
|
|
18
49
|
ast.node.specifiers.forEach(node => {
|
|
19
50
|
if (t.isImportDefaultSpecifier(node)) {
|
|
@@ -21,8 +52,9 @@ const plugin = function (babel) {
|
|
|
21
52
|
taroName = node.local.name;
|
|
22
53
|
}
|
|
23
54
|
else if (t.isImportSpecifier(node)) {
|
|
24
|
-
const
|
|
25
|
-
|
|
55
|
+
const { imported } = node;
|
|
56
|
+
const propertyName = t.isIdentifier(imported) ? imported.name : imported.value;
|
|
57
|
+
if (this.apis.has(propertyName)) { // 记录api名字
|
|
26
58
|
ast.scope.rename(node.local.name);
|
|
27
59
|
invokedApis.set(propertyName, node.local.name);
|
|
28
60
|
}
|
|
@@ -39,9 +71,8 @@ const plugin = function (babel) {
|
|
|
39
71
|
}
|
|
40
72
|
});
|
|
41
73
|
},
|
|
42
|
-
MemberExpression(ast
|
|
74
|
+
MemberExpression(ast) {
|
|
43
75
|
/* 处理Taro.xxx */
|
|
44
|
-
const apis = state.opts.apis;
|
|
45
76
|
const isTaro = t.isIdentifier(ast.node.object, { name: taroName });
|
|
46
77
|
const property = ast.node.property;
|
|
47
78
|
let propertyName = null;
|
|
@@ -56,7 +87,7 @@ const plugin = function (babel) {
|
|
|
56
87
|
if (!propertyName)
|
|
57
88
|
return;
|
|
58
89
|
// 同一api使用多次, 读取变量名
|
|
59
|
-
if (apis.has(propertyName)) {
|
|
90
|
+
if (this.apis.has(propertyName)) {
|
|
60
91
|
const parentNode = ast.parent;
|
|
61
92
|
const isAssignment = t.isAssignmentExpression(parentNode) && parentNode.left === ast.node;
|
|
62
93
|
if (!isAssignment) {
|
|
@@ -77,16 +108,42 @@ const plugin = function (babel) {
|
|
|
77
108
|
needDefault = true;
|
|
78
109
|
}
|
|
79
110
|
},
|
|
111
|
+
CallExpression(ast) {
|
|
112
|
+
if (!ast.scope.hasReference(this.canIUse))
|
|
113
|
+
return;
|
|
114
|
+
const callee = ast.node.callee;
|
|
115
|
+
if (t.isMemberExpression(callee) && t.isIdentifier(callee.object, { name: taroName })) {
|
|
116
|
+
let propertyName = null;
|
|
117
|
+
let propName = 'name';
|
|
118
|
+
// 兼容一下 Taro['xxx']
|
|
119
|
+
if (t.isStringLiteral(callee.property)) {
|
|
120
|
+
propName = 'value';
|
|
121
|
+
}
|
|
122
|
+
propertyName = callee.property[propName];
|
|
123
|
+
if (propertyName === this.canIUse) {
|
|
124
|
+
// Taro.canIUse or Taro['canIUse']
|
|
125
|
+
replaceCanIUse(ast, this.definition);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else if (invokedApis.has(this.canIUse)) {
|
|
129
|
+
const { name } = t.identifier(invokedApis.get(this.canIUse));
|
|
130
|
+
const isCanIUse = t.isIdentifier(callee, { name });
|
|
131
|
+
// canIUse as _canIUse
|
|
132
|
+
if (isCanIUse)
|
|
133
|
+
replaceCanIUse(ast, this.definition);
|
|
134
|
+
}
|
|
135
|
+
},
|
|
80
136
|
Program: {
|
|
81
137
|
enter(ast) {
|
|
82
138
|
needDefault = false;
|
|
83
139
|
referTaro = [];
|
|
84
140
|
invokedApis.clear();
|
|
85
|
-
taroName = ast.scope.getBinding(
|
|
86
|
-
? ast.scope.generateUid(
|
|
87
|
-
:
|
|
141
|
+
taroName = ast.scope.getBinding(this.bindingName)
|
|
142
|
+
? ast.scope.generateUid(this.bindingName)
|
|
143
|
+
: this.bindingName;
|
|
88
144
|
},
|
|
89
|
-
exit(ast
|
|
145
|
+
exit(ast) {
|
|
146
|
+
const that = this;
|
|
90
147
|
// 防止重复引入
|
|
91
148
|
let isTaroApiImported = false;
|
|
92
149
|
referTaro.forEach(node => {
|
|
@@ -94,8 +151,7 @@ const plugin = function (babel) {
|
|
|
94
151
|
});
|
|
95
152
|
ast.traverse({
|
|
96
153
|
ImportDeclaration(ast) {
|
|
97
|
-
const
|
|
98
|
-
const isImportingTaroApi = ast.node.source.value === packageName;
|
|
154
|
+
const isImportingTaroApi = ast.node.source.value === that.packageName;
|
|
99
155
|
if (!isImportingTaroApi)
|
|
100
156
|
return;
|
|
101
157
|
if (isTaroApiImported)
|
|
@@ -113,7 +169,18 @@ const plugin = function (babel) {
|
|
|
113
169
|
else {
|
|
114
170
|
ast.node.specifiers = namedImports;
|
|
115
171
|
}
|
|
116
|
-
}
|
|
172
|
+
},
|
|
173
|
+
CallExpression(ast) {
|
|
174
|
+
if (!invokedApis.has(that.canIUse))
|
|
175
|
+
return;
|
|
176
|
+
const callee = ast.node.callee;
|
|
177
|
+
const { name } = t.identifier(invokedApis.get(that.canIUse));
|
|
178
|
+
const isCanIUse = t.isIdentifier(callee, { name });
|
|
179
|
+
if (isCanIUse) {
|
|
180
|
+
// canIUse as _use
|
|
181
|
+
replaceCanIUse(ast, that.definition);
|
|
182
|
+
}
|
|
183
|
+
},
|
|
117
184
|
});
|
|
118
185
|
}
|
|
119
186
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Config } from 'jest'
|
|
2
|
+
|
|
3
|
+
const config: Config = {
|
|
2
4
|
collectCoverage: false,
|
|
3
5
|
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'node'],
|
|
4
6
|
preset: 'ts-jest',
|
|
@@ -18,3 +20,5 @@ module.exports = {
|
|
|
18
20
|
},
|
|
19
21
|
transformIgnorePatterns: ['<rootDir>/node_modules/']
|
|
20
22
|
}
|
|
23
|
+
|
|
24
|
+
export default config
|
package/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "babel-plugin-transform-taroapi",
|
|
3
|
-
"version": "3.7.0-alpha.
|
|
3
|
+
"version": "3.7.0-alpha.3",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"lodash": "^4.17.21"
|
|
7
|
+
},
|
|
5
8
|
"devDependencies": {
|
|
6
9
|
"@babel/core": "^7.14.5",
|
|
7
10
|
"@babel/types": "^7.14.5",
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { isMatchWith, set } from 'lodash'
|
|
2
|
+
|
|
3
|
+
import type * as BabelCore from '@babel/core'
|
|
4
|
+
|
|
5
|
+
interface IState extends BabelCore.PluginPass {
|
|
6
|
+
apis: Set<string>
|
|
7
|
+
bindingName: string
|
|
8
|
+
packageName: string
|
|
9
|
+
canIUse: string
|
|
10
|
+
definition: Record<string, any>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const plugin = function (babel: typeof BabelCore): BabelCore.PluginObj<IState> {
|
|
4
14
|
const t = babel.types
|
|
5
15
|
|
|
6
16
|
// 这些变量需要在每个 program 里重置
|
|
@@ -10,21 +20,57 @@ const plugin = function (babel: {
|
|
|
10
20
|
|
|
11
21
|
let referTaro: any[]
|
|
12
22
|
|
|
23
|
+
function canIUse (definition, scheme = '') {
|
|
24
|
+
if (!scheme) return false
|
|
25
|
+
const o = set({}, scheme, true)
|
|
26
|
+
return isMatchWith(definition, o, (a, b) => {
|
|
27
|
+
if (a === '*' || b === true) return true
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function replaceCanIUse (ast: BabelCore.NodePath<BabelCore.types.CallExpression>, definition) {
|
|
32
|
+
const args = ast.node.arguments
|
|
33
|
+
|
|
34
|
+
if (args.length < 1) return
|
|
35
|
+
|
|
36
|
+
// Note: 暂不考虑其他类型的参数映射
|
|
37
|
+
if (t.isStringLiteral(args[0])) {
|
|
38
|
+
const isSupported = canIUse(definition, args[0].value)
|
|
39
|
+
ast.replaceInline(t.booleanLiteral(isSupported))
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
13
43
|
return {
|
|
14
44
|
name: 'babel-plugin-transform-taro-api',
|
|
45
|
+
pre () {
|
|
46
|
+
const { opts = {} as any } = this
|
|
47
|
+
const { apis = new Set<string>(), bindingName = 'Taro', packageName = '@tarojs/taro-h5', definition = {} } = opts
|
|
48
|
+
this.definition = {
|
|
49
|
+
...definition.apis,
|
|
50
|
+
...definition.components,
|
|
51
|
+
[this.canIUse]: '*'
|
|
52
|
+
}
|
|
53
|
+
this.bindingName = bindingName
|
|
54
|
+
this.packageName = packageName
|
|
55
|
+
this.canIUse = 'canIUse'
|
|
56
|
+
if (apis.size < 1) {
|
|
57
|
+
apis.add(this.canIUse)
|
|
58
|
+
Object.keys(definition.apis || {}).forEach(key => apis.add(key))
|
|
59
|
+
}
|
|
60
|
+
this.apis = apis
|
|
61
|
+
},
|
|
15
62
|
visitor: {
|
|
16
|
-
ImportDeclaration (ast
|
|
17
|
-
|
|
18
|
-
const apis = state.opts.apis
|
|
19
|
-
if (ast.node.source.value !== packageName) return
|
|
63
|
+
ImportDeclaration (ast) {
|
|
64
|
+
if (ast.node.source.value !== this.packageName) return
|
|
20
65
|
|
|
21
66
|
ast.node.specifiers.forEach(node => {
|
|
22
67
|
if (t.isImportDefaultSpecifier(node)) {
|
|
23
68
|
needDefault = true
|
|
24
69
|
taroName = node.local.name
|
|
25
70
|
} else if (t.isImportSpecifier(node)) {
|
|
26
|
-
const
|
|
27
|
-
|
|
71
|
+
const { imported } = node
|
|
72
|
+
const propertyName = t.isIdentifier(imported) ? imported.name : imported.value
|
|
73
|
+
if (this.apis.has(propertyName)) { // 记录api名字
|
|
28
74
|
ast.scope.rename(node.local.name)
|
|
29
75
|
invokedApis.set(propertyName, node.local.name)
|
|
30
76
|
} else { // 如果是未实现的api 改成Taro.xxx
|
|
@@ -45,9 +91,8 @@ const plugin = function (babel: {
|
|
|
45
91
|
}
|
|
46
92
|
})
|
|
47
93
|
},
|
|
48
|
-
MemberExpression (ast
|
|
94
|
+
MemberExpression (ast) {
|
|
49
95
|
/* 处理Taro.xxx */
|
|
50
|
-
const apis = state.opts.apis
|
|
51
96
|
const isTaro = t.isIdentifier(ast.node.object, { name: taroName })
|
|
52
97
|
const property = ast.node.property
|
|
53
98
|
let propertyName: string | null = null
|
|
@@ -64,12 +109,12 @@ const plugin = function (babel: {
|
|
|
64
109
|
if (!propertyName) return
|
|
65
110
|
|
|
66
111
|
// 同一api使用多次, 读取变量名
|
|
67
|
-
if (apis.has(propertyName)) {
|
|
112
|
+
if (this.apis.has(propertyName)) {
|
|
68
113
|
const parentNode = ast.parent
|
|
69
114
|
const isAssignment = t.isAssignmentExpression(parentNode) && parentNode.left === ast.node
|
|
70
115
|
|
|
71
116
|
if (!isAssignment) {
|
|
72
|
-
let identifier:
|
|
117
|
+
let identifier: BabelCore.types.Identifier
|
|
73
118
|
if (invokedApis.has(propertyName)) {
|
|
74
119
|
identifier = t.identifier(invokedApis.get(propertyName)!)
|
|
75
120
|
} else {
|
|
@@ -84,17 +129,41 @@ const plugin = function (babel: {
|
|
|
84
129
|
needDefault = true
|
|
85
130
|
}
|
|
86
131
|
},
|
|
132
|
+
CallExpression (ast) {
|
|
133
|
+
if (!ast.scope.hasReference(this.canIUse)) return
|
|
134
|
+
const callee = ast.node.callee
|
|
135
|
+
if (t.isMemberExpression(callee) && t.isIdentifier(callee.object, { name: taroName })) {
|
|
136
|
+
let propertyName: string | null = null
|
|
137
|
+
let propName = 'name'
|
|
138
|
+
|
|
139
|
+
// 兼容一下 Taro['xxx']
|
|
140
|
+
if (t.isStringLiteral(callee.property)) {
|
|
141
|
+
propName = 'value'
|
|
142
|
+
}
|
|
143
|
+
propertyName = callee.property[propName]
|
|
144
|
+
if (propertyName === this.canIUse) {
|
|
145
|
+
// Taro.canIUse or Taro['canIUse']
|
|
146
|
+
replaceCanIUse(ast, this.definition)
|
|
147
|
+
}
|
|
148
|
+
} else if (invokedApis.has(this.canIUse)) {
|
|
149
|
+
const { name } = t.identifier(invokedApis.get(this.canIUse)!)
|
|
150
|
+
const isCanIUse = t.isIdentifier(callee, { name })
|
|
151
|
+
// canIUse as _canIUse
|
|
152
|
+
if (isCanIUse) replaceCanIUse(ast, this.definition)
|
|
153
|
+
}
|
|
154
|
+
},
|
|
87
155
|
Program: {
|
|
88
156
|
enter (ast) {
|
|
89
157
|
needDefault = false
|
|
90
158
|
referTaro = []
|
|
91
159
|
invokedApis.clear()
|
|
92
160
|
|
|
93
|
-
taroName = ast.scope.getBinding(
|
|
94
|
-
? ast.scope.generateUid(
|
|
95
|
-
:
|
|
161
|
+
taroName = ast.scope.getBinding(this.bindingName)
|
|
162
|
+
? ast.scope.generateUid(this.bindingName)
|
|
163
|
+
: this.bindingName
|
|
96
164
|
},
|
|
97
|
-
exit (ast
|
|
165
|
+
exit (ast) {
|
|
166
|
+
const that = this
|
|
98
167
|
// 防止重复引入
|
|
99
168
|
let isTaroApiImported = false
|
|
100
169
|
referTaro.forEach(node => {
|
|
@@ -103,8 +172,7 @@ const plugin = function (babel: {
|
|
|
103
172
|
|
|
104
173
|
ast.traverse({
|
|
105
174
|
ImportDeclaration (ast) {
|
|
106
|
-
const
|
|
107
|
-
const isImportingTaroApi = ast.node.source.value === packageName
|
|
175
|
+
const isImportingTaroApi = ast.node.source.value === that.packageName
|
|
108
176
|
if (!isImportingTaroApi) return
|
|
109
177
|
if (isTaroApiImported) return ast.remove()
|
|
110
178
|
isTaroApiImported = true
|
|
@@ -119,11 +187,22 @@ const plugin = function (babel: {
|
|
|
119
187
|
} else {
|
|
120
188
|
ast.node.specifiers = namedImports
|
|
121
189
|
}
|
|
122
|
-
}
|
|
190
|
+
},
|
|
191
|
+
CallExpression (ast) {
|
|
192
|
+
if (!invokedApis.has(that.canIUse)) return
|
|
193
|
+
const callee = ast.node.callee
|
|
194
|
+
const { name } = t.identifier(invokedApis.get(that.canIUse)!)
|
|
195
|
+
const isCanIUse = t.isIdentifier(callee, { name })
|
|
196
|
+
if (isCanIUse) {
|
|
197
|
+
// canIUse as _use
|
|
198
|
+
replaceCanIUse(ast, that.definition)
|
|
199
|
+
}
|
|
200
|
+
},
|
|
123
201
|
})
|
|
124
202
|
}
|
|
125
203
|
}
|
|
126
204
|
}
|
|
127
205
|
}
|
|
128
206
|
}
|
|
207
|
+
|
|
129
208
|
export default plugin
|