@mpxjs/webpack-plugin 2.9.39 → 2.9.41-react.0
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/lib/config.js +63 -97
- package/lib/dependencies/{RecordVueContentDependency.js → RecordLoaderContentDependency.js} +5 -5
- package/lib/dependencies/ResolveDependency.js +2 -2
- package/lib/helpers.js +5 -1
- package/lib/index.js +26 -21
- package/lib/loader.js +43 -97
- package/lib/native-loader.js +0 -1
- package/lib/platform/index.js +3 -0
- package/lib/platform/style/wx/index.js +414 -0
- package/lib/platform/template/wx/component-config/button.js +36 -0
- package/lib/platform/template/wx/component-config/image.js +15 -0
- package/lib/platform/template/wx/component-config/input.js +41 -0
- package/lib/platform/template/wx/component-config/scroll-view.js +27 -1
- package/lib/platform/template/wx/component-config/swiper-item.js +13 -1
- package/lib/platform/template/wx/component-config/swiper.js +25 -1
- package/lib/platform/template/wx/component-config/text.js +15 -0
- package/lib/platform/template/wx/component-config/textarea.js +39 -0
- package/lib/platform/template/wx/component-config/unsupported.js +18 -0
- package/lib/platform/template/wx/component-config/view.js +14 -0
- package/lib/platform/template/wx/index.js +88 -4
- package/lib/react/index.js +104 -0
- package/lib/react/processJSON.js +361 -0
- package/lib/react/processMainScript.js +21 -0
- package/lib/react/processScript.js +70 -0
- package/lib/react/processStyles.js +69 -0
- package/lib/react/processTemplate.js +153 -0
- package/lib/react/script-helper.js +133 -0
- package/lib/react/style-helper.js +91 -0
- package/lib/resolver/PackageEntryPlugin.js +1 -0
- package/lib/runtime/components/react/event.config.ts +32 -0
- package/lib/runtime/components/react/getInnerListeners.ts +289 -0
- package/lib/runtime/components/react/getInnerListeners.type.ts +68 -0
- package/lib/runtime/components/react/mpx-button.tsx +402 -0
- package/lib/runtime/components/react/mpx-image/index.tsx +351 -0
- package/lib/runtime/components/react/mpx-image/svg.tsx +21 -0
- package/lib/runtime/components/react/mpx-input.tsx +389 -0
- package/lib/runtime/components/react/mpx-scroll-view.tsx +412 -0
- package/lib/runtime/components/react/mpx-swiper/carouse.tsx +398 -0
- package/lib/runtime/components/react/mpx-swiper/index.tsx +68 -0
- package/lib/runtime/components/react/mpx-swiper/type.ts +69 -0
- package/lib/runtime/components/react/mpx-swiper-item.tsx +42 -0
- package/lib/runtime/components/react/mpx-text.tsx +106 -0
- package/lib/runtime/components/react/mpx-textarea.tsx +46 -0
- package/lib/runtime/components/react/mpx-view.tsx +397 -0
- package/lib/runtime/components/react/useNodesRef.ts +39 -0
- package/lib/runtime/components/react/utils.ts +92 -0
- package/lib/runtime/optionProcessorReact.d.ts +9 -0
- package/lib/runtime/optionProcessorReact.js +21 -0
- package/lib/runtime/stringify.wxs +3 -8
- package/lib/style-compiler/index.js +2 -1
- package/lib/template-compiler/compiler.js +293 -38
- package/lib/template-compiler/gen-node-react.js +95 -0
- package/lib/template-compiler/index.js +15 -24
- package/lib/utils/env.js +17 -0
- package/lib/utils/make-map.js +1 -1
- package/lib/utils/shallow-stringify.js +12 -12
- package/lib/web/index.js +123 -0
- package/lib/web/processJSON.js +3 -3
- package/lib/web/processMainScript.js +25 -23
- package/lib/web/processScript.js +12 -16
- package/lib/web/processTemplate.js +13 -12
- package/lib/web/script-helper.js +14 -22
- package/package.json +4 -3
package/lib/loader.js
CHANGED
|
@@ -5,22 +5,19 @@ const parseRequest = require('./utils/parse-request')
|
|
|
5
5
|
const { matchCondition } = require('./utils/match-condition')
|
|
6
6
|
const addQuery = require('./utils/add-query')
|
|
7
7
|
const async = require('async')
|
|
8
|
-
const processJSON = require('./web/processJSON')
|
|
9
|
-
const processScript = require('./web/processScript')
|
|
10
|
-
const processStyles = require('./web/processStyles')
|
|
11
|
-
const processTemplate = require('./web/processTemplate')
|
|
12
8
|
const getJSONContent = require('./utils/get-json-content')
|
|
13
9
|
const normalize = require('./utils/normalize')
|
|
14
10
|
const getEntryName = require('./utils/get-entry-name')
|
|
15
11
|
const AppEntryDependency = require('./dependencies/AppEntryDependency')
|
|
16
12
|
const RecordResourceMapDependency = require('./dependencies/RecordResourceMapDependency')
|
|
17
|
-
const RecordVueContentDependency = require('./dependencies/RecordVueContentDependency')
|
|
18
13
|
const CommonJsVariableDependency = require('./dependencies/CommonJsVariableDependency')
|
|
19
14
|
const DynamicEntryDependency = require('./dependencies/DynamicEntryDependency')
|
|
20
15
|
const tsWatchRunLoaderFilter = require('./utils/ts-loader-watch-run-loader-filter')
|
|
21
16
|
const { MPX_APP_MODULE_ID } = require('./utils/const')
|
|
17
|
+
const { isReact } = require('./utils/env')
|
|
22
18
|
const path = require('path')
|
|
23
|
-
const
|
|
19
|
+
const processWeb = require('./web')
|
|
20
|
+
const processReact = require('./react')
|
|
24
21
|
const getRulesRunner = require('./platform')
|
|
25
22
|
const genMpxCustomElement = require('./runtime-render/gen-mpx-custom-element')
|
|
26
23
|
|
|
@@ -105,7 +102,6 @@ module.exports = function (content) {
|
|
|
105
102
|
getRequire
|
|
106
103
|
} = createHelpers(loaderContext)
|
|
107
104
|
|
|
108
|
-
let output = ''
|
|
109
105
|
const callback = this.async()
|
|
110
106
|
|
|
111
107
|
async.waterfall([
|
|
@@ -157,98 +153,47 @@ module.exports = function (content) {
|
|
|
157
153
|
}
|
|
158
154
|
// 处理mode为web时输出vue格式文件
|
|
159
155
|
if (mode === 'web') {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
tabBarStr: jsonRes.tabBarStr,
|
|
178
|
-
localPagesMap: jsonRes.localPagesMap,
|
|
179
|
-
resource: this.resource
|
|
180
|
-
}, callback)
|
|
181
|
-
}
|
|
182
|
-
], (err, scriptRes) => {
|
|
183
|
-
if (err) return callback(err)
|
|
184
|
-
this.loaderIndex = -1
|
|
185
|
-
return callback(null, scriptRes.output)
|
|
186
|
-
})
|
|
187
|
-
}
|
|
188
|
-
// 通过RecordVueContentDependency和vueContentCache确保子request不再重复生成vueContent
|
|
189
|
-
const cacheContent = mpx.vueContentCache.get(filePath)
|
|
190
|
-
if (cacheContent) return callback(null, cacheContent)
|
|
191
|
-
|
|
192
|
-
return async.waterfall([
|
|
193
|
-
(callback) => {
|
|
194
|
-
async.parallel([
|
|
195
|
-
(callback) => {
|
|
196
|
-
processTemplate(parts.template, {
|
|
197
|
-
loaderContext,
|
|
198
|
-
hasScoped,
|
|
199
|
-
hasComment,
|
|
200
|
-
isNative,
|
|
201
|
-
srcMode,
|
|
202
|
-
moduleId,
|
|
203
|
-
ctorType,
|
|
204
|
-
usingComponents,
|
|
205
|
-
componentGenerics
|
|
206
|
-
}, callback)
|
|
207
|
-
},
|
|
208
|
-
(callback) => {
|
|
209
|
-
processStyles(parts.styles, {
|
|
210
|
-
ctorType,
|
|
211
|
-
autoScope,
|
|
212
|
-
moduleId
|
|
213
|
-
}, callback)
|
|
214
|
-
},
|
|
215
|
-
(callback) => {
|
|
216
|
-
processJSON(parts.json, {
|
|
217
|
-
loaderContext,
|
|
218
|
-
pagesMap,
|
|
219
|
-
componentsMap
|
|
220
|
-
}, callback)
|
|
221
|
-
}
|
|
222
|
-
], (err, res) => {
|
|
223
|
-
callback(err, res)
|
|
224
|
-
})
|
|
225
|
-
},
|
|
226
|
-
([templateRes, stylesRes, jsonRes], callback) => {
|
|
227
|
-
output += templateRes.output
|
|
228
|
-
output += stylesRes.output
|
|
229
|
-
output += jsonRes.output
|
|
230
|
-
processScript(parts.script, {
|
|
231
|
-
loaderContext,
|
|
232
|
-
ctorType,
|
|
233
|
-
srcMode,
|
|
234
|
-
moduleId,
|
|
235
|
-
isProduction,
|
|
236
|
-
componentGenerics,
|
|
237
|
-
jsonConfig: jsonRes.jsonObj,
|
|
238
|
-
outputPath: queryObj.outputPath || '',
|
|
239
|
-
builtInComponentsMap: templateRes.builtInComponentsMap,
|
|
240
|
-
genericsInfo: templateRes.genericsInfo,
|
|
241
|
-
wxsModuleMap: templateRes.wxsModuleMap,
|
|
242
|
-
localComponentsMap: jsonRes.localComponentsMap
|
|
243
|
-
}, callback)
|
|
244
|
-
}
|
|
245
|
-
], (err, scriptRes) => {
|
|
246
|
-
if (err) return callback(err)
|
|
247
|
-
output += scriptRes.output
|
|
248
|
-
this._module.addPresentationalDependency(new RecordVueContentDependency(filePath, output))
|
|
249
|
-
callback(null, output)
|
|
156
|
+
return processWeb({
|
|
157
|
+
parts,
|
|
158
|
+
loaderContext,
|
|
159
|
+
pagesMap,
|
|
160
|
+
componentsMap,
|
|
161
|
+
queryObj,
|
|
162
|
+
ctorType,
|
|
163
|
+
srcMode,
|
|
164
|
+
moduleId,
|
|
165
|
+
isProduction,
|
|
166
|
+
hasScoped,
|
|
167
|
+
hasComment,
|
|
168
|
+
isNative,
|
|
169
|
+
usingComponents,
|
|
170
|
+
componentGenerics,
|
|
171
|
+
autoScope,
|
|
172
|
+
callback
|
|
250
173
|
})
|
|
251
174
|
}
|
|
175
|
+
// 处理mode为react时输出js格式文件
|
|
176
|
+
if (isReact(mode)) {
|
|
177
|
+
return processReact({
|
|
178
|
+
parts,
|
|
179
|
+
loaderContext,
|
|
180
|
+
pagesMap,
|
|
181
|
+
componentsMap,
|
|
182
|
+
queryObj,
|
|
183
|
+
ctorType,
|
|
184
|
+
srcMode,
|
|
185
|
+
moduleId,
|
|
186
|
+
isProduction,
|
|
187
|
+
hasScoped,
|
|
188
|
+
hasComment,
|
|
189
|
+
isNative,
|
|
190
|
+
usingComponents,
|
|
191
|
+
componentGenerics,
|
|
192
|
+
autoScope,
|
|
193
|
+
callback
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
|
|
252
197
|
const moduleGraph = this._compilation.moduleGraph
|
|
253
198
|
|
|
254
199
|
const issuer = moduleGraph.getIssuer(this._module)
|
|
@@ -257,6 +202,7 @@ module.exports = function (content) {
|
|
|
257
202
|
return callback(new Error(`Current ${ctorType} [${this.resourcePath}] is issued by [${issuer.resource}], which is not allowed!`))
|
|
258
203
|
}
|
|
259
204
|
|
|
205
|
+
let output = ''
|
|
260
206
|
// 注入模块id及资源路径
|
|
261
207
|
output += `global.currentModuleId = ${JSON.stringify(moduleId)}\n`
|
|
262
208
|
if (!isProduction) {
|
package/lib/native-loader.js
CHANGED
package/lib/platform/index.js
CHANGED
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
const { hump2dash } = require('../../../utils/hump-dash')
|
|
2
|
+
|
|
3
|
+
module.exports = function getSpec ({ warn, error }) {
|
|
4
|
+
// React Native 双端都不支持的 CSS property
|
|
5
|
+
const unsupportedPropExp = /^(box-sizing|white-space|text-overflow|animation|transition)$/
|
|
6
|
+
const unsupportedPropMode = {
|
|
7
|
+
// React Native ios 不支持的 CSS property
|
|
8
|
+
ios: /^(vertical-align)$/,
|
|
9
|
+
// React Native android 不支持的 CSS property
|
|
10
|
+
android: /^(text-decoration-style|text-decoration-color|shadow-offset|shadow-opacity|shadow-radius)$/
|
|
11
|
+
}
|
|
12
|
+
const unsupportedPropError = ({ prop, mode }) => {
|
|
13
|
+
error(`Property [${prop}] is not supported in React Native ${mode} environment!`)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// React 属性支持的枚举值
|
|
17
|
+
const SUPPORTED_PROP_VAL_ARR = {
|
|
18
|
+
overflow: ['visible', 'hidden', 'scroll'],
|
|
19
|
+
'border-style': ['solid', 'dotted', 'dashed'],
|
|
20
|
+
display: ['flex', 'none'],
|
|
21
|
+
'pointer-events': ['auto', 'none'],
|
|
22
|
+
'vertical-align': ['auto', 'top', 'bottom', 'center'],
|
|
23
|
+
position: ['relative', 'absolute'],
|
|
24
|
+
'font-variant': ['small-caps', 'oldstyle-nums', 'lining-nums', 'tabular-nums', 'proportional-nums'],
|
|
25
|
+
'text-align': ['left', 'right', 'center', 'justify'],
|
|
26
|
+
'font-style': ['normal', 'italic'],
|
|
27
|
+
'font-weight': ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
|
|
28
|
+
'text-decoration-line': ['none', 'underline', 'line-through', 'underline line-through'],
|
|
29
|
+
'text-transform': ['none', 'uppercase', 'lowercase', 'capitalize'],
|
|
30
|
+
'user-select': ['auto', 'text', 'none', 'contain', 'all'],
|
|
31
|
+
'align-content': ['flex-start', 'flex-end', 'center', 'stretch', 'space-between', 'space-around'],
|
|
32
|
+
'align-items': ['flex-start', 'flex-end', 'center', 'stretch', 'baseline'],
|
|
33
|
+
'align-self': ['auto', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline'],
|
|
34
|
+
'justify-content': ['flex-start', 'flex-end', 'center', 'space-between', 'space-around', 'space-evenly', 'none'],
|
|
35
|
+
'background-size': ['contain', 'cover', 'auto'],
|
|
36
|
+
'background-repeat': ['no-repeat']
|
|
37
|
+
}
|
|
38
|
+
const propValExp = new RegExp('^(' + Object.keys(SUPPORTED_PROP_VAL_ARR).join('|') + ')$')
|
|
39
|
+
const isIllegalValue = ({ prop, value }) => SUPPORTED_PROP_VAL_ARR[prop]?.length > 0 && !SUPPORTED_PROP_VAL_ARR[prop].includes(value)
|
|
40
|
+
const unsupportedValueError = ({ prop, value }) => {
|
|
41
|
+
error(`Property [${prop}] only support value [${SUPPORTED_PROP_VAL_ARR[prop]?.join(',')}] in React Native environment, the value [${value}] does not support!`)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 过滤的不合法的属性
|
|
45
|
+
const delRule = ({ prop, value }, { mode }) => {
|
|
46
|
+
if (unsupportedPropExp.test(prop) || unsupportedPropMode[mode].test(prop)) {
|
|
47
|
+
unsupportedPropError({ prop, mode })
|
|
48
|
+
return false
|
|
49
|
+
}
|
|
50
|
+
if (isIllegalValue({ prop, value })) {
|
|
51
|
+
unsupportedValueError({ prop, value })
|
|
52
|
+
return false
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// color & number 值校验
|
|
57
|
+
const ValueType = {
|
|
58
|
+
number: 'number',
|
|
59
|
+
color: 'color',
|
|
60
|
+
default: 'default' // 不校验
|
|
61
|
+
}
|
|
62
|
+
// number 类型支持的单位
|
|
63
|
+
const numberRegExp = /^\s*(\d+(\.\d+)?)(rpx|px|%)?\s*$/
|
|
64
|
+
// RN 不支持的颜色格式
|
|
65
|
+
const colorRegExp = /^\s*(lab|lch|oklab|oklch|color-mix|color|hwb|lch|light-dark).*$/
|
|
66
|
+
|
|
67
|
+
const verifyValues = ({ prop, value, valueType }) => {
|
|
68
|
+
// 校验 value 枚举 是否支持
|
|
69
|
+
switch (valueType) {
|
|
70
|
+
case ValueType.color: {
|
|
71
|
+
const isNumber = numberRegExp.test(value)
|
|
72
|
+
const isUnsupporttedColor = colorRegExp.test(value)
|
|
73
|
+
isNumber && warn(`React Native property [${prop}]'s valueType is ${valueType}, we does not set type number`)
|
|
74
|
+
isUnsupporttedColor && warn('React Native color does not support type [lab,lch,oklab,oklch,color-mix,color,hwb,lch,light-dark]')
|
|
75
|
+
return !isNumber && !isUnsupporttedColor
|
|
76
|
+
}
|
|
77
|
+
case ValueType.number: {
|
|
78
|
+
const isNumber = numberRegExp.test(value)
|
|
79
|
+
!isNumber && warn(`React Native property [${prop}] unit only supports [rpx,px,%]`)
|
|
80
|
+
return isNumber
|
|
81
|
+
}
|
|
82
|
+
default:
|
|
83
|
+
return true
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// 统一校验 value type 值类型
|
|
87
|
+
const checkCommonValue = (valueType) => ({ prop, value }) => {
|
|
88
|
+
verifyValues({ prop, value, valueType })
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 简写转换规则
|
|
92
|
+
const AbbreviationMap = {
|
|
93
|
+
'text-shadow': { // 仅支持 offset-x | offset-y | blur-radius | color 排序
|
|
94
|
+
'textShadowOffset.width': ValueType.number,
|
|
95
|
+
'textShadowOffset.height': ValueType.number,
|
|
96
|
+
textShadowRadius: ValueType.number,
|
|
97
|
+
textShadowColor: ValueType.color
|
|
98
|
+
},
|
|
99
|
+
border: { // 仅支持 width | style | color 这种排序
|
|
100
|
+
borderWidth: ValueType.number,
|
|
101
|
+
borderStyle: ValueType.default,
|
|
102
|
+
borderColor: ValueType.color
|
|
103
|
+
},
|
|
104
|
+
'box-shadow': { // 仅支持 offset-x | offset-y | blur-radius | color 排序
|
|
105
|
+
'shadowOffset.width': ValueType.number,
|
|
106
|
+
'shadowOffset.height': ValueType.number,
|
|
107
|
+
shadowRadius: ValueType.number,
|
|
108
|
+
shadowColor: ValueType.color
|
|
109
|
+
},
|
|
110
|
+
'text-decoration': { // 仅支持 text-decoration-line text-decoration-style text-decoration-color 这种格式
|
|
111
|
+
textDecorationLine: ValueType.default,
|
|
112
|
+
textDecorationStyle: ValueType.default,
|
|
113
|
+
textDecorationColor: ValueType.color
|
|
114
|
+
},
|
|
115
|
+
flex: { // /* Three values: flex-grow | flex-shrink | flex-basis */
|
|
116
|
+
flexGrow: ValueType.number,
|
|
117
|
+
flexShrink: ValueType.number,
|
|
118
|
+
flexBasis: ValueType.number
|
|
119
|
+
},
|
|
120
|
+
'flex-flow': { // 仅支持 flex-flow: <'flex-direction'> or flex-flow: <'flex-direction'> and <'flex-wrap'>
|
|
121
|
+
flexDirection: ValueType.default,
|
|
122
|
+
flexWrap: ValueType.default
|
|
123
|
+
},
|
|
124
|
+
'border-radius': {
|
|
125
|
+
borderTopLeftRadius: ValueType.number,
|
|
126
|
+
borderTopRightRadius: ValueType.number,
|
|
127
|
+
borderBottomRightRadius: ValueType.number,
|
|
128
|
+
borderBottomLeftRadius: ValueType.number
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const formatAbbreviation = ({ value, keyMap }) => {
|
|
132
|
+
const values = value.trim().split(/\s(?![^()]*\))/)
|
|
133
|
+
const cssMap = []
|
|
134
|
+
const props = Object.getOwnPropertyNames(keyMap)
|
|
135
|
+
let idx = 0
|
|
136
|
+
// 按值的个数循环赋值
|
|
137
|
+
while (idx < values.length && idx < props.length) {
|
|
138
|
+
const prop = props[idx]
|
|
139
|
+
const valueType = keyMap[prop]
|
|
140
|
+
const dashProp = hump2dash(prop)
|
|
141
|
+
// 校验 value 类型
|
|
142
|
+
verifyValues({ prop, value: values[idx], valueType })
|
|
143
|
+
const value = values[idx]
|
|
144
|
+
if (isIllegalValue({ prop: dashProp, value })) {
|
|
145
|
+
// 过滤不支持 value
|
|
146
|
+
unsupportedValueError({ prop: dashProp, value })
|
|
147
|
+
} else if (prop.includes('.')) {
|
|
148
|
+
// 多个属性值的prop
|
|
149
|
+
const [main, sub] = prop.split('.')
|
|
150
|
+
const cssData = cssMap.find(item => item.prop === main)
|
|
151
|
+
if (cssData) { // 设置过
|
|
152
|
+
cssData.value[sub] = value
|
|
153
|
+
} else { // 第一次设置
|
|
154
|
+
cssMap.push({
|
|
155
|
+
prop: main,
|
|
156
|
+
value: {
|
|
157
|
+
[sub]: value
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
// 单个值的属性
|
|
163
|
+
cssMap.push({
|
|
164
|
+
prop,
|
|
165
|
+
value
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
idx += 1
|
|
169
|
+
}
|
|
170
|
+
return cssMap
|
|
171
|
+
}
|
|
172
|
+
const getAbbreviation = ({ prop, value }) => {
|
|
173
|
+
const keyMap = AbbreviationMap[prop]
|
|
174
|
+
return formatAbbreviation({ prop, value, keyMap })
|
|
175
|
+
}
|
|
176
|
+
// 简写过滤安卓不支持的类型
|
|
177
|
+
const getAbbreviationAndroid = ({ prop, value }, { mode }) => {
|
|
178
|
+
const cssMap = getAbbreviation({ prop, value })
|
|
179
|
+
// android 不支持的 shadowOffset shadowOpacity shadowRadius textDecorationStyle 和 textDecorationStyle
|
|
180
|
+
return cssMap.filter(({ prop }) => { // 不支持的 prop 提示 & 过滤不支持的 prop
|
|
181
|
+
const dashProp = hump2dash(prop)
|
|
182
|
+
if (unsupportedPropMode.android.test(dashProp)) {
|
|
183
|
+
unsupportedPropError({ prop: dashProp, mode })
|
|
184
|
+
return false
|
|
185
|
+
}
|
|
186
|
+
return true
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const formatMargins = ({ prop, value }) => {
|
|
191
|
+
const values = value.trim().split(/\s(?![^()]*\))/)
|
|
192
|
+
// validate
|
|
193
|
+
for (let i = 0; i < values.length; i++) {
|
|
194
|
+
verifyValues({ prop, value: values[i], valueType: ValueType.number })
|
|
195
|
+
}
|
|
196
|
+
// format
|
|
197
|
+
let suffix = []
|
|
198
|
+
switch (values.length) {
|
|
199
|
+
// case 1:
|
|
200
|
+
case 2:
|
|
201
|
+
suffix = ['Vertical', 'Horizontal']
|
|
202
|
+
break
|
|
203
|
+
case 3:
|
|
204
|
+
suffix = ['Top', 'Horizontal', 'Bottom']
|
|
205
|
+
break
|
|
206
|
+
case 4:
|
|
207
|
+
suffix = ['Top', 'Right', 'Bottom', 'Left']
|
|
208
|
+
break
|
|
209
|
+
}
|
|
210
|
+
return values.map((value, index) => {
|
|
211
|
+
return {
|
|
212
|
+
prop: `${prop}${suffix[index] || ''}`,
|
|
213
|
+
value: value
|
|
214
|
+
}
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const formatLineHeight = ({ prop, value }) => {
|
|
219
|
+
if (!verifyValues({ prop, value, valueType: ValueType.number })) return false
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
prop,
|
|
223
|
+
value: /\d+(\.\d+)?$/.test(value) ? `${Math.round(value * 100)}%` : value
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const getFontVariant = ({ prop, value }) => {
|
|
228
|
+
if (/^(font-variant-caps|font-variant-numeric|font-variant-east-asian|font-variant-alternates|font-variant-ligatures)$/.test(prop)) {
|
|
229
|
+
error(`Property [${prop}] is not supported in React Native environment, please replace [font-variant]!`)
|
|
230
|
+
}
|
|
231
|
+
prop = 'font-variant'
|
|
232
|
+
// 校验枚举值
|
|
233
|
+
if (isIllegalValue({ prop, value })) {
|
|
234
|
+
unsupportedValueError({ prop, value })
|
|
235
|
+
return false
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
prop,
|
|
239
|
+
value
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// background 相关属性的处理,仅支持以下属性,不支持其他背景相关的属性:/^((?!(-color)).)*background((?!(-color)).)*$/ 包含background且不包含background-color
|
|
244
|
+
const checkBackgroundImage = ({ prop, value }, { mode }) => {
|
|
245
|
+
const bgPropMap = {
|
|
246
|
+
image: 'background-image',
|
|
247
|
+
color: 'background-color',
|
|
248
|
+
size: 'background-size',
|
|
249
|
+
repeat: 'background-repeat',
|
|
250
|
+
// position: 'background-position',
|
|
251
|
+
all: 'background'
|
|
252
|
+
}
|
|
253
|
+
const urlExp = /url\(["']?(.*?)["']?\)/
|
|
254
|
+
switch (prop) {
|
|
255
|
+
case bgPropMap.color: {
|
|
256
|
+
// background-color 背景色校验一下颜色值
|
|
257
|
+
verifyValues({ prop, value, valueType: ValueType.color })
|
|
258
|
+
return { prop, value }
|
|
259
|
+
}
|
|
260
|
+
case bgPropMap.image: {
|
|
261
|
+
// background-image 仅支持背景图
|
|
262
|
+
const imgUrl = value.match(urlExp)?.[0]
|
|
263
|
+
if (/.*linear-gradient*./.test(value)) {
|
|
264
|
+
error(`<linear-gradient()> is not supported in React Native ${mode} environment!`)
|
|
265
|
+
}
|
|
266
|
+
if (imgUrl) {
|
|
267
|
+
return { prop, value: imgUrl }
|
|
268
|
+
} else {
|
|
269
|
+
error(`[${prop}] only support value <url()>`)
|
|
270
|
+
return false
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
case bgPropMap.size: {
|
|
274
|
+
// background-size
|
|
275
|
+
// 不支持逗号分隔的多个值:设置多重背景!!!
|
|
276
|
+
// 支持一个值:这个值指定图片的宽度,图片的高度隐式的为 auto
|
|
277
|
+
// 支持两个值:第一个值指定图片的宽度,第二个值指定图片的高度
|
|
278
|
+
if (value.includes(',')) { // commas are not allowed in values
|
|
279
|
+
error(`background size value[${value}] does not support commas in React Native ${mode} environment!`)
|
|
280
|
+
return false
|
|
281
|
+
}
|
|
282
|
+
const values = []
|
|
283
|
+
value.trim().split(/\s(?![^()]*\))/).forEach(item => {
|
|
284
|
+
if (numberRegExp.test(item) || !isIllegalValue({ prop, value: item })) {
|
|
285
|
+
// 支持 number 值 / container cover auto 枚举
|
|
286
|
+
values.push(item)
|
|
287
|
+
} else {
|
|
288
|
+
error(`background size value[${value}] does not support in React Native ${mode} environment!`)
|
|
289
|
+
}
|
|
290
|
+
})
|
|
291
|
+
// value 无有效值时返回false
|
|
292
|
+
return values.length === 0 ? false : { prop, value: values }
|
|
293
|
+
}
|
|
294
|
+
case bgPropMap.repeat: {
|
|
295
|
+
// background-repeat 仅支持 no-repeat
|
|
296
|
+
if (isIllegalValue({ prop, value })) {
|
|
297
|
+
unsupportedValueError({ prop, value })
|
|
298
|
+
return false
|
|
299
|
+
}
|
|
300
|
+
return { prop, value }
|
|
301
|
+
}
|
|
302
|
+
case bgPropMap.all: {
|
|
303
|
+
// background: 仅支持 background-image & background-color & background-repeat
|
|
304
|
+
const bgMap = []
|
|
305
|
+
const values = value.trim().split(/\s(?![^()]*\))/)
|
|
306
|
+
values.forEach(item => {
|
|
307
|
+
const url = item.match(urlExp)?.[0]
|
|
308
|
+
if (/.*linear-gradient*./.test(item)) {
|
|
309
|
+
error(`<linear-gradient()> is not supported in React Native ${mode} environment!`)
|
|
310
|
+
} else if (url) {
|
|
311
|
+
bgMap.push({ prop: bgPropMap.image, value: url })
|
|
312
|
+
} else if (/^(#[0-9a-f]{3}$|#[0-9a-f]{6}$|rgb|rgba)/i.test(item)) {
|
|
313
|
+
bgMap.push({ prop: bgPropMap.color, value: item })
|
|
314
|
+
} else if (SUPPORTED_PROP_VAL_ARR[bgPropMap.repeat].includes(item)) {
|
|
315
|
+
bgMap.push({ prop: bgPropMap.repeat, value: item })
|
|
316
|
+
}
|
|
317
|
+
// else if (SUPPORTED_PROP_VAL_ARR[bgPropMap.size].includes(item)) {
|
|
318
|
+
// bgMap.push({ prop: bgPropMap.size, value: item })
|
|
319
|
+
// }
|
|
320
|
+
})
|
|
321
|
+
return bgMap.length ? bgMap : false
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
unsupportedPropError({ prop, mode })
|
|
325
|
+
return false
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const getBorderRadius = ({ prop, value }) => {
|
|
329
|
+
const values = value.trim().split(/\s(?![^()]*\))/)
|
|
330
|
+
if (values.length === 1) {
|
|
331
|
+
verifyValues({ prop, value, valueType: ValueType.number })
|
|
332
|
+
return { prop, value }
|
|
333
|
+
} else {
|
|
334
|
+
return getAbbreviation({ prop, value })
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const spec = {
|
|
339
|
+
supportedModes: ['ios', 'android'],
|
|
340
|
+
rules: [
|
|
341
|
+
{ // 背景相关属性的处理
|
|
342
|
+
test: /.*background*./,
|
|
343
|
+
ios: checkBackgroundImage,
|
|
344
|
+
android: checkBackgroundImage
|
|
345
|
+
},
|
|
346
|
+
{ // RN 不支持的 CSS property
|
|
347
|
+
test: unsupportedPropExp,
|
|
348
|
+
ios: delRule,
|
|
349
|
+
android: delRule
|
|
350
|
+
},
|
|
351
|
+
{ // React Native android 不支持的 CSS property
|
|
352
|
+
test: unsupportedPropMode.android,
|
|
353
|
+
android: delRule
|
|
354
|
+
},
|
|
355
|
+
{ // React Native ios 不支持的 CSS property
|
|
356
|
+
test: unsupportedPropMode.ios,
|
|
357
|
+
ios: delRule
|
|
358
|
+
},
|
|
359
|
+
{ // RN 支持的 CSS property value
|
|
360
|
+
test: propValExp,
|
|
361
|
+
ios: delRule,
|
|
362
|
+
android: delRule
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
test: 'box-shadow',
|
|
366
|
+
ios: getAbbreviation,
|
|
367
|
+
android: getAbbreviationAndroid
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
test: 'text-decoration',
|
|
371
|
+
ios: getAbbreviation,
|
|
372
|
+
android: getAbbreviationAndroid
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
test: /.*font-variant.*/,
|
|
376
|
+
ios: getFontVariant,
|
|
377
|
+
android: getFontVariant
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
test: 'border-radius',
|
|
381
|
+
ios: getBorderRadius,
|
|
382
|
+
android: getBorderRadius
|
|
383
|
+
},
|
|
384
|
+
{ // margin padding 内外边距的处理
|
|
385
|
+
test: /.*(margin|padding).*/,
|
|
386
|
+
ios: formatMargins,
|
|
387
|
+
android: formatMargins
|
|
388
|
+
},
|
|
389
|
+
// 通用的简写格式匹配
|
|
390
|
+
{
|
|
391
|
+
test: new RegExp('^(' + Object.keys(AbbreviationMap).join('|') + ')$'),
|
|
392
|
+
ios: getAbbreviation,
|
|
393
|
+
android: getAbbreviation
|
|
394
|
+
},
|
|
395
|
+
// 值类型校验放到最后
|
|
396
|
+
{ // color 颜色值校验
|
|
397
|
+
test: /.*color.*/i,
|
|
398
|
+
ios: checkCommonValue(ValueType.color),
|
|
399
|
+
android: checkCommonValue(ValueType.color)
|
|
400
|
+
},
|
|
401
|
+
{ // color 颜色值校验
|
|
402
|
+
test: 'line-height',
|
|
403
|
+
ios: formatLineHeight,
|
|
404
|
+
android: formatLineHeight
|
|
405
|
+
},
|
|
406
|
+
{ // number 值校验
|
|
407
|
+
test: /.*width|height|left|right|top|bottom|radius|margin|padding|spacing|offset|size.*/i,
|
|
408
|
+
ios: checkCommonValue(ValueType.number),
|
|
409
|
+
android: checkCommonValue(ValueType.number)
|
|
410
|
+
}
|
|
411
|
+
]
|
|
412
|
+
}
|
|
413
|
+
return spec
|
|
414
|
+
}
|
|
@@ -30,6 +30,12 @@ module.exports = function ({ print }) {
|
|
|
30
30
|
const webEventLog = print({ platform: 'web', tag: TAG_NAME, isError: false, type: 'event' })
|
|
31
31
|
const qaPropLog = print({ platform: 'qa', tag: TAG_NAME, isError: false })
|
|
32
32
|
const wxPropValueLog = print({ platform: 'wx', tag: TAG_NAME, isError: false, type: 'value' })
|
|
33
|
+
const iosValueLogError = print({ platform: 'ios', tag: TAG_NAME, isError: true, type: 'value' })
|
|
34
|
+
const iosPropLog = print({ platform: 'ios', tag: TAG_NAME, isError: false })
|
|
35
|
+
const iosEventLog = print({ platform: 'ios', tag: TAG_NAME, isError: false, type: 'event' })
|
|
36
|
+
const androidValueLogError = print({ platform: 'android', tag: TAG_NAME, isError: true, type: 'value' })
|
|
37
|
+
const androidPropLog = print({ platform: 'android', tag: TAG_NAME, isError: false })
|
|
38
|
+
const androidEventLog = print({ platform: 'android', tag: TAG_NAME, isError: false, type: 'event' })
|
|
33
39
|
|
|
34
40
|
return {
|
|
35
41
|
test: TAG_NAME,
|
|
@@ -37,6 +43,14 @@ module.exports = function ({ print }) {
|
|
|
37
43
|
el.isBuiltIn = true
|
|
38
44
|
return 'mpx-button'
|
|
39
45
|
},
|
|
46
|
+
ios (tag, { el }) {
|
|
47
|
+
el.isBuiltIn = true
|
|
48
|
+
return 'mpx-button'
|
|
49
|
+
},
|
|
50
|
+
android (tag, { el }) {
|
|
51
|
+
el.isBuiltIn = true
|
|
52
|
+
return 'mpx-button'
|
|
53
|
+
},
|
|
40
54
|
props: [
|
|
41
55
|
{
|
|
42
56
|
test: 'open-type',
|
|
@@ -107,6 +121,18 @@ module.exports = function ({ print }) {
|
|
|
107
121
|
ttValueLogError({ name, value })
|
|
108
122
|
}
|
|
109
123
|
}
|
|
124
|
+
},
|
|
125
|
+
ios ({ name, value }) {
|
|
126
|
+
const supported = ['share']
|
|
127
|
+
if (!supported.includes(value)) {
|
|
128
|
+
iosValueLogError({ name, value })
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
android ({ name, value }) {
|
|
132
|
+
const supported = ['share']
|
|
133
|
+
if (!supported.includes(value)) {
|
|
134
|
+
androidValueLogError({ name, value })
|
|
135
|
+
}
|
|
110
136
|
}
|
|
111
137
|
},
|
|
112
138
|
{
|
|
@@ -143,6 +169,11 @@ module.exports = function ({ print }) {
|
|
|
143
169
|
{
|
|
144
170
|
test: /^(open-type|lang|session-from|send-message-title|send-message-path|send-message-img|app-parameter|show-message-card|bindgetuserinfo|bindcontact|bindgetphonenumber|binderror|bindopensetting|bindlaunchapp)$/,
|
|
145
171
|
qa: qaPropLog
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
test: /^(lang|from-type|hover-class|send-message-title|send-message-path|send-message-img|app-parameter|show-message-card|phone-number-no-quota-toast|bindgetuserinfo|bindcontact|createliveactivity|bindgetphonenumber|bindgetrealtimephonenumber|binderror|bindopensetting|bindlaunchapp|bindchooseavatar|bindagreeprivacyauthorization)$/,
|
|
175
|
+
ios: iosPropLog,
|
|
176
|
+
android: androidPropLog
|
|
146
177
|
}
|
|
147
178
|
],
|
|
148
179
|
event: [
|
|
@@ -175,6 +206,11 @@ module.exports = function ({ print }) {
|
|
|
175
206
|
{
|
|
176
207
|
test: /^(getuserinfo|contact|error|launchapp|opensetting|getphonenumber)$/,
|
|
177
208
|
web: webEventLog
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
test: /^(getuserinfo|contact|getphonenumber|bindgetrealtimephonenumber|error|opensetting|launchapp|chooseavatar|agreeprivacyauthorization)$/,
|
|
212
|
+
ios: iosEventLog,
|
|
213
|
+
android: androidEventLog
|
|
178
214
|
}
|
|
179
215
|
]
|
|
180
216
|
}
|