react-native-boost 0.0.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/.github/FUNDING.yml +1 -0
- package/.github/actions/setup/action.yml +28 -0
- package/.github/workflows/release.yml +87 -0
- package/.github/workflows/stale.yml +37 -0
- package/.github/workflows/test.yml +54 -0
- package/.husky/pre-commit +2 -0
- package/.lintstagedrc +3 -0
- package/.nvmrc +1 -0
- package/.prettierignore +4 -0
- package/.prettierrc +14 -0
- package/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs +541 -0
- package/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs +28 -0
- package/.yarn/releases/yarn-3.6.1.cjs +874 -0
- package/.yarnrc.yml +2 -0
- package/CODE_OF_CONDUCT.md +132 -0
- package/CONTRIBUTING.md +122 -0
- package/LICENSE +20 -0
- package/README.md +72 -0
- package/commitlint.config.mjs +1 -0
- package/dist/plugin.js +70473 -0
- package/dist/plugin.js.map +7 -0
- package/eslint.config.mjs +14 -0
- package/package.json +70 -0
- package/src/optimizers/text/__tests__/fixtures/basic/code.js +2 -0
- package/src/optimizers/text/__tests__/fixtures/basic/options.js +4 -0
- package/src/optimizers/text/__tests__/fixtures/basic/output.js +3 -0
- package/src/optimizers/text/__tests__/fixtures/text-content/code.js +2 -0
- package/src/optimizers/text/__tests__/fixtures/text-content/options.js +4 -0
- package/src/optimizers/text/__tests__/fixtures/text-content/output.js +3 -0
- package/src/optimizers/text/__tests__/fixtures/text-content-as-explicit-child-prop/code.js +2 -0
- package/src/optimizers/text/__tests__/fixtures/text-content-as-explicit-child-prop/options.js +4 -0
- package/src/optimizers/text/__tests__/fixtures/text-content-as-explicit-child-prop/output.js +3 -0
- package/src/optimizers/text/__tests__/fixtures/two-components/code.js +3 -0
- package/src/optimizers/text/__tests__/fixtures/two-components/options.js +4 -0
- package/src/optimizers/text/__tests__/fixtures/two-components/output.js +4 -0
- package/src/optimizers/text/__tests__/index.test.ts +12 -0
- package/src/optimizers/text/index.ts +128 -0
- package/src/plugin.ts +15 -0
- package/tsconfig.json +14 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import globals from 'globals';
|
|
2
|
+
import pluginJs from '@eslint/js';
|
|
3
|
+
import tseslint from 'typescript-eslint';
|
|
4
|
+
import eslintPluginUnicorn from 'eslint-plugin-unicorn';
|
|
5
|
+
|
|
6
|
+
/** @type {import('eslint').Linter.Config[]} */
|
|
7
|
+
export default [
|
|
8
|
+
{ files: ['**/*.{js,mjs,cjs,ts}'] },
|
|
9
|
+
{ languageOptions: { globals: globals.node } },
|
|
10
|
+
{ ignores: ['**/fixtures', '**/*.config.{js,mjs,cjs}'] },
|
|
11
|
+
pluginJs.configs.recommended,
|
|
12
|
+
...tseslint.configs.recommended,
|
|
13
|
+
eslintPluginUnicorn.configs.recommended,
|
|
14
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-native-boost",
|
|
3
|
+
"description": "🚀 Boost your React Native app's performance with a single line of code",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"main": "dist/plugin.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"clean": "rm -rf dist",
|
|
8
|
+
"build": "yarn clean && esbuild src/plugin.ts --bundle --outfile=dist/plugin.js --sourcemap --platform=node",
|
|
9
|
+
"test": "vitest",
|
|
10
|
+
"typecheck": "tsc --noEmit",
|
|
11
|
+
"lint": "eslint src/**/*.ts",
|
|
12
|
+
"format": "prettier --write .",
|
|
13
|
+
"prepare": "husky",
|
|
14
|
+
"release": "release-it"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/kuatsu/react-native-boost.git"
|
|
19
|
+
},
|
|
20
|
+
"author": "Kuatsu App Agency <hello@kuatsu.de>",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/kuatsu/react-native-boost/issues"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/kuatsu/react-native-boost#readme",
|
|
26
|
+
"packageManager": "yarn@3.6.1",
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@babel/core": "^7.25.0",
|
|
29
|
+
"@babel/helper-module-imports": "^7.25.0",
|
|
30
|
+
"@babel/helper-plugin-utils": "^7.25.0",
|
|
31
|
+
"@babel/plugin-syntax-jsx": "^7.25.0",
|
|
32
|
+
"@babel/preset-typescript": "^7.25.0",
|
|
33
|
+
"@commitlint/cli": "^19.7.1",
|
|
34
|
+
"@commitlint/config-conventional": "^17.0.2",
|
|
35
|
+
"@eslint/js": "^9.21.0",
|
|
36
|
+
"@release-it/conventional-changelog": "^5.0.0",
|
|
37
|
+
"@types/babel__helper-module-imports": "^7.0.0",
|
|
38
|
+
"@types/babel__helper-plugin-utils": "^7.0.0",
|
|
39
|
+
"@types/node": "^20",
|
|
40
|
+
"babel-plugin-tester": "^11.0.4",
|
|
41
|
+
"esbuild": "^0.25.0",
|
|
42
|
+
"eslint": "^9.21.0",
|
|
43
|
+
"eslint-plugin-unicorn": "^57.0.0",
|
|
44
|
+
"globals": "^16.0.0",
|
|
45
|
+
"husky": "^9.1.7",
|
|
46
|
+
"lint-staged": "^15.4.3",
|
|
47
|
+
"prettier": "^3.5.2",
|
|
48
|
+
"release-it": "^18.1.2",
|
|
49
|
+
"typescript": "^5.7.3",
|
|
50
|
+
"typescript-eslint": "^8.24.1",
|
|
51
|
+
"vitest": "^3.0.6"
|
|
52
|
+
},
|
|
53
|
+
"release-it": {
|
|
54
|
+
"git": {
|
|
55
|
+
"commitMessage": "chore: release ${version}",
|
|
56
|
+
"tagName": "v${version}"
|
|
57
|
+
},
|
|
58
|
+
"npm": {
|
|
59
|
+
"publish": true
|
|
60
|
+
},
|
|
61
|
+
"github": {
|
|
62
|
+
"release": true
|
|
63
|
+
},
|
|
64
|
+
"plugins": {
|
|
65
|
+
"@release-it/conventional-changelog": {
|
|
66
|
+
"preset": "angular"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { pluginTester } from 'babel-plugin-tester/pure';
|
|
3
|
+
import plugin from '../../../plugin';
|
|
4
|
+
|
|
5
|
+
pluginTester({
|
|
6
|
+
plugin,
|
|
7
|
+
title: 'text',
|
|
8
|
+
fixtures: path.resolve(import.meta.dirname, 'fixtures'),
|
|
9
|
+
babelOptions: {
|
|
10
|
+
plugins: ['@babel/plugin-syntax-jsx'],
|
|
11
|
+
},
|
|
12
|
+
});
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { NodePath, types as t } from '@babel/core';
|
|
2
|
+
import { addNamed } from '@babel/helper-module-imports';
|
|
3
|
+
|
|
4
|
+
export function textOptimizer(path: NodePath<t.JSXOpeningElement>): void {
|
|
5
|
+
// Ensure we're processing a JSX element
|
|
6
|
+
if (!t.isJSXIdentifier(path.node.name)) return;
|
|
7
|
+
|
|
8
|
+
const parent = path.parent;
|
|
9
|
+
if (!t.isJSXElement(parent)) return;
|
|
10
|
+
|
|
11
|
+
const elementName = path.node.name.name;
|
|
12
|
+
if (elementName !== 'Text') return;
|
|
13
|
+
|
|
14
|
+
// Ensure Text element comes from react-native
|
|
15
|
+
const binding = path.scope.getBinding(elementName);
|
|
16
|
+
if (!binding) return;
|
|
17
|
+
if (binding.kind === 'module') {
|
|
18
|
+
const parentNode = binding.path.parent;
|
|
19
|
+
if (!t.isImportDeclaration(parentNode) || parentNode.source.value !== 'react-native') {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Bail if the element has any blacklisted properties or non-string children props
|
|
25
|
+
if (hasBlacklistedProperties(path)) return;
|
|
26
|
+
if (!hasOnlyStringChildren(path, parent)) return;
|
|
27
|
+
// TODO: Don't bail if the element has a style prop
|
|
28
|
+
|
|
29
|
+
// Add NativeTextComponent import (cached on file) so we only add it once per file
|
|
30
|
+
const file = (path.hub as unknown as { file: t.File }).file as t.File & {
|
|
31
|
+
__nativeTextImport?: t.Identifier;
|
|
32
|
+
};
|
|
33
|
+
if (!file.__nativeTextImport) {
|
|
34
|
+
file.__nativeTextImport = addNamed(path, 'NativeText', 'react-native/Libraries/Text/TextNativeComponent');
|
|
35
|
+
}
|
|
36
|
+
const nativeTextIdentifier = file.__nativeTextImport;
|
|
37
|
+
path.node.name.name = nativeTextIdentifier.name;
|
|
38
|
+
|
|
39
|
+
// If the element is not self-closing, update the closing element as well
|
|
40
|
+
if (
|
|
41
|
+
!path.node.selfClosing &&
|
|
42
|
+
parent.closingElement &&
|
|
43
|
+
t.isJSXIdentifier(parent.closingElement.name) &&
|
|
44
|
+
parent.closingElement.name.name === 'Text'
|
|
45
|
+
) {
|
|
46
|
+
parent.closingElement.name.name = nativeTextIdentifier.name;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function hasOnlyStringChildren(path: NodePath<t.JSXOpeningElement>, node: t.JSXElement): boolean {
|
|
51
|
+
return node.children.every((child) => isStringNode(path, child));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isStringNode(path: NodePath<t.JSXOpeningElement>, child: t.Node): boolean {
|
|
55
|
+
if (t.isJSXText(child)) return true;
|
|
56
|
+
|
|
57
|
+
// Check for JSX expressions
|
|
58
|
+
if (t.isJSXExpressionContainer(child)) {
|
|
59
|
+
const expression = child.expression;
|
|
60
|
+
|
|
61
|
+
// If the expression is an identifier, look it up in the current scope
|
|
62
|
+
if (t.isIdentifier(expression)) {
|
|
63
|
+
const binding = path.scope.getBinding(expression.name);
|
|
64
|
+
return binding ? t.isStringLiteral(binding.path.node) : false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const blacklistedProperties = new Set([
|
|
71
|
+
'accessible',
|
|
72
|
+
'accessibilityLabel',
|
|
73
|
+
'accessibilityState',
|
|
74
|
+
'allowFontScaling',
|
|
75
|
+
'aria-busy',
|
|
76
|
+
'aria-checked',
|
|
77
|
+
'aria-disabled',
|
|
78
|
+
'aria-expanded',
|
|
79
|
+
'aria-label',
|
|
80
|
+
'aria-selected',
|
|
81
|
+
'ellipsizeMode',
|
|
82
|
+
'id',
|
|
83
|
+
'nativeID',
|
|
84
|
+
'onLongPress',
|
|
85
|
+
'onPress',
|
|
86
|
+
'onPressIn',
|
|
87
|
+
'onPressOut',
|
|
88
|
+
'onResponderGrant',
|
|
89
|
+
'onResponderMove',
|
|
90
|
+
'onResponderRelease',
|
|
91
|
+
'onResponderTerminate',
|
|
92
|
+
'onResponderTerminationRequest',
|
|
93
|
+
'onStartShouldSetResponder',
|
|
94
|
+
'pressRetentionOffset',
|
|
95
|
+
'suppressHighlighting',
|
|
96
|
+
'style',
|
|
97
|
+
]);
|
|
98
|
+
|
|
99
|
+
function hasBlacklistedProperties(path: NodePath<t.JSXOpeningElement>): boolean {
|
|
100
|
+
return path.node.attributes.some((attribute) => {
|
|
101
|
+
if (t.isJSXSpreadAttribute(attribute)) {
|
|
102
|
+
if (t.isIdentifier(attribute.argument)) {
|
|
103
|
+
const binding = path.scope.getBinding(attribute.argument.name);
|
|
104
|
+
if (binding && t.isObjectExpression(binding.path.node)) {
|
|
105
|
+
return binding.path.node.properties.some((property) => {
|
|
106
|
+
if (t.isObjectProperty(property) && t.isIdentifier(property.key)) {
|
|
107
|
+
return blacklistedProperties.has(property.key.name);
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Bail if we can't resolve the spread attribute
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (t.isJSXIdentifier(attribute.name) && attribute.value) {
|
|
118
|
+
// For a "children" attribute, optimization is allowed only if it is a string
|
|
119
|
+
if (attribute.name.name === 'children') {
|
|
120
|
+
return isStringNode(path, attribute.value);
|
|
121
|
+
}
|
|
122
|
+
return blacklistedProperties.has(attribute.name.name);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// For other attribute types (e.g. namespaced), assume no blacklisting
|
|
126
|
+
return false;
|
|
127
|
+
});
|
|
128
|
+
}
|
package/src/plugin.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { declare } from '@babel/helper-plugin-utils';
|
|
2
|
+
import { textOptimizer } from './optimizers/text';
|
|
3
|
+
|
|
4
|
+
export default declare((api) => {
|
|
5
|
+
api.assertVersion(7);
|
|
6
|
+
|
|
7
|
+
return {
|
|
8
|
+
name: 'react-native-boost/text',
|
|
9
|
+
visitor: {
|
|
10
|
+
JSXOpeningElement(path) {
|
|
11
|
+
textOptimizer(path);
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"lib": ["ESNext"],
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"target": "es2019",
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"outDir": "./dist",
|
|
9
|
+
"types": ["node"],
|
|
10
|
+
"skipLibCheck": true
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*"],
|
|
13
|
+
"exclude": ["node_modules", "dist", "fixtures"]
|
|
14
|
+
}
|