react-native-boost 0.3.0 โ†’ 0.4.1

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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  A powerful Babel plugin that automatically optimizes React Native apps through source code analysis and optimization. It identifies safe micro-optimization opportunities, which can lead to significant performance improvements.
6
6
 
7
7
  > [!WARNING]
8
- > This project is highly experimental and under active development. **Your app might break** and the optimization strategies used can change significantly between versions. Use with caution!
8
+ > The library and its Babel plugin are still experimental. You should expect things to break. Please report any issues you encounter in the issues tab with reproducible examples, and use the library's ignore mechanisms to disable optimizations for problematic files or lines of code.
9
9
 
10
10
  - โšก Automatic performance optimization through source code analysis
11
11
  - ๐Ÿ”’ Safe optimizations that don't break your app
@@ -14,12 +14,16 @@ A powerful Babel plugin that automatically optimizes React Native apps through s
14
14
  - ๐Ÿงช Works seamlessly with Expo
15
15
  - ๐ŸŽจ Configurable optimization strategies
16
16
 
17
+ ## Documentation
18
+
19
+ The documentation is available at [react-native-boost.oss.kuatsu.de](https://react-native-boost.oss.kuatsu.de).
20
+
17
21
  ## Benchmark
18
22
 
19
23
  The example app in the `apps/example` directory is a benchmark for the performance of the plugin.
20
24
 
21
25
  <div align="center">
22
- <img src="./packages/react-native-boost/img/benchmark.png" width="500" />
26
+ <img src="https://react-native-boost.oss.kuatsu.de/assets/images/benchmark-d60fdc78daeb03798d41c220bfed1f64.png" width="500" />
23
27
  <p>
24
28
  <b>1,000 Text components</b>: Render time of 1,000 Text components with and without React Native Boost.<br/>
25
29
  Measured in milliseconds on an iPhone 16 Pro in development mode and using New Architecture, lower is better.
@@ -44,63 +48,11 @@ module.exports = {
44
48
  };
45
49
  ```
46
50
 
47
- That's it! No imports in your code, pod installing, or anything else is required.
48
-
49
- Optionally, you can configure the plugin to log optimized files to the console and disable specific optimizations:
50
-
51
- ```js
52
- module.exports = {
53
- plugins: [
54
- [
55
- 'react-native-boost/plugin',
56
- {
57
- verbose: true,
58
- optimizations: {
59
- text: false,
60
- },
61
- },
62
- ],
63
- ],
64
- };
65
- ```
66
-
67
- You can also skip optimization for a specific comment using a decorator comment above the component's opening tag:
68
-
69
- ```jsx
70
- // @boost-ignore
71
- <Text>This will not be optimized.</Text>
72
- ```
51
+ That's it! No imports in your code, pod installing, or anything else is required. Optionally, you can configure the plugin with a few options. See the [documentation](https://react-native-boost.oss.kuatsu.de/docs/babel-plugin/configure) for more information.
73
52
 
74
53
  ## How It Works
75
54
 
76
- Several standard components in React Native are actually wrappers around their native counterparts. These wrappers often only handle edge cases and aren't needed in most cases. However, they add additional runtime overhead and depth to the component tree, which can lead to performance bottlenecks.
77
-
78
- React Native Boost replaces these wrapper components directly with their respective native components, flattening the component tree. It intelligently analyzes your code and only optimizes components that are used in a way where they can be optimized without breaking the app.
79
-
80
- Here's an example of how it works:
81
-
82
- ```jsx
83
- // Your original code ๐ŸŒ
84
- import React from 'react';
85
- import { View, Text } from 'react-native';
86
-
87
- const MyComponent = () => (
88
- <View>
89
- <Text>Hello, World!</Text>
90
- </View>
91
- );
92
-
93
- // Automagically transformed to โœจ
94
- import React from 'react';
95
- import { View } from 'react-native';
96
- import { NativeText } from 'react-native/Libraries/Text/TextNativeComponent';
97
-
98
- const MyComponent = () => (
99
- <View>
100
- <NativeText>Hello, World!</NativeText>
101
- </View>
102
- );
103
- ```
55
+ A technical rundown of how the plugin works can be found in the [docs](https://react-native-boost.oss.kuatsu.de/docs/introduction/how-it-works).
104
56
 
105
57
  ## Contributing
106
58
 
@@ -1,6 +1,8 @@
1
1
  import { declare } from '@babel/helper-plugin-utils';
2
2
  import { types } from '@babel/core';
3
- import { addNamed } from '@babel/helper-module-imports';
3
+ import { addNamed, addDefault } from '@babel/helper-module-imports';
4
+ import { minimatch } from 'minimatch';
5
+ import path from 'node:path';
4
6
 
5
7
  class PluginError extends Error {
6
8
  constructor(message) {
@@ -14,12 +16,28 @@ const ensureArray = (value) => {
14
16
  return [value];
15
17
  };
16
18
 
17
- const shouldIgnoreOptimization = (path) => {
19
+ const isIgnoredFile = (p, ignores) => {
20
+ const hub = p.hub;
21
+ const file = typeof hub === "object" && hub !== null && "file" in hub ? hub.file : void 0;
22
+ if (!file) {
23
+ throw new PluginError("No file found in Babel hub");
24
+ }
25
+ const fileName = file.opts.filename;
26
+ const baseDirectory = "cwd" in file.opts ? file.opts.cwd : process.cwd();
27
+ for (const pattern of ignores) {
28
+ const absolutePattern = path.isAbsolute(pattern) ? pattern : path.join(baseDirectory, pattern);
29
+ if (minimatch(fileName, absolutePattern, { dot: true })) {
30
+ return true;
31
+ }
32
+ }
33
+ return false;
34
+ };
35
+ const shouldIgnoreOptimization = (path2) => {
18
36
  var _a, _b, _c;
19
- if ((_a = path.node.leadingComments) == null ? void 0 : _a.some((comment) => comment.value.includes("@boost-ignore"))) {
37
+ if ((_a = path2.node.leadingComments) == null ? void 0 : _a.some((comment) => comment.value.includes("@boost-ignore"))) {
20
38
  return true;
21
39
  }
22
- const jsxElementPath = path.parentPath;
40
+ const jsxElementPath = path2.parentPath;
23
41
  if ((_b = jsxElementPath.node.leadingComments) == null ? void 0 : _b.some((comment) => comment.value.includes("@boost-ignore"))) {
24
42
  return true;
25
43
  }
@@ -57,7 +75,63 @@ const shouldIgnoreOptimization = (path) => {
57
75
  }
58
76
  return false;
59
77
  };
78
+ const hasBlacklistedProperty = (path2, blacklist) => {
79
+ return path2.node.attributes.some((attribute) => {
80
+ if (types.isJSXSpreadAttribute(attribute)) {
81
+ if (types.isIdentifier(attribute.argument)) {
82
+ const binding = path2.scope.getBinding(attribute.argument.name);
83
+ let objectExpression;
84
+ if (binding) {
85
+ if (types.isVariableDeclarator(binding.path.node)) {
86
+ objectExpression = binding.path.node.init;
87
+ } else if (types.isObjectExpression(binding.path.node)) {
88
+ objectExpression = binding.path.node;
89
+ }
90
+ }
91
+ if (objectExpression && types.isObjectExpression(objectExpression)) {
92
+ return objectExpression.properties.some((property) => {
93
+ if (types.isObjectProperty(property) && types.isIdentifier(property.key)) {
94
+ return blacklist.has(property.key.name);
95
+ }
96
+ return false;
97
+ });
98
+ }
99
+ }
100
+ return true;
101
+ }
102
+ return false;
103
+ });
104
+ };
60
105
 
106
+ const textBlacklistedProperties = /* @__PURE__ */ new Set([
107
+ "accessible",
108
+ "accessibilityLabel",
109
+ "accessibilityState",
110
+ "allowFontScaling",
111
+ "aria-busy",
112
+ "aria-checked",
113
+ "aria-disabled",
114
+ "aria-expanded",
115
+ "aria-label",
116
+ "aria-selected",
117
+ "ellipsizeMode",
118
+ "id",
119
+ "nativeID",
120
+ "onLongPress",
121
+ "onPress",
122
+ "onPressIn",
123
+ "onPressOut",
124
+ "onResponderGrant",
125
+ "onResponderMove",
126
+ "onResponderRelease",
127
+ "onResponderTerminate",
128
+ "onResponderTerminationRequest",
129
+ "onStartShouldSetResponder",
130
+ "pressRetentionOffset",
131
+ "suppressHighlighting",
132
+ "selectable",
133
+ "selectionColor"
134
+ ]);
61
135
  const textOptimizer = (path, log = () => {
62
136
  }) => {
63
137
  var _a, _b, _c;
@@ -77,7 +151,8 @@ const textOptimizer = (path, log = () => {
77
151
  return;
78
152
  }
79
153
  }
80
- if (hasBlacklistedProperties(path)) return;
154
+ if (hasBlacklistedProperty(path, textBlacklistedProperties)) return;
155
+ if (hasInvalidChildren(path)) return;
81
156
  if (!hasOnlyStringChildren(path, parent)) return;
82
157
  const hub = path.hub;
83
158
  const file = typeof hub === "object" && hub !== null && "file" in hub ? hub.file : void 0;
@@ -115,34 +190,6 @@ function isStringNode(path, child) {
115
190
  }
116
191
  return false;
117
192
  }
118
- const blacklistedProperties = /* @__PURE__ */ new Set([
119
- "accessible",
120
- "accessibilityLabel",
121
- "accessibilityState",
122
- "allowFontScaling",
123
- "aria-busy",
124
- "aria-checked",
125
- "aria-disabled",
126
- "aria-expanded",
127
- "aria-label",
128
- "aria-selected",
129
- "ellipsizeMode",
130
- "id",
131
- "nativeID",
132
- "onLongPress",
133
- "onPress",
134
- "onPressIn",
135
- "onPressOut",
136
- "onResponderGrant",
137
- "onResponderMove",
138
- "onResponderRelease",
139
- "onResponderTerminate",
140
- "onResponderTerminationRequest",
141
- "onStartShouldSetResponder",
142
- "pressRetentionOffset",
143
- "suppressHighlighting",
144
- "selectionColor"
145
- ]);
146
193
  function fixNegativeNumberOfLines({
147
194
  path,
148
195
  log
@@ -183,55 +230,115 @@ function optimizeStyleTag({ path, file }) {
183
230
  file.__hasImports.flattenTextStyle = addNamed(path, "flattenTextStyle", "react-native-boost", { nameHint });
184
231
  }
185
232
  }
186
- function hasBlacklistedProperties(path) {
187
- return path.node.attributes.some((attribute) => {
188
- if (types.isJSXSpreadAttribute(attribute)) {
189
- if (types.isIdentifier(attribute.argument)) {
190
- const binding = path.scope.getBinding(attribute.argument.name);
191
- let objectExpression;
192
- if (binding) {
193
- if (types.isVariableDeclarator(binding.path.node)) {
194
- objectExpression = binding.path.node.init;
195
- } else if (types.isObjectExpression(binding.path.node)) {
196
- objectExpression = binding.path.node;
197
- }
198
- }
199
- if (objectExpression && types.isObjectExpression(objectExpression)) {
200
- return objectExpression.properties.some((property) => {
201
- if (types.isObjectProperty(property) && types.isIdentifier(property.key)) {
202
- return blacklistedProperties.has(property.key.name);
203
- }
204
- return false;
205
- });
206
- }
207
- }
208
- return true;
209
- }
233
+ function hasInvalidChildren(path) {
234
+ for (const attribute of path.node.attributes) {
235
+ if (types.isJSXSpreadAttribute(attribute)) return false;
210
236
  if (types.isJSXIdentifier(attribute.name) && attribute.value) {
211
237
  if (attribute.name.name === "children") {
212
238
  return isStringNode(path, attribute.value);
213
239
  }
214
- return blacklistedProperties.has(attribute.name.name);
240
+ return textBlacklistedProperties.has(attribute.name.name);
215
241
  }
216
- return false;
217
- });
242
+ }
243
+ return false;
218
244
  }
219
245
 
220
246
  const log = (message) => {
221
247
  console.log(`[react-native-boost] ${message}`);
222
248
  };
223
249
 
250
+ const viewBlacklistedProperties = /* @__PURE__ */ new Set([
251
+ "accessible",
252
+ "accessibilityLabel",
253
+ "accessibilityState",
254
+ "allowFontScaling",
255
+ "aria-busy",
256
+ "aria-checked",
257
+ "aria-disabled",
258
+ "aria-expanded",
259
+ "aria-label",
260
+ "aria-selected",
261
+ "ellipsizeMode",
262
+ "disabled",
263
+ "id",
264
+ "nativeID",
265
+ "numberOfLines",
266
+ "onLongPress",
267
+ "onPress",
268
+ "onPressIn",
269
+ "onPressOut",
270
+ "onResponderGrant",
271
+ "onResponderMove",
272
+ "onResponderRelease",
273
+ "onResponderTerminate",
274
+ "onResponderTerminationRequest",
275
+ "onStartShouldSetResponder",
276
+ "pressRetentionOffset",
277
+ "selectable",
278
+ "selectionColor",
279
+ "suppressHighlighting",
280
+ "style"
281
+ ]);
282
+ const viewOptimizer = (path, log = () => {
283
+ }) => {
284
+ var _a, _b, _c;
285
+ if (!types.isJSXIdentifier(path.node.name)) return;
286
+ const parent = path.parent;
287
+ if (!types.isJSXElement(parent)) return;
288
+ const elementName = path.node.name.name;
289
+ if (elementName !== "View") return;
290
+ if (shouldIgnoreOptimization(path)) return;
291
+ const binding = path.scope.getBinding(elementName);
292
+ if (!binding) return;
293
+ if (binding.kind === "module") {
294
+ const parentNode = binding.path.parent;
295
+ if (!types.isImportDeclaration(parentNode) || parentNode.source.value !== "react-native") {
296
+ return;
297
+ }
298
+ }
299
+ if (hasBlacklistedProperty(path, viewBlacklistedProperties)) return;
300
+ if (hasTextAncestor(path)) return;
301
+ const hub = path.hub;
302
+ const file = typeof hub === "object" && hub !== null && "file" in hub ? hub.file : void 0;
303
+ if (!file) {
304
+ throw new PluginError("No file found in Babel hub");
305
+ }
306
+ const filename = ((_a = file.opts) == null ? void 0 : _a.filename) || "unknown file";
307
+ const lineNumber = (_c = (_b = path.node.loc) == null ? void 0 : _b.start.line) != null ? _c : "unknown line";
308
+ log(`Optimizing View component in ${filename}:${lineNumber}`);
309
+ if (!file.__hasImports) {
310
+ file.__hasImports = {};
311
+ }
312
+ if (!file.__hasImports.ViewNativeComponent) {
313
+ file.__hasImports.NativeView = addDefault(path, "react-native/Libraries/Components/View/ViewNativeComponent", {
314
+ nameHint: "NativeView"
315
+ });
316
+ }
317
+ const viewNativeIdentifier = file.__hasImports.NativeView;
318
+ path.node.name.name = viewNativeIdentifier.name;
319
+ if (!path.node.selfClosing && parent.closingElement && types.isJSXIdentifier(parent.closingElement.name) && parent.closingElement.name.name === "View") {
320
+ parent.closingElement.name.name = viewNativeIdentifier.name;
321
+ }
322
+ };
323
+ function hasTextAncestor(path) {
324
+ return !!path.findParent((parentPath) => {
325
+ return types.isJSXElement(parentPath.node) && types.isJSXIdentifier(parentPath.node.openingElement.name, { name: "Text" });
326
+ });
327
+ }
328
+
224
329
  var index = declare((api) => {
225
330
  api.assertVersion(7);
226
331
  return {
227
332
  name: "react-native-boost",
228
333
  visitor: {
229
334
  JSXOpeningElement(path, state) {
230
- var _a, _b;
335
+ var _a, _b, _c, _d;
231
336
  const options = (_a = state.opts) != null ? _a : {};
232
337
  const logger = options.verbose ? log : () => {
233
338
  };
234
- if (((_b = options.optimizations) == null ? void 0 : _b.text) !== false) textOptimizer(path, logger);
339
+ if (isIgnoredFile(path, (_b = options.ignores) != null ? _b : [])) return;
340
+ if (((_c = options.optimizations) == null ? void 0 : _c.text) !== false) textOptimizer(path, logger);
341
+ if (((_d = options.optimizations) == null ? void 0 : _d.view) !== false) viewOptimizer(path, logger);
235
342
  }
236
343
  }
237
344
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../../../src/plugin/utils/plugin-error.ts","../../../src/plugin/utils/helpers.ts","../../../src/plugin/utils/common.ts","../../../src/plugin/optimizers/text/index.ts","../../../src/plugin/utils/logger.ts","../../../src/plugin/index.ts"],"sourcesContent":["export default class PluginError extends Error {\n constructor(message: string) {\n super(`[react-native-boost] Babel plugin exception: ${message}`);\n this.name = 'PluginError';\n }\n}\n","export const ensureArray = <T>(value: T | T[]): T[] => {\n if (Array.isArray(value)) return value;\n return [value];\n};\n","import { NodePath, types as t } from '@babel/core';\nimport { ensureArray } from './helpers';\n\n/**\n * Checks if the JSX element should be ignored based on a preceding comment.\n *\n * The function looks up the JSXOpeningElement's own leading comments as well as\n * the parent element's comments before falling back to inspect siblings.\n */\nexport const shouldIgnoreOptimization = (path: NodePath<t.JSXOpeningElement>): boolean => {\n // Check for @boost-ignore in the leading comments on the JSX opening element.\n if (path.node.leadingComments?.some((comment) => comment.value.includes('@boost-ignore'))) {\n return true;\n }\n\n // Check for @boost-ignore in the leading comments on the parent JSX element.\n const jsxElementPath = path.parentPath;\n if (jsxElementPath.node.leadingComments?.some((comment) => comment.value.includes('@boost-ignore'))) {\n return true;\n }\n\n // NEW: Check for @boost-ignore in the leading comments on the ObjectProperty (if it exists)\n // This handles cases where the JSX element is used as a value inside an object literal.\n const propertyPath = jsxElementPath.parentPath;\n if (\n propertyPath &&\n propertyPath.isObjectProperty() &&\n propertyPath.node.leadingComments?.some((comment) => comment.value.includes('@boost-ignore'))\n ) {\n return true;\n }\n\n if (!jsxElementPath.parentPath) return false;\n\n // Get the container that holds this element (for example, a JSX fragment or JSX element)\n const containerPath = jsxElementPath.parentPath;\n const siblings = ensureArray(containerPath.get('children'));\n const index = siblings.findIndex((sibling) => sibling.node === jsxElementPath.node);\n if (index === -1) return false;\n\n // Look backward from the current element for a non-empty node.\n for (let index_ = index - 1; index_ >= 0; index_--) {\n const sibling = siblings[index_];\n // Skip over any whitespace (only in JSXText nodes)\n if (sibling.isJSXText() && sibling.node.value.trim() === '') {\n continue;\n }\n // If the sibling is a JSX expression container, check its empty expression's comments.\n if (sibling.isJSXExpressionContainer()) {\n const expression = sibling.get('expression');\n if (expression && expression.node) {\n const comments = [\n ...(expression.node.leadingComments || []),\n ...(expression.node.trailingComments || []),\n ...(expression.node.innerComments || []),\n ].map((comment) => comment.value.trim());\n if (comments.some((comment) => comment.includes('@boost-ignore'))) {\n return true;\n }\n }\n }\n // Also check if the node itself carries a leadingComments property.\n if (\n sibling.node.leadingComments &&\n sibling.node.leadingComments.some((comment) => comment.value.includes('@boost-ignore'))\n ) {\n return true;\n }\n break; // if the immediate non-whitespace node is not our ignore marker, stop\n }\n return false;\n};\n","import { NodePath, types as t } from '@babel/core';\nimport { addNamed } from '@babel/helper-module-imports';\nimport { HubFile, Optimizer } from '../../types';\nimport PluginError from '../../utils/plugin-error';\nimport { shouldIgnoreOptimization } from '../../utils/common';\n\nexport const textOptimizer: Optimizer = (path, log = () => {}) => {\n // Ensure we're processing a JSX Text element\n if (!t.isJSXIdentifier(path.node.name)) return;\n\n const parent = path.parent;\n if (!t.isJSXElement(parent)) return;\n\n const elementName = path.node.name.name;\n if (elementName !== 'Text') return;\n\n // If the component is preceded by an ignore comment, do not optimize.\n if (shouldIgnoreOptimization(path)) {\n return;\n }\n\n // Ensure Text element comes from react-native\n const binding = path.scope.getBinding(elementName);\n if (!binding) return;\n if (binding.kind === 'module') {\n const parentNode = binding.path.parent;\n if (!t.isImportDeclaration(parentNode) || parentNode.source.value !== 'react-native') {\n return;\n }\n }\n\n // Bail if the element has any blacklisted properties or non-string children props\n if (hasBlacklistedProperties(path)) return;\n if (!hasOnlyStringChildren(path, parent)) return;\n\n // Extract the file from the Babel hub and add flags for logging & import caching\n const hub = path.hub as unknown;\n const file = typeof hub === 'object' && hub !== null && 'file' in hub ? (hub.file as HubFile) : undefined;\n\n if (!file) {\n throw new PluginError('No file found in Babel hub');\n }\n\n const filename = file.opts?.filename || 'unknown file';\n const lineNumber = path.node.loc?.start.line ?? 'unknown line';\n log(`Optimizing Text component in ${filename}:${lineNumber}`);\n\n // Optimize props\n fixNegativeNumberOfLines({ path, log });\n optimizeStyleTag({ path, file });\n\n // Add TextNativeComponent import (cached on file) so we only add it once per file\n if (!file.__hasImports) {\n file.__hasImports = {};\n }\n if (!file.__hasImports.NativeText) {\n file.__hasImports.NativeText = addNamed(path, 'NativeText', 'react-native/Libraries/Text/TextNativeComponent');\n }\n const nativeTextIdentifier = file.__hasImports.NativeText;\n path.node.name.name = nativeTextIdentifier.name;\n\n // If the element is not self-closing, update the closing element as well\n if (\n !path.node.selfClosing &&\n parent.closingElement &&\n t.isJSXIdentifier(parent.closingElement.name) &&\n parent.closingElement.name.name === 'Text'\n ) {\n parent.closingElement.name.name = nativeTextIdentifier.name;\n }\n};\n\nfunction hasOnlyStringChildren(path: NodePath<t.JSXOpeningElement>, node: t.JSXElement): boolean {\n return node.children.every((child) => isStringNode(path, child));\n}\n\nfunction isStringNode(path: NodePath<t.JSXOpeningElement>, child: t.Node): boolean {\n if (t.isJSXText(child)) return true;\n\n // Check for JSX expressions\n if (t.isJSXExpressionContainer(child)) {\n const expression = child.expression;\n\n // If the expression is an identifier, look it up in the current scope\n if (t.isIdentifier(expression)) {\n const binding = path.scope.getBinding(expression.name);\n return binding ? t.isStringLiteral(binding.path.node) : false;\n }\n }\n return false;\n}\n\nconst blacklistedProperties = new Set([\n 'accessible',\n 'accessibilityLabel',\n 'accessibilityState',\n 'allowFontScaling',\n 'aria-busy',\n 'aria-checked',\n 'aria-disabled',\n 'aria-expanded',\n 'aria-label',\n 'aria-selected',\n 'ellipsizeMode',\n 'id',\n 'nativeID',\n 'onLongPress',\n 'onPress',\n 'onPressIn',\n 'onPressOut',\n 'onResponderGrant',\n 'onResponderMove',\n 'onResponderRelease',\n 'onResponderTerminate',\n 'onResponderTerminationRequest',\n 'onStartShouldSetResponder',\n 'pressRetentionOffset',\n 'suppressHighlighting',\n 'selectionColor',\n]);\n\nfunction fixNegativeNumberOfLines({\n path,\n log,\n}: {\n path: NodePath<t.JSXOpeningElement>;\n log: (message: string) => void;\n}) {\n for (const attribute of path.node.attributes) {\n if (\n t.isJSXAttribute(attribute) &&\n t.isJSXIdentifier(attribute.name, { name: 'numberOfLines' }) &&\n attribute.value &&\n t.isJSXExpressionContainer(attribute.value)\n ) {\n let originalValue: number | undefined;\n if (t.isNumericLiteral(attribute.value.expression)) {\n originalValue = attribute.value.expression.value;\n } else if (\n t.isUnaryExpression(attribute.value.expression) &&\n attribute.value.expression.operator === '-' &&\n t.isNumericLiteral(attribute.value.expression.argument)\n ) {\n originalValue = -attribute.value.expression.argument.value;\n }\n if (originalValue !== undefined && originalValue < 0) {\n log(\n `Warning: 'numberOfLines' in <Text> must be a non-negative number, received: ${originalValue}. The value will be set to 0.`\n );\n attribute.value.expression = t.numericLiteral(0);\n }\n }\n }\n}\n\nfunction optimizeStyleTag({ path, file }: { path: NodePath<t.JSXOpeningElement>; file: HubFile }) {\n let shouldImportFlattenTextStyle = false;\n const nameHint = '_flattenTextStyle';\n\n for (const [index, attribute] of path.node.attributes.entries()) {\n if (t.isJSXAttribute(attribute) && t.isJSXIdentifier(attribute.name, { name: 'style' })) {\n shouldImportFlattenTextStyle = true;\n\n if (t.isJSXExpressionContainer(attribute.value) && !t.isJSXEmptyExpression(attribute.value.expression)) {\n path.node.attributes[index] = t.jsxSpreadAttribute(\n t.callExpression(t.identifier(nameHint), [attribute.value.expression])\n );\n }\n }\n }\n\n if (shouldImportFlattenTextStyle && !file.__hasImports?.flattenTextStyle) {\n if (!file.__hasImports) file.__hasImports = {};\n file.__hasImports.flattenTextStyle = addNamed(path, 'flattenTextStyle', 'react-native-boost', { nameHint });\n }\n}\n\nfunction hasBlacklistedProperties(path: NodePath<t.JSXOpeningElement>): boolean {\n return path.node.attributes.some((attribute) => {\n // Check if we can resolve the spread attribute\n if (t.isJSXSpreadAttribute(attribute)) {\n if (t.isIdentifier(attribute.argument)) {\n const binding = path.scope.getBinding(attribute.argument.name);\n let objectExpression: t.ObjectExpression | undefined;\n if (binding) {\n // If the binding node is a VariableDeclarator, use its initializer\n if (t.isVariableDeclarator(binding.path.node)) {\n objectExpression = binding.path.node.init as t.ObjectExpression;\n } else if (t.isObjectExpression(binding.path.node)) {\n objectExpression = binding.path.node;\n }\n }\n if (objectExpression && t.isObjectExpression(objectExpression)) {\n return objectExpression.properties.some((property) => {\n if (t.isObjectProperty(property) && t.isIdentifier(property.key)) {\n return blacklistedProperties.has(property.key.name);\n }\n return false;\n });\n }\n }\n // Bail if we can't resolve the spread attribute\n return true;\n }\n\n if (t.isJSXIdentifier(attribute.name) && attribute.value) {\n // For a \"children\" attribute, optimization is allowed only if it is a string\n if (attribute.name.name === 'children') {\n return isStringNode(path, attribute.value);\n }\n return blacklistedProperties.has(attribute.name.name);\n }\n\n // For other attribute types (e.g. namespaced), assume no blacklisting\n return false;\n });\n}\n","export const log = (message: string) => {\n console.log(`[react-native-boost] ${message}`);\n};\n","import { declare } from '@babel/helper-plugin-utils';\nimport { textOptimizer } from './optimizers/text';\nimport { PluginOptions } from './types';\nimport { log } from './utils/logger';\n\nexport default declare((api) => {\n api.assertVersion(7);\n\n return {\n name: 'react-native-boost',\n visitor: {\n JSXOpeningElement(path, state) {\n const options = (state.opts ?? {}) as PluginOptions;\n const logger = options.verbose ? log : () => {};\n if (options.optimizations?.text !== false) textOptimizer(path, logger);\n },\n },\n };\n});\n"],"names":["t"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../../../src/plugin/utils/plugin-error.ts","../../../src/plugin/utils/helpers.ts","../../../src/plugin/utils/common.ts","../../../src/plugin/optimizers/text/index.ts","../../../src/plugin/utils/logger.ts","../../../src/plugin/optimizers/view/index.ts","../../../src/plugin/index.ts"],"sourcesContent":["export default class PluginError extends Error {\n constructor(message: string) {\n super(`[react-native-boost] Babel plugin exception: ${message}`);\n this.name = 'PluginError';\n }\n}\n","export const ensureArray = <T>(value: T | T[]): T[] => {\n if (Array.isArray(value)) return value;\n return [value];\n};\n","import { NodePath, types as t } from '@babel/core';\nimport { ensureArray } from './helpers';\nimport { HubFile } from '../types';\nimport { minimatch } from 'minimatch';\nimport path from 'node:path';\nimport PluginError from './plugin-error';\n\n/**\n * Checks if the file is in the list of ignored files.\n *\n * @param p - The path to the JSXOpeningElement.\n * @param ignores - List of glob paths (absolute or relative to import.meta.dirname).\n * @returns true if the file matches any of the ignore patterns.\n */\nexport const isIgnoredFile = (p: NodePath<t.JSXOpeningElement>, ignores: string[]): boolean => {\n const hub = p.hub as unknown;\n const file = typeof hub === 'object' && hub !== null && 'file' in hub ? (hub.file as HubFile) : undefined;\n\n if (!file) {\n throw new PluginError('No file found in Babel hub');\n }\n\n const fileName = file.opts.filename;\n\n // Use the current working directory which typically corresponds to the user's project root.\n const baseDirectory = 'cwd' in file.opts ? (file.opts.cwd as string) : process.cwd();\n\n // Iterate through the ignore patterns.\n for (const pattern of ignores) {\n // If the pattern is not absolute, join it with the baseDir\n const absolutePattern = path.isAbsolute(pattern) ? pattern : path.join(baseDirectory, pattern);\n\n // Check if the file name matches the glob pattern.\n if (minimatch(fileName, absolutePattern, { dot: true })) {\n return true;\n }\n }\n\n return false;\n};\n\n/**\n * Checks if the JSX element should be ignored based on a preceding comment.\n *\n * The function looks up the JSXOpeningElement's own leading comments as well as\n * the parent element's comments before falling back to inspect siblings.\n */\nexport const shouldIgnoreOptimization = (path: NodePath<t.JSXOpeningElement>): boolean => {\n // Check for @boost-ignore in the leading comments on the JSX opening element.\n if (path.node.leadingComments?.some((comment) => comment.value.includes('@boost-ignore'))) {\n return true;\n }\n\n // Check for @boost-ignore in the leading comments on the parent JSX element.\n const jsxElementPath = path.parentPath;\n if (jsxElementPath.node.leadingComments?.some((comment) => comment.value.includes('@boost-ignore'))) {\n return true;\n }\n\n // NEW: Check for @boost-ignore in the leading comments on the ObjectProperty (if it exists)\n // This handles cases where the JSX element is used as a value inside an object literal.\n const propertyPath = jsxElementPath.parentPath;\n if (\n propertyPath &&\n propertyPath.isObjectProperty() &&\n propertyPath.node.leadingComments?.some((comment) => comment.value.includes('@boost-ignore'))\n ) {\n return true;\n }\n\n if (!jsxElementPath.parentPath) return false;\n\n // Get the container that holds this element (for example, a JSX fragment or JSX element)\n const containerPath = jsxElementPath.parentPath;\n const siblings = ensureArray(containerPath.get('children'));\n const index = siblings.findIndex((sibling) => sibling.node === jsxElementPath.node);\n if (index === -1) return false;\n\n // Look backward from the current element for a non-empty node.\n for (let index_ = index - 1; index_ >= 0; index_--) {\n const sibling = siblings[index_];\n // Skip over any whitespace (only in JSXText nodes)\n if (sibling.isJSXText() && sibling.node.value.trim() === '') {\n continue;\n }\n // If the sibling is a JSX expression container, check its empty expression's comments.\n if (sibling.isJSXExpressionContainer()) {\n const expression = sibling.get('expression');\n if (expression && expression.node) {\n const comments = [\n ...(expression.node.leadingComments || []),\n ...(expression.node.trailingComments || []),\n ...(expression.node.innerComments || []),\n ].map((comment) => comment.value.trim());\n if (comments.some((comment) => comment.includes('@boost-ignore'))) {\n return true;\n }\n }\n }\n // Also check if the node itself carries a leadingComments property.\n if (\n sibling.node.leadingComments &&\n sibling.node.leadingComments.some((comment) => comment.value.includes('@boost-ignore'))\n ) {\n return true;\n }\n break; // if the immediate non-whitespace node is not our ignore marker, stop\n }\n return false;\n};\n\nexport const hasBlacklistedProperty = (path: NodePath<t.JSXOpeningElement>, blacklist: Set<string>): boolean => {\n return path.node.attributes.some((attribute) => {\n // Check if we can resolve the spread attribute\n if (t.isJSXSpreadAttribute(attribute)) {\n if (t.isIdentifier(attribute.argument)) {\n const binding = path.scope.getBinding(attribute.argument.name);\n let objectExpression: t.ObjectExpression | undefined;\n if (binding) {\n // If the binding node is a VariableDeclarator, use its initializer\n if (t.isVariableDeclarator(binding.path.node)) {\n objectExpression = binding.path.node.init as t.ObjectExpression;\n } else if (t.isObjectExpression(binding.path.node)) {\n objectExpression = binding.path.node;\n }\n }\n if (objectExpression && t.isObjectExpression(objectExpression)) {\n return objectExpression.properties.some((property) => {\n if (t.isObjectProperty(property) && t.isIdentifier(property.key)) {\n return blacklist.has(property.key.name);\n }\n return false;\n });\n }\n }\n // Bail if we can't resolve the spread attribute\n return true;\n }\n\n // For other attribute types (e.g. namespaced), assume no blacklisting\n return false;\n });\n};\n","import { NodePath, types as t } from '@babel/core';\nimport { addNamed } from '@babel/helper-module-imports';\nimport { HubFile, Optimizer } from '../../types';\nimport PluginError from '../../utils/plugin-error';\nimport { hasBlacklistedProperty, shouldIgnoreOptimization } from '../../utils/common';\n\nexport const textBlacklistedProperties = new Set([\n 'accessible',\n 'accessibilityLabel',\n 'accessibilityState',\n 'allowFontScaling',\n 'aria-busy',\n 'aria-checked',\n 'aria-disabled',\n 'aria-expanded',\n 'aria-label',\n 'aria-selected',\n 'ellipsizeMode',\n 'id',\n 'nativeID',\n 'onLongPress',\n 'onPress',\n 'onPressIn',\n 'onPressOut',\n 'onResponderGrant',\n 'onResponderMove',\n 'onResponderRelease',\n 'onResponderTerminate',\n 'onResponderTerminationRequest',\n 'onStartShouldSetResponder',\n 'pressRetentionOffset',\n 'suppressHighlighting',\n 'selectable',\n 'selectionColor',\n]);\n\nexport const textOptimizer: Optimizer = (path, log = () => {}) => {\n // Ensure we're processing a JSX Text element\n if (!t.isJSXIdentifier(path.node.name)) return;\n\n const parent = path.parent;\n if (!t.isJSXElement(parent)) return;\n\n const elementName = path.node.name.name;\n if (elementName !== 'Text') return;\n\n // If the component is preceded by an ignore comment, do not optimize.\n if (shouldIgnoreOptimization(path)) {\n return;\n }\n\n // Ensure Text element comes from react-native\n const binding = path.scope.getBinding(elementName);\n if (!binding) return;\n if (binding.kind === 'module') {\n const parentNode = binding.path.parent;\n if (!t.isImportDeclaration(parentNode) || parentNode.source.value !== 'react-native') {\n return;\n }\n }\n\n // Bail if the element has any blacklisted properties or non-string children props\n if (hasBlacklistedProperty(path, textBlacklistedProperties)) return;\n if (hasInvalidChildren(path)) return;\n if (!hasOnlyStringChildren(path, parent)) return;\n\n // Extract the file from the Babel hub and add flags for logging & import caching\n const hub = path.hub as unknown;\n const file = typeof hub === 'object' && hub !== null && 'file' in hub ? (hub.file as HubFile) : undefined;\n\n if (!file) {\n throw new PluginError('No file found in Babel hub');\n }\n\n const filename = file.opts?.filename || 'unknown file';\n const lineNumber = path.node.loc?.start.line ?? 'unknown line';\n log(`Optimizing Text component in ${filename}:${lineNumber}`);\n\n // Optimize props\n fixNegativeNumberOfLines({ path, log });\n optimizeStyleTag({ path, file });\n\n // Add TextNativeComponent import (cached on file) so we only add it once per file\n if (!file.__hasImports) {\n file.__hasImports = {};\n }\n if (!file.__hasImports.NativeText) {\n file.__hasImports.NativeText = addNamed(path, 'NativeText', 'react-native/Libraries/Text/TextNativeComponent');\n }\n const nativeTextIdentifier = file.__hasImports.NativeText;\n path.node.name.name = nativeTextIdentifier.name;\n\n // If the element is not self-closing, update the closing element as well\n if (\n !path.node.selfClosing &&\n parent.closingElement &&\n t.isJSXIdentifier(parent.closingElement.name) &&\n parent.closingElement.name.name === 'Text'\n ) {\n parent.closingElement.name.name = nativeTextIdentifier.name;\n }\n};\n\nfunction hasOnlyStringChildren(path: NodePath<t.JSXOpeningElement>, node: t.JSXElement): boolean {\n return node.children.every((child) => isStringNode(path, child));\n}\n\nfunction isStringNode(path: NodePath<t.JSXOpeningElement>, child: t.Node): boolean {\n if (t.isJSXText(child)) return true;\n\n // Check for JSX expressions\n if (t.isJSXExpressionContainer(child)) {\n const expression = child.expression;\n\n // If the expression is an identifier, look it up in the current scope\n if (t.isIdentifier(expression)) {\n const binding = path.scope.getBinding(expression.name);\n return binding ? t.isStringLiteral(binding.path.node) : false;\n }\n }\n return false;\n}\n\nfunction fixNegativeNumberOfLines({\n path,\n log,\n}: {\n path: NodePath<t.JSXOpeningElement>;\n log: (message: string) => void;\n}) {\n for (const attribute of path.node.attributes) {\n if (\n t.isJSXAttribute(attribute) &&\n t.isJSXIdentifier(attribute.name, { name: 'numberOfLines' }) &&\n attribute.value &&\n t.isJSXExpressionContainer(attribute.value)\n ) {\n let originalValue: number | undefined;\n if (t.isNumericLiteral(attribute.value.expression)) {\n originalValue = attribute.value.expression.value;\n } else if (\n t.isUnaryExpression(attribute.value.expression) &&\n attribute.value.expression.operator === '-' &&\n t.isNumericLiteral(attribute.value.expression.argument)\n ) {\n originalValue = -attribute.value.expression.argument.value;\n }\n if (originalValue !== undefined && originalValue < 0) {\n log(\n `Warning: 'numberOfLines' in <Text> must be a non-negative number, received: ${originalValue}. The value will be set to 0.`\n );\n attribute.value.expression = t.numericLiteral(0);\n }\n }\n }\n}\n\nfunction optimizeStyleTag({ path, file }: { path: NodePath<t.JSXOpeningElement>; file: HubFile }) {\n let shouldImportFlattenTextStyle = false;\n const nameHint = '_flattenTextStyle';\n\n for (const [index, attribute] of path.node.attributes.entries()) {\n if (t.isJSXAttribute(attribute) && t.isJSXIdentifier(attribute.name, { name: 'style' })) {\n shouldImportFlattenTextStyle = true;\n\n if (t.isJSXExpressionContainer(attribute.value) && !t.isJSXEmptyExpression(attribute.value.expression)) {\n path.node.attributes[index] = t.jsxSpreadAttribute(\n t.callExpression(t.identifier(nameHint), [attribute.value.expression])\n );\n }\n }\n }\n\n if (shouldImportFlattenTextStyle && !file.__hasImports?.flattenTextStyle) {\n if (!file.__hasImports) file.__hasImports = {};\n file.__hasImports.flattenTextStyle = addNamed(path, 'flattenTextStyle', 'react-native-boost', { nameHint });\n }\n}\n\nfunction hasInvalidChildren(path: NodePath<t.JSXOpeningElement>): boolean {\n for (const attribute of path.node.attributes) {\n if (t.isJSXSpreadAttribute(attribute)) return false; // spread attributes are handled in hasBlacklistedProperty\n\n if (t.isJSXIdentifier(attribute.name) && attribute.value) {\n // For a \"children\" attribute, optimization is allowed only if it is a string\n if (attribute.name.name === 'children') {\n return isStringNode(path, attribute.value);\n }\n return textBlacklistedProperties.has(attribute.name.name);\n }\n }\n return false;\n}\n","export const log = (message: string) => {\n console.log(`[react-native-boost] ${message}`);\n};\n","import { NodePath, types as t } from '@babel/core';\nimport { addDefault } from '@babel/helper-module-imports';\nimport { HubFile, Optimizer } from '../../types';\nimport PluginError from '../../utils/plugin-error';\nimport { hasBlacklistedProperty, shouldIgnoreOptimization } from '../../utils/common';\n\nexport const viewBlacklistedProperties = new Set([\n 'accessible',\n 'accessibilityLabel',\n 'accessibilityState',\n 'allowFontScaling',\n 'aria-busy',\n 'aria-checked',\n 'aria-disabled',\n 'aria-expanded',\n 'aria-label',\n 'aria-selected',\n 'ellipsizeMode',\n 'disabled',\n 'id',\n 'nativeID',\n 'numberOfLines',\n 'onLongPress',\n 'onPress',\n 'onPressIn',\n 'onPressOut',\n 'onResponderGrant',\n 'onResponderMove',\n 'onResponderRelease',\n 'onResponderTerminate',\n 'onResponderTerminationRequest',\n 'onStartShouldSetResponder',\n 'pressRetentionOffset',\n 'selectable',\n 'selectionColor',\n 'suppressHighlighting',\n 'style',\n]);\n\nexport const viewOptimizer: Optimizer = (path, log = () => {}) => {\n // Ensure we're processing a JSX element identifier.\n if (!t.isJSXIdentifier(path.node.name)) return;\n\n const parent = path.parent;\n if (!t.isJSXElement(parent)) return;\n\n const elementName = path.node.name.name;\n if (elementName !== 'View') return;\n\n // Respect comments that disable optimization.\n if (shouldIgnoreOptimization(path)) return;\n\n // Ensure the View element comes from react-native.\n const binding = path.scope.getBinding(elementName);\n if (!binding) return;\n if (binding.kind === 'module') {\n const parentNode = binding.path.parent;\n if (!t.isImportDeclaration(parentNode) || parentNode.source.value !== 'react-native') {\n return;\n }\n }\n\n // Bail if any blacklisted props are present.\n if (hasBlacklistedProperty(path, viewBlacklistedProperties)) return;\n\n // Bail if a <TextAncestor /> component exists as an ancestor.\n if (hasTextAncestor(path)) return;\n\n // Extract the file from the Babel hub and add flags for logging & import caching.\n const hub = path.hub as unknown;\n const file = typeof hub === 'object' && hub !== null && 'file' in hub ? (hub.file as HubFile) : undefined;\n\n if (!file) {\n throw new PluginError('No file found in Babel hub');\n }\n\n const filename = file.opts?.filename || 'unknown file';\n const lineNumber = path.node.loc?.start.line ?? 'unknown line';\n log(`Optimizing View component in ${filename}:${lineNumber}`);\n\n // Add ViewNativeComponent import (cached on the file) to prevent duplicate imports.\n if (!file.__hasImports) {\n file.__hasImports = {};\n }\n if (!file.__hasImports.ViewNativeComponent) {\n file.__hasImports.NativeView = addDefault(path, 'react-native/Libraries/Components/View/ViewNativeComponent', {\n nameHint: 'NativeView',\n });\n }\n const viewNativeIdentifier = file.__hasImports.NativeView;\n\n // Replace the component with its native counterpart.\n path.node.name.name = viewNativeIdentifier.name;\n\n // If the element is not self-closing, update the closing element as well.\n if (\n !path.node.selfClosing &&\n parent.closingElement &&\n t.isJSXIdentifier(parent.closingElement.name) &&\n parent.closingElement.name.name === 'View'\n ) {\n parent.closingElement.name.name = viewNativeIdentifier.name;\n }\n};\n\n/**\n * Returns true if any ancestor element is a <Text />.\n * TODO: This is dangerous as we can't resolve custom components and check if they have a <Text /> ancestor in the tree\n */\nfunction hasTextAncestor(path: NodePath<t.JSXOpeningElement>): boolean {\n return !!path.findParent((parentPath) => {\n return t.isJSXElement(parentPath.node) && t.isJSXIdentifier(parentPath.node.openingElement.name, { name: 'Text' });\n });\n}\n","import { declare } from '@babel/helper-plugin-utils';\nimport { textOptimizer } from './optimizers/text';\nimport { PluginOptions } from './types';\nimport { log } from './utils/logger';\nimport { viewOptimizer } from './optimizers/view';\nimport { isIgnoredFile } from './utils/common';\n\nexport default declare((api) => {\n api.assertVersion(7);\n\n return {\n name: 'react-native-boost',\n visitor: {\n JSXOpeningElement(path, state) {\n const options = (state.opts ?? {}) as PluginOptions;\n const logger = options.verbose ? log : () => {};\n if (isIgnoredFile(path, options.ignores ?? [])) return;\n if (options.optimizations?.text !== false) textOptimizer(path, logger);\n if (options.optimizations?.view !== false) viewOptimizer(path, logger);\n },\n },\n };\n});\n"],"names":["path","t"],"mappings":"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"}