react-native-boost 0.5.3 → 0.5.4
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/dist/plugin/esm/index.mjs +174 -160
- package/dist/plugin/esm/index.mjs.map +1 -1
- package/dist/plugin/index.js +174 -160
- package/dist/plugin/index.js.map +1 -1
- package/package.json +1 -1
- package/src/plugin/optimizers/text/index.ts +127 -155
- package/src/plugin/optimizers/view/index.ts +13 -47
- package/src/plugin/utils/common/attributes.ts +144 -0
- package/src/plugin/utils/common/base.ts +82 -0
- package/src/plugin/utils/common/index.ts +4 -0
- package/src/plugin/utils/common/node-types.ts +22 -0
- package/src/plugin/utils/common/validation.ts +181 -0
- package/src/plugin/utils/constants.ts +16 -0
- package/src/plugin/utils/common.ts +0 -296
package/dist/plugin/index.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
var helperPluginUtils = require('@babel/helper-plugin-utils');
|
|
4
4
|
var core = require('@babel/core');
|
|
5
|
-
var minimatch = require('minimatch');
|
|
6
|
-
var path = require('node:path');
|
|
7
5
|
var helperModuleImports = require('@babel/helper-module-imports');
|
|
6
|
+
var minimatch = require('minimatch');
|
|
7
|
+
var nodePath = require('node:path');
|
|
8
8
|
|
|
9
9
|
class PluginError extends Error {
|
|
10
10
|
constructor(message) {
|
|
@@ -13,15 +13,23 @@ class PluginError extends Error {
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
const RUNTIME_MODULE_NAME = "react-native-boost";
|
|
17
|
+
const ACCESSIBILITY_PROPERTIES = /* @__PURE__ */ new Set([
|
|
18
|
+
"accessibilityLabel",
|
|
19
|
+
"aria-label",
|
|
20
|
+
"accessibilityState",
|
|
21
|
+
"aria-busy",
|
|
22
|
+
"aria-checked",
|
|
23
|
+
"aria-disabled",
|
|
24
|
+
"aria-expanded",
|
|
25
|
+
"aria-selected",
|
|
26
|
+
"accessible"
|
|
27
|
+
]);
|
|
20
28
|
|
|
21
29
|
function addFileImportHint({
|
|
22
30
|
file,
|
|
23
31
|
nameHint,
|
|
24
|
-
path
|
|
32
|
+
path,
|
|
25
33
|
importName,
|
|
26
34
|
moduleName,
|
|
27
35
|
importType = "named"
|
|
@@ -29,12 +37,35 @@ function addFileImportHint({
|
|
|
29
37
|
var _a;
|
|
30
38
|
if (!((_a = file.__hasImports) == null ? void 0 : _a[nameHint])) {
|
|
31
39
|
file.__hasImports = file.__hasImports || {};
|
|
32
|
-
file.__hasImports[nameHint] = importType === "default" ? helperModuleImports.addDefault(
|
|
40
|
+
file.__hasImports[nameHint] = importType === "default" ? helperModuleImports.addDefault(path, moduleName, { nameHint }) : helperModuleImports.addNamed(path, importName, moduleName, { nameHint });
|
|
33
41
|
}
|
|
34
42
|
return file.__hasImports[nameHint];
|
|
35
43
|
}
|
|
36
|
-
const
|
|
37
|
-
const
|
|
44
|
+
const replaceWithNativeComponent = (path, parent, file, nativeComponentName) => {
|
|
45
|
+
const nativeIdentifier = addFileImportHint({
|
|
46
|
+
file,
|
|
47
|
+
nameHint: nativeComponentName,
|
|
48
|
+
path,
|
|
49
|
+
importName: nativeComponentName,
|
|
50
|
+
moduleName: RUNTIME_MODULE_NAME,
|
|
51
|
+
importType: "named"
|
|
52
|
+
});
|
|
53
|
+
const currentName = path.node.name.name;
|
|
54
|
+
const jsxName = path.node.name;
|
|
55
|
+
jsxName.name = nativeIdentifier.name;
|
|
56
|
+
if (!path.node.selfClosing && parent.closingElement && core.types.isJSXIdentifier(parent.closingElement.name) && parent.closingElement.name.name === currentName) {
|
|
57
|
+
parent.closingElement.name.name = nativeIdentifier.name;
|
|
58
|
+
}
|
|
59
|
+
return nativeIdentifier;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const ensureArray = (value) => {
|
|
63
|
+
if (Array.isArray(value)) return value;
|
|
64
|
+
return [value];
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const isIgnoredFile = (path, ignores) => {
|
|
68
|
+
const hub = path.hub;
|
|
38
69
|
const file = typeof hub === "object" && hub !== null && "file" in hub ? hub.file : void 0;
|
|
39
70
|
if (!file) {
|
|
40
71
|
throw new PluginError("No file found in Babel hub");
|
|
@@ -42,19 +73,19 @@ const isIgnoredFile = (p, ignores) => {
|
|
|
42
73
|
const fileName = file.opts.filename;
|
|
43
74
|
const baseDirectory = "cwd" in file.opts ? file.opts.cwd : process.cwd();
|
|
44
75
|
for (const pattern of ignores) {
|
|
45
|
-
const absolutePattern =
|
|
76
|
+
const absolutePattern = nodePath.isAbsolute(pattern) ? pattern : nodePath.join(baseDirectory, pattern);
|
|
46
77
|
if (minimatch.minimatch(fileName, absolutePattern, { dot: true })) {
|
|
47
78
|
return true;
|
|
48
79
|
}
|
|
49
80
|
}
|
|
50
81
|
return false;
|
|
51
82
|
};
|
|
52
|
-
const
|
|
83
|
+
const isIgnoredLine = (path) => {
|
|
53
84
|
var _a, _b, _c;
|
|
54
|
-
if ((_a =
|
|
85
|
+
if ((_a = path.node.leadingComments) == null ? void 0 : _a.some((comment) => comment.value.includes("@boost-ignore"))) {
|
|
55
86
|
return true;
|
|
56
87
|
}
|
|
57
|
-
const jsxElementPath =
|
|
88
|
+
const jsxElementPath = path.parentPath;
|
|
58
89
|
if ((_b = jsxElementPath.node.leadingComments) == null ? void 0 : _b.some((comment) => comment.value.includes("@boost-ignore"))) {
|
|
59
90
|
return true;
|
|
60
91
|
}
|
|
@@ -92,11 +123,51 @@ const shouldIgnoreOptimization = (path2) => {
|
|
|
92
123
|
}
|
|
93
124
|
return false;
|
|
94
125
|
};
|
|
95
|
-
const
|
|
96
|
-
|
|
126
|
+
const isValidJSXComponent = (path, componentName) => {
|
|
127
|
+
if (!core.types.isJSXIdentifier(path.node.name)) return false;
|
|
128
|
+
const parent = path.parent;
|
|
129
|
+
if (!core.types.isJSXElement(parent)) return false;
|
|
130
|
+
const componentIdentifier = path.node.name.name;
|
|
131
|
+
const binding = path.scope.getBinding(componentIdentifier);
|
|
132
|
+
if (!binding) return false;
|
|
133
|
+
if (binding.kind === "module" && core.types.isImportDeclaration(binding.path.parent) && core.types.isImportSpecifier(binding.path.node)) {
|
|
134
|
+
const imported = binding.path.node.imported;
|
|
135
|
+
if (core.types.isIdentifier(imported)) {
|
|
136
|
+
return imported.name === componentName;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return path.node.name.name === componentName;
|
|
140
|
+
};
|
|
141
|
+
const isReactNativeImport = (path, expectedImportedName) => {
|
|
142
|
+
if (!core.types.isJSXIdentifier(path.node.name)) return false;
|
|
143
|
+
const localName = path.node.name.name;
|
|
144
|
+
const binding = path.scope.getBinding(localName);
|
|
145
|
+
if (!binding) return false;
|
|
146
|
+
if (binding.kind === "module") {
|
|
147
|
+
const importDeclaration = binding.path.parent;
|
|
148
|
+
if (!core.types.isImportDeclaration(importDeclaration)) return false;
|
|
149
|
+
if (importDeclaration.source.value !== "react-native") return false;
|
|
150
|
+
if (core.types.isImportSpecifier(binding.path.node)) {
|
|
151
|
+
const imported = binding.path.node.imported;
|
|
152
|
+
if (core.types.isIdentifier(imported)) {
|
|
153
|
+
return imported.name === expectedImportedName;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (core.types.isImportDefaultSpecifier(binding.path.node)) {
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return false;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const hasBlacklistedProperty = (path, blacklist) => {
|
|
164
|
+
return path.node.attributes.some((attribute) => {
|
|
165
|
+
if (core.types.isJSXAttribute(attribute) && core.types.isJSXIdentifier(attribute.name) && blacklist.has(attribute.name.name)) {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
97
168
|
if (core.types.isJSXSpreadAttribute(attribute)) {
|
|
98
169
|
if (core.types.isIdentifier(attribute.argument)) {
|
|
99
|
-
const binding =
|
|
170
|
+
const binding = path.scope.getBinding(attribute.argument.name);
|
|
100
171
|
let objectExpression;
|
|
101
172
|
if (binding) {
|
|
102
173
|
if (core.types.isVariableDeclarator(binding.path.node)) {
|
|
@@ -149,38 +220,27 @@ const buildPropertiesFromAttributes = (attributes) => {
|
|
|
149
220
|
...arguments_
|
|
150
221
|
]);
|
|
151
222
|
};
|
|
152
|
-
const
|
|
153
|
-
"accessibilityLabel",
|
|
154
|
-
"aria-label",
|
|
155
|
-
"accessibilityState",
|
|
156
|
-
"aria-busy",
|
|
157
|
-
"aria-checked",
|
|
158
|
-
"aria-disabled",
|
|
159
|
-
"aria-expanded",
|
|
160
|
-
"aria-selected",
|
|
161
|
-
"accessible"
|
|
162
|
-
]);
|
|
163
|
-
const hasAccessibilityProperty = (path2, attributes) => {
|
|
223
|
+
const hasAccessibilityProperty = (path, attributes) => {
|
|
164
224
|
for (const attribute of attributes) {
|
|
165
225
|
if (core.types.isJSXAttribute(attribute)) {
|
|
166
226
|
const key = attribute.name.name;
|
|
167
|
-
if (typeof key === "string" &&
|
|
227
|
+
if (typeof key === "string" && ACCESSIBILITY_PROPERTIES.has(key)) {
|
|
168
228
|
return true;
|
|
169
229
|
}
|
|
170
230
|
} else if (core.types.isJSXSpreadAttribute(attribute)) {
|
|
171
231
|
if (core.types.isObjectExpression(attribute.argument)) {
|
|
172
232
|
for (const property of attribute.argument.properties) {
|
|
173
|
-
if (core.types.isObjectProperty(property) && core.types.isIdentifier(property.key) &&
|
|
233
|
+
if (core.types.isObjectProperty(property) && core.types.isIdentifier(property.key) && ACCESSIBILITY_PROPERTIES.has(property.key.name)) {
|
|
174
234
|
return true;
|
|
175
235
|
}
|
|
176
236
|
}
|
|
177
237
|
} else if (core.types.isIdentifier(attribute.argument)) {
|
|
178
|
-
const binding =
|
|
238
|
+
const binding = path.scope.getBinding(attribute.argument.name);
|
|
179
239
|
if (binding && core.types.isVariableDeclarator(binding.path.node)) {
|
|
180
240
|
const declarator = binding.path.node;
|
|
181
241
|
if (declarator.init && core.types.isObjectExpression(declarator.init)) {
|
|
182
242
|
for (const property of declarator.init.properties) {
|
|
183
|
-
if (core.types.isObjectProperty(property) && core.types.isIdentifier(property.key) &&
|
|
243
|
+
if (core.types.isObjectProperty(property) && core.types.isIdentifier(property.key) && ACCESSIBILITY_PROPERTIES.has(property.key.name)) {
|
|
184
244
|
return true;
|
|
185
245
|
}
|
|
186
246
|
}
|
|
@@ -196,6 +256,22 @@ const hasAccessibilityProperty = (path2, attributes) => {
|
|
|
196
256
|
return false;
|
|
197
257
|
};
|
|
198
258
|
|
|
259
|
+
const isStringNode = (path, child) => {
|
|
260
|
+
if (core.types.isJSXText(child) || core.types.isStringLiteral(child)) return true;
|
|
261
|
+
if (core.types.isJSXExpressionContainer(child)) {
|
|
262
|
+
const expression = child.expression;
|
|
263
|
+
if (core.types.isIdentifier(expression)) {
|
|
264
|
+
const binding = path.scope.getBinding(expression.name);
|
|
265
|
+
if (binding && binding.path.node && core.types.isVariableDeclarator(binding.path.node)) {
|
|
266
|
+
return !!binding.path.node.init && core.types.isStringLiteral(binding.path.node.init);
|
|
267
|
+
}
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
if (core.types.isStringLiteral(expression)) return true;
|
|
271
|
+
}
|
|
272
|
+
return false;
|
|
273
|
+
};
|
|
274
|
+
|
|
199
275
|
const textBlacklistedProperties = /* @__PURE__ */ new Set([
|
|
200
276
|
"allowFontScaling",
|
|
201
277
|
"ellipsizeMode",
|
|
@@ -219,25 +295,12 @@ const textBlacklistedProperties = /* @__PURE__ */ new Set([
|
|
|
219
295
|
const textOptimizer = (path, log = () => {
|
|
220
296
|
}) => {
|
|
221
297
|
var _a, _b, _c;
|
|
222
|
-
if (
|
|
223
|
-
|
|
224
|
-
if (!
|
|
225
|
-
const elementName = path.node.name.name;
|
|
226
|
-
if (elementName !== "Text") return;
|
|
227
|
-
if (shouldIgnoreOptimization(path)) {
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
const binding = path.scope.getBinding(elementName);
|
|
231
|
-
if (!binding) return;
|
|
232
|
-
if (binding.kind === "module") {
|
|
233
|
-
const parentNode = binding.path.parent;
|
|
234
|
-
if (!core.types.isImportDeclaration(parentNode) || parentNode.source.value !== "react-native") {
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
298
|
+
if (isIgnoredLine(path)) return;
|
|
299
|
+
if (!isValidJSXComponent(path, "Text")) return;
|
|
300
|
+
if (!isReactNativeImport(path, "Text")) return;
|
|
238
301
|
if (hasBlacklistedProperty(path, textBlacklistedProperties)) return;
|
|
239
|
-
|
|
240
|
-
if (
|
|
302
|
+
const parent = path.parent;
|
|
303
|
+
if (hasInvalidChildren(path, parent)) return;
|
|
241
304
|
const hub = path.hub;
|
|
242
305
|
const file = typeof hub === "object" && hub !== null && "file" in hub ? hub.file : void 0;
|
|
243
306
|
if (!file) {
|
|
@@ -246,32 +309,69 @@ const textOptimizer = (path, log = () => {
|
|
|
246
309
|
const filename = ((_a = file.opts) == null ? void 0 : _a.filename) || "unknown file";
|
|
247
310
|
const lineNumber = (_c = (_b = path.node.loc) == null ? void 0 : _b.start.line) != null ? _c : "unknown line";
|
|
248
311
|
log(`Optimizing Text component in ${filename}:${lineNumber}`);
|
|
249
|
-
fixNegativeNumberOfLines({ path, log });
|
|
250
312
|
const originalAttributes = [...path.node.attributes];
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
313
|
+
fixNegativeNumberOfLines({ path, log });
|
|
314
|
+
processProps(path, file, originalAttributes);
|
|
315
|
+
replaceWithNativeComponent(path, parent, file, "NativeText");
|
|
316
|
+
};
|
|
317
|
+
function hasInvalidChildren(path, parent) {
|
|
318
|
+
for (const attribute of path.node.attributes) {
|
|
319
|
+
if (core.types.isJSXSpreadAttribute(attribute)) continue;
|
|
320
|
+
if (core.types.isJSXIdentifier(attribute.name) && attribute.value && // For a "children" attribute, optimization is allowed only if it is a string
|
|
321
|
+
attribute.name.name === "children" && !isStringNode(path, attribute.value)) {
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return !parent.children.every((child) => isStringNode(path, child));
|
|
326
|
+
}
|
|
327
|
+
function fixNegativeNumberOfLines({
|
|
328
|
+
path,
|
|
329
|
+
log
|
|
330
|
+
}) {
|
|
331
|
+
for (const attribute of path.node.attributes) {
|
|
332
|
+
if (core.types.isJSXAttribute(attribute) && core.types.isJSXIdentifier(attribute.name, { name: "numberOfLines" }) && attribute.value && core.types.isJSXExpressionContainer(attribute.value)) {
|
|
333
|
+
let originalValue;
|
|
334
|
+
if (core.types.isNumericLiteral(attribute.value.expression)) {
|
|
335
|
+
originalValue = attribute.value.expression.value;
|
|
336
|
+
} else if (core.types.isUnaryExpression(attribute.value.expression) && attribute.value.expression.operator === "-" && core.types.isNumericLiteral(attribute.value.expression.argument)) {
|
|
337
|
+
originalValue = -attribute.value.expression.argument.value;
|
|
338
|
+
}
|
|
339
|
+
if (originalValue !== void 0 && originalValue < 0) {
|
|
340
|
+
log(
|
|
341
|
+
`Warning: 'numberOfLines' in <Text> must be a non-negative number, received: ${originalValue}. The value will be set to 0.`
|
|
342
|
+
);
|
|
343
|
+
attribute.value.expression = core.types.numericLiteral(0);
|
|
344
|
+
}
|
|
256
345
|
}
|
|
257
346
|
}
|
|
258
|
-
|
|
259
|
-
|
|
347
|
+
}
|
|
348
|
+
function extractStyleAttribute(attributes) {
|
|
349
|
+
for (const attribute of attributes) {
|
|
350
|
+
if (core.types.isJSXAttribute(attribute) && core.types.isJSXIdentifier(attribute.name, { name: "style" })) {
|
|
351
|
+
if (attribute.value && core.types.isJSXExpressionContainer(attribute.value) && !core.types.isJSXEmptyExpression(attribute.value.expression)) {
|
|
352
|
+
return {
|
|
353
|
+
styleAttribute: attribute,
|
|
354
|
+
styleExpr: attribute.value.expression
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
return { styleAttribute: attribute };
|
|
358
|
+
}
|
|
260
359
|
}
|
|
360
|
+
return {};
|
|
361
|
+
}
|
|
362
|
+
function processProps(path, file, originalAttributes) {
|
|
363
|
+
const { styleExpr } = extractStyleAttribute(originalAttributes);
|
|
261
364
|
const hasA11y = hasAccessibilityProperty(path, originalAttributes);
|
|
262
365
|
if (styleExpr && hasA11y) {
|
|
263
|
-
const accessibilityAttributes = originalAttributes.filter(
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
return true;
|
|
268
|
-
});
|
|
366
|
+
const accessibilityAttributes = originalAttributes.filter(
|
|
367
|
+
(attribute) => !(core.types.isJSXAttribute(attribute) && core.types.isJSXIdentifier(attribute.name, { name: "style" }))
|
|
368
|
+
);
|
|
269
369
|
const normalizeIdentifier = addFileImportHint({
|
|
270
370
|
file,
|
|
271
371
|
nameHint: "normalizeAccessibilityProps",
|
|
272
372
|
path,
|
|
273
373
|
importName: "normalizeAccessibilityProps",
|
|
274
|
-
moduleName:
|
|
374
|
+
moduleName: RUNTIME_MODULE_NAME
|
|
275
375
|
});
|
|
276
376
|
const accessibilityObject = buildPropertiesFromAttributes(accessibilityAttributes);
|
|
277
377
|
const accessibilityExpr = core.types.callExpression(core.types.identifier(normalizeIdentifier.name), [accessibilityObject]);
|
|
@@ -280,7 +380,7 @@ const textOptimizer = (path, log = () => {
|
|
|
280
380
|
nameHint: "flattenTextStyle",
|
|
281
381
|
path,
|
|
282
382
|
importName: "flattenTextStyle",
|
|
283
|
-
moduleName:
|
|
383
|
+
moduleName: RUNTIME_MODULE_NAME
|
|
284
384
|
});
|
|
285
385
|
const flattenedStyleExpr = core.types.callExpression(core.types.identifier(flattenIdentifier.name), [styleExpr]);
|
|
286
386
|
path.node.attributes = [core.types.jsxSpreadAttribute(accessibilityExpr), core.types.jsxSpreadAttribute(flattenedStyleExpr)];
|
|
@@ -290,7 +390,7 @@ const textOptimizer = (path, log = () => {
|
|
|
290
390
|
nameHint: "flattenTextStyle",
|
|
291
391
|
path,
|
|
292
392
|
importName: "flattenTextStyle",
|
|
293
|
-
moduleName:
|
|
393
|
+
moduleName: RUNTIME_MODULE_NAME
|
|
294
394
|
});
|
|
295
395
|
const flattened = core.types.callExpression(core.types.identifier(flattenIdentifier.name), [styleExpr]);
|
|
296
396
|
path.node.attributes = [core.types.jsxSpreadAttribute(flattened)];
|
|
@@ -300,77 +400,12 @@ const textOptimizer = (path, log = () => {
|
|
|
300
400
|
nameHint: "normalizeAccessibilityProps",
|
|
301
401
|
path,
|
|
302
402
|
importName: "normalizeAccessibilityProps",
|
|
303
|
-
moduleName:
|
|
403
|
+
moduleName: RUNTIME_MODULE_NAME
|
|
304
404
|
});
|
|
305
405
|
const propsObject = buildPropertiesFromAttributes(originalAttributes);
|
|
306
406
|
const normalized = core.types.callExpression(core.types.identifier(normalizeIdentifier.name), [propsObject]);
|
|
307
407
|
path.node.attributes = [core.types.jsxSpreadAttribute(normalized)];
|
|
308
408
|
}
|
|
309
|
-
const nativeTextIdentifier = addFileImportHint({
|
|
310
|
-
file,
|
|
311
|
-
nameHint: "NativeText",
|
|
312
|
-
path,
|
|
313
|
-
importName: "NativeText",
|
|
314
|
-
moduleName: "react-native-boost"
|
|
315
|
-
});
|
|
316
|
-
path.node.name.name = nativeTextIdentifier.name;
|
|
317
|
-
if (!path.node.selfClosing && parent.closingElement && core.types.isJSXIdentifier(parent.closingElement.name) && parent.closingElement.name.name === "Text") {
|
|
318
|
-
parent.closingElement.name.name = nativeTextIdentifier.name;
|
|
319
|
-
}
|
|
320
|
-
};
|
|
321
|
-
function hasOnlyStringChildren(path, node) {
|
|
322
|
-
return node.children.every((child) => isStringNode(path, child));
|
|
323
|
-
}
|
|
324
|
-
function isStringNode(path, child) {
|
|
325
|
-
if (core.types.isJSXText(child) || core.types.isStringLiteral(child)) return true;
|
|
326
|
-
if (core.types.isJSXExpressionContainer(child)) {
|
|
327
|
-
const expression = child.expression;
|
|
328
|
-
if (core.types.isIdentifier(expression)) {
|
|
329
|
-
const binding = path.scope.getBinding(expression.name);
|
|
330
|
-
if (binding && binding.path.node && core.types.isVariableDeclarator(binding.path.node)) {
|
|
331
|
-
return !!binding.path.node.init && core.types.isStringLiteral(binding.path.node.init);
|
|
332
|
-
}
|
|
333
|
-
return false;
|
|
334
|
-
}
|
|
335
|
-
if (core.types.isStringLiteral(expression)) return true;
|
|
336
|
-
}
|
|
337
|
-
return false;
|
|
338
|
-
}
|
|
339
|
-
function fixNegativeNumberOfLines({
|
|
340
|
-
path,
|
|
341
|
-
log
|
|
342
|
-
}) {
|
|
343
|
-
for (const attribute of path.node.attributes) {
|
|
344
|
-
if (core.types.isJSXAttribute(attribute) && core.types.isJSXIdentifier(attribute.name, { name: "numberOfLines" }) && attribute.value && core.types.isJSXExpressionContainer(attribute.value)) {
|
|
345
|
-
let originalValue;
|
|
346
|
-
if (core.types.isNumericLiteral(attribute.value.expression)) {
|
|
347
|
-
originalValue = attribute.value.expression.value;
|
|
348
|
-
} else if (core.types.isUnaryExpression(attribute.value.expression) && attribute.value.expression.operator === "-" && core.types.isNumericLiteral(attribute.value.expression.argument)) {
|
|
349
|
-
originalValue = -attribute.value.expression.argument.value;
|
|
350
|
-
}
|
|
351
|
-
if (originalValue !== void 0 && originalValue < 0) {
|
|
352
|
-
log(
|
|
353
|
-
`Warning: 'numberOfLines' in <Text> must be a non-negative number, received: ${originalValue}. The value will be set to 0.`
|
|
354
|
-
);
|
|
355
|
-
attribute.value.expression = core.types.numericLiteral(0);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
function hasInvalidChildren(path) {
|
|
361
|
-
for (const attribute of path.node.attributes) {
|
|
362
|
-
if (core.types.isJSXSpreadAttribute(attribute)) continue;
|
|
363
|
-
if (core.types.isJSXIdentifier(attribute.name) && attribute.value) {
|
|
364
|
-
if (attribute.name.name === "children") {
|
|
365
|
-
if (!isStringNode(path, attribute.value)) {
|
|
366
|
-
return true;
|
|
367
|
-
}
|
|
368
|
-
} else if (textBlacklistedProperties.has(attribute.name.name)) {
|
|
369
|
-
return true;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
return false;
|
|
374
409
|
}
|
|
375
410
|
|
|
376
411
|
const log = (message) => {
|
|
@@ -412,20 +447,9 @@ const viewBlacklistedProperties = /* @__PURE__ */ new Set([
|
|
|
412
447
|
const viewOptimizer = (path, log = () => {
|
|
413
448
|
}) => {
|
|
414
449
|
var _a, _b, _c;
|
|
415
|
-
if (
|
|
416
|
-
|
|
417
|
-
if (!
|
|
418
|
-
const elementName = path.node.name.name;
|
|
419
|
-
if (elementName !== "View") return;
|
|
420
|
-
if (shouldIgnoreOptimization(path)) return;
|
|
421
|
-
const binding = path.scope.getBinding(elementName);
|
|
422
|
-
if (!binding) return;
|
|
423
|
-
if (binding.kind === "module") {
|
|
424
|
-
const parentNode = binding.path.parent;
|
|
425
|
-
if (!core.types.isImportDeclaration(parentNode) || parentNode.source.value !== "react-native") {
|
|
426
|
-
return;
|
|
427
|
-
}
|
|
428
|
-
}
|
|
450
|
+
if (isIgnoredLine(path)) return;
|
|
451
|
+
if (!isValidJSXComponent(path, "View")) return;
|
|
452
|
+
if (!isReactNativeImport(path, "View")) return;
|
|
429
453
|
if (hasBlacklistedProperty(path, viewBlacklistedProperties)) return;
|
|
430
454
|
if (hasTextAncestor(path)) return;
|
|
431
455
|
const hub = path.hub;
|
|
@@ -436,18 +460,8 @@ const viewOptimizer = (path, log = () => {
|
|
|
436
460
|
const filename = ((_a = file.opts) == null ? void 0 : _a.filename) || "unknown file";
|
|
437
461
|
const lineNumber = (_c = (_b = path.node.loc) == null ? void 0 : _b.start.line) != null ? _c : "unknown line";
|
|
438
462
|
log(`Optimizing View component in ${filename}:${lineNumber}`);
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
path,
|
|
442
|
-
importName: "NativeView",
|
|
443
|
-
moduleName: "react-native-boost",
|
|
444
|
-
importType: "named",
|
|
445
|
-
nameHint: "NativeView"
|
|
446
|
-
});
|
|
447
|
-
path.node.name.name = viewNativeIdentifier.name;
|
|
448
|
-
if (!path.node.selfClosing && parent.closingElement && core.types.isJSXIdentifier(parent.closingElement.name) && parent.closingElement.name.name === "View") {
|
|
449
|
-
parent.closingElement.name.name = viewNativeIdentifier.name;
|
|
450
|
-
}
|
|
463
|
+
const parent = path.parent;
|
|
464
|
+
replaceWithNativeComponent(path, parent, file, "NativeView");
|
|
451
465
|
};
|
|
452
466
|
function hasTextAncestor(path) {
|
|
453
467
|
return !!path.findParent((parentPath) => {
|