Showing preview only (297K chars total). Download the full file or copy to clipboard to get everything.
Repository: kuatsu/react-native-boost
Branch: main
Commit: 950c0234e327
Files: 202
Total size: 240.4 KB
Directory structure:
gitextract_wntfy7wt/
├── .github/
│ ├── FUNDING.yml
│ ├── actions/
│ │ └── setup/
│ │ └── action.yml
│ └── workflows/
│ ├── release.yml
│ ├── stale.yml
│ └── test.yml
├── .gitignore
├── .husky/
│ ├── commit-msg
│ └── pre-commit
├── .lintstagedrc
├── .npmrc
├── .nvmrc
├── .oxfmtrc.json
├── .oxlintrc.json
├── .zed/
│ └── settings.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── apps/
│ ├── docs/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── app/
│ │ │ ├── (home)/
│ │ │ │ ├── layout.tsx
│ │ │ │ └── page.tsx
│ │ │ ├── api/
│ │ │ │ └── search/
│ │ │ │ └── route.ts
│ │ │ ├── docs/
│ │ │ │ ├── [[...slug]]/
│ │ │ │ │ └── page.tsx
│ │ │ │ └── layout.tsx
│ │ │ ├── global.css
│ │ │ ├── layout.tsx
│ │ │ ├── llms-full.txt/
│ │ │ │ └── route.ts
│ │ │ ├── llms.mdx/
│ │ │ │ └── docs/
│ │ │ │ └── [[...slug]]/
│ │ │ │ └── route.ts
│ │ │ ├── llms.txt/
│ │ │ │ └── route.ts
│ │ │ └── og/
│ │ │ └── docs/
│ │ │ └── [...slug]/
│ │ │ └── route.tsx
│ │ ├── components/
│ │ │ ├── ai/
│ │ │ │ └── page-actions.tsx
│ │ │ └── docs/
│ │ │ ├── auto-option-sections.tsx
│ │ │ ├── auto-runtime-reference.tsx
│ │ │ └── reference-sections.tsx
│ │ ├── content/
│ │ │ └── docs/
│ │ │ ├── configuration/
│ │ │ │ ├── boost-decorator.mdx
│ │ │ │ ├── configure.mdx
│ │ │ │ └── nativewind.mdx
│ │ │ ├── index.mdx
│ │ │ ├── information/
│ │ │ │ ├── benchmarks.mdx
│ │ │ │ ├── how-it-works.mdx
│ │ │ │ ├── optimization-coverage.mdx
│ │ │ │ └── troubleshooting.mdx
│ │ │ ├── meta.json
│ │ │ └── runtime-library/
│ │ │ └── index.mdx
│ │ ├── lib/
│ │ │ ├── cn.ts
│ │ │ ├── layout.shared.tsx
│ │ │ ├── source.ts
│ │ │ └── type-generator.ts
│ │ ├── mdx-components.tsx
│ │ ├── next.config.mjs
│ │ ├── package.json
│ │ ├── postcss.config.mjs
│ │ ├── source.config.ts
│ │ └── tsconfig.json
│ └── example/
│ ├── .gitignore
│ ├── app.json
│ ├── babel.config.js
│ ├── index.ts
│ ├── package.json
│ ├── src/
│ │ ├── app.tsx
│ │ ├── components/
│ │ │ └── measure-component.tsx
│ │ ├── screens/
│ │ │ └── home.tsx
│ │ ├── types/
│ │ │ └── index.ts
│ │ └── utils/
│ │ └── helpers.ts
│ └── tsconfig.json
├── commitlint.config.mjs
├── package.json
├── packages/
│ ├── react-native-boost/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── package.json
│ │ ├── rollup.config.mjs
│ │ ├── src/
│ │ │ ├── plugin/
│ │ │ │ ├── index.ts
│ │ │ │ ├── optimizers/
│ │ │ │ │ ├── text/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── fixtures/
│ │ │ │ │ │ │ │ ├── basic/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── complex-example/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── default-props/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── expo-router-link-alias-as-child/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── expo-router-link-as-child/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── expo-router-link-as-child-false-static/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── expo-router-link-as-child-nested-view/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── expo-router-link-namespace-as-child/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── flattens-styles-at-runtime/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── force-comment/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── ignore-comment/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── mixed-children-types/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── nested-in-object-with-ignore-comment/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── non-react-native-import/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── normalize-accessibility-props/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── normalize-accessibility-props-and-flatten-styles/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── number-of-lines/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── pressables/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── resolvable-spread-props/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── text-content/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── text-content-as-explicit-child-prop/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── two-components/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ ├── unresolvable-spread-props/
│ │ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ │ └── variable-child-no-string/
│ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ └── index.test.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── view/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── fixtures/
│ │ │ │ │ │ │ ├── basic/
│ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ ├── force-comment/
│ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ ├── ignore-comment/
│ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ ├── indirect-text-ancestor/
│ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ ├── react-native-namespace-text-ancestor/
│ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ ├── same-file-safe-ancestor/
│ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ ├── same-file-unknown-ancestor/
│ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ ├── text-ancestor/
│ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ ├── unknown-imported-ancestor/
│ │ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ │ ├── dangerous-output.js
│ │ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ │ └── unresolvable-spread-props/
│ │ │ │ │ │ │ ├── code.js
│ │ │ │ │ │ │ └── output.js
│ │ │ │ │ │ └── index.test.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── types/
│ │ │ │ │ └── index.ts
│ │ │ │ └── utils/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── logger.test.ts
│ │ │ │ ├── common/
│ │ │ │ │ ├── attributes.ts
│ │ │ │ │ ├── base.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── validation.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── format-test-result.ts
│ │ │ │ ├── generate-test-plugin.ts
│ │ │ │ ├── helpers.ts
│ │ │ │ ├── logger.ts
│ │ │ │ └── plugin-error.ts
│ │ │ └── runtime/
│ │ │ ├── __tests__/
│ │ │ │ ├── index.test.ts
│ │ │ │ └── mocks/
│ │ │ │ └── react-native.ts
│ │ │ ├── components/
│ │ │ │ ├── native-text.tsx
│ │ │ │ └── native-view.tsx
│ │ │ ├── index.ts
│ │ │ ├── index.web.ts
│ │ │ ├── types/
│ │ │ │ ├── index.ts
│ │ │ │ └── react-native.d.ts
│ │ │ └── utils/
│ │ │ └── constants.ts
│ │ ├── tsconfig.build.json
│ │ ├── tsconfig.json
│ │ └── vitest.config.ts
│ └── react-native-time-to-render/
│ ├── .gitignore
│ ├── LICENSE
│ ├── README.md
│ ├── TimeToRender.podspec
│ ├── android/
│ │ ├── build.gradle
│ │ ├── gradle.properties
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── AndroidManifestNew.xml
│ │ └── java/
│ │ └── com/
│ │ └── timetorender/
│ │ ├── MarkerStore.kt
│ │ ├── OnMarkerPaintedEvent.kt
│ │ ├── TimeToRenderModule.kt
│ │ ├── TimeToRenderPackage.kt
│ │ ├── TimeToRenderView.kt
│ │ └── TimeToRenderViewManager.kt
│ ├── ios/
│ │ ├── MarkerPaintComponentView.h
│ │ ├── MarkerPaintComponentView.mm
│ │ ├── MarkerStore.h
│ │ ├── MarkerStore.m
│ │ ├── PaintMarkerView.h
│ │ ├── PaintMarkerView.m
│ │ ├── TimeToRender.h
│ │ ├── TimeToRender.mm
│ │ ├── TimeToRenderManager.h
│ │ └── TimeToRenderManager.m
│ ├── package.json
│ ├── react-native.config.js
│ └── src/
│ ├── NativeTimeToRender.ts
│ ├── TimeToRenderNativeComponent.ts
│ └── index.tsx
├── pnpm-workspace.yaml
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
github: mfkrause
================================================
FILE: .github/actions/setup/action.yml
================================================
name: Setup
description: Setup Node.js and install dependencies
runs:
using: composite
steps:
- uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Enable Corepack
run: corepack enable
shell: bash
- name: Install dependencies
run: pnpm install --frozen-lockfile
shell: bash
================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
workflow_dispatch:
inputs:
release_type:
description: 'Release type (patch, minor, major, or a semver version)'
required: false
type: string
npm_tag:
description: 'Optional npm dist-tag override (e.g. latest, v0, v1)'
required: false
type: string
github_make_latest:
description: 'Optional GitHub latest release override (true or false)'
required: false
type: string
permissions:
contents: write
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup
uses: ./.github/actions/setup
- name: Lint files
run: pnpm lint
- name: Test formatting
run: pnpm format --check
- name: Typecheck files
run: pnpm typecheck
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup
uses: ./.github/actions/setup
- name: Run tests
run: pnpm test
build-release:
runs-on: ubuntu-latest
needs: [lint, test]
permissions:
contents: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup
uses: ./.github/actions/setup
- name: Build package
run: pnpm package build
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Validate release type
if: ${{ inputs.release_type != '' }}
run: |
if [[ "${{ inputs.release_type }}" =~ ^(patch|minor|major)$ ]]; then
echo "Valid release type: ${{ inputs.release_type }}"
elif [[ "${{ inputs.release_type }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Valid semver version: ${{ inputs.release_type }}"
else
echo "Invalid input. Must be 'patch', 'minor', 'major', or a valid semver version (e.g., 1.2.3)."
exit 1
fi
- name: Resolve release strategy
run: |
branch="${{ github.ref_name }}"
release_type="${{ inputs.release_type }}"
npm_tag_input="${{ inputs.npm_tag }}"
github_make_latest_input="${{ inputs.github_make_latest }}"
package_version=$(node -p "require('./packages/react-native-boost/package.json').version")
package_major="${package_version%%.*}"
case "$github_make_latest_input" in
""|true|false) ;;
*)
echo "Invalid github_make_latest input. Must be 'true' or 'false' when provided."
exit 1
;;
esac
if [[ "$branch" =~ ^v([0-9]+)$ ]]; then
branch_major="${BASH_REMATCH[1]}"
release_npm_tag="${npm_tag_input:-v${branch_major}}"
release_github_make_latest="${github_make_latest_input:-false}"
if [[ "$package_major" != "$branch_major" ]]; then
echo "Branch $branch expects package major $branch_major, but package.json is $package_version."
exit 1
fi
if [[ -n "$release_type" ]]; then
if [[ "$release_type" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
release_major="${release_type%%.*}"
if [[ "$release_major" != "$branch_major" ]]; then
echo "Explicit version $release_type does not match branch major $branch_major."
exit 1
fi
elif [[ "$release_type" == "major" ]]; then
echo "Major increments are not allowed on maintenance branch $branch."
exit 1
fi
fi
elif [[ "$branch" == "main" || "$branch" == "master" ]]; then
release_npm_tag="${npm_tag_input:-latest}"
release_github_make_latest="${github_make_latest_input:-true}"
else
if [[ -z "$npm_tag_input" || -z "$github_make_latest_input" ]]; then
echo "Releases from branch '$branch' require explicit npm_tag and github_make_latest inputs."
exit 1
fi
release_npm_tag="$npm_tag_input"
release_github_make_latest="$github_make_latest_input"
fi
if [[ ! "$release_npm_tag" =~ ^[A-Za-z0-9._-]+$ ]]; then
echo "Invalid npm tag '$release_npm_tag'. Use only letters, numbers, dots, underscores, and dashes."
exit 1
fi
echo "RELEASE_NPM_TAG=$release_npm_tag" >> "$GITHUB_ENV"
echo "RELEASE_GITHUB_MAKE_LATEST=$release_github_make_latest" >> "$GITHUB_ENV"
echo "Release branch: $branch"
echo "npm tag: $release_npm_tag"
echo "GitHub make_latest: $release_github_make_latest"
- name: Release
run: |
if [ -n "${{ inputs.release_type }}" ]; then
pnpm package release --increment "${{ inputs.release_type }}" --npm.tag "$RELEASE_NPM_TAG" --github.makeLatest "$RELEASE_GITHUB_MAKE_LATEST"
else
pnpm package release --npm.tag "$RELEASE_NPM_TAG" --github.makeLatest "$RELEASE_GITHUB_MAKE_LATEST"
fi
env:
GITHUB_TOKEN: ${{ github.token }}
================================================
FILE: .github/workflows/stale.yml
================================================
name: 'Close stale issues and PRs'
on:
schedule:
- cron: '30 1 * * *'
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.'
stale-pr-message: 'This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.'
days-before-stale: 60
days-before-close: 7
stale-issue-label: stale
stale-pr-label: stale
exempt-issue-labels: 'help wanted,in progress,pinned'
exempt-pr-labels: 'in progress,pinned'
stale-missing-info:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
any-of-labels: 'repro-missing'
stale-issue-message: 'This issue is stale because it is missing information. Please add the requested information or this will be closed in 7 days.'
stale-pr-message: 'This PR is stale because it is missing information. Please add the requested information or this will be closed in 7 days.'
days-before-stale: 14
days-before-close: 7
stale-issue-label: stale
stale-pr-label: stale
================================================
FILE: .github/workflows/test.yml
================================================
name: Test & build
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup
uses: ./.github/actions/setup
- name: Lint files
run: pnpm lint
- name: Test formatting
run: pnpm format --check
- name: Verify formatted code is unchanged
run: git diff --exit-code HEAD
- name: Typecheck files
run: pnpm typecheck
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup
uses: ./.github/actions/setup
- name: Run tests
run: pnpm test
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup
uses: ./.github/actions/setup
- name: Build plugin
run: pnpm package build
================================================
FILE: .gitignore
================================================
*.tgz
package-lock.json
yarn.lock
# OSX
.DS_Store
# VSCode
.vscode/
jsconfig.json
# node.js
#
node_modules/
npm-debug.log
yarn-debug.log
yarn-error.log
# pnpm
.pnpm-store/
# Turborepo
.turbo/
================================================
FILE: .husky/commit-msg
================================================
npx --no-install commitlint --edit $1
================================================
FILE: .husky/pre-commit
================================================
npx --no-install lint-staged
================================================
FILE: .lintstagedrc
================================================
{
"*.{js,mjs,cjs,jsx,ts,tsx}": ["pnpm exec oxlint --fix", "pnpm exec oxfmt --write"],
"*.json": "pnpm exec oxfmt --write"
}
================================================
FILE: .npmrc
================================================
node-linker=hoisted
================================================
FILE: .nvmrc
================================================
v24
================================================
FILE: .oxfmtrc.json
================================================
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"printWidth": 120,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "consistent",
"jsxSingleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"bracketSameLine": true,
"arrowParens": "always",
"endOfLine": "lf",
"sortPackageJson": false,
"ignorePatterns": ["CHANGELOG.md", "apps/docs/**/*.md", "apps/docs/**/*.mdx", "apps/docs/.docusaurus/**"]
}
================================================
FILE: .oxlintrc.json
================================================
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["eslint", "typescript", "unicorn"],
"categories": {
"correctness": "error"
},
"env": {
"node": true
},
"ignorePatterns": [
"**/fixtures",
"**/*.config.{js,mjs,cjs}",
"**/scripts",
"**/__tests__",
"apps/docs/.docusaurus/**"
],
"rules": {
"no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}
],
"@typescript-eslint/ban-ts-comment": "error",
"no-array-constructor": "error",
"@typescript-eslint/no-empty-object-type": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-require-imports": "error",
"@typescript-eslint/no-unnecessary-type-constraint": "error",
"@typescript-eslint/no-unsafe-function-type": "error",
"unicorn/catch-error-name": "error",
"unicorn/consistent-assert": "error",
"unicorn/consistent-date-clone": "error",
"unicorn/consistent-empty-array-spread": "error",
"unicorn/consistent-existence-index-check": "error",
"unicorn/consistent-function-scoping": "error",
"unicorn/empty-brace-spaces": "error",
"unicorn/error-message": "error",
"unicorn/escape-case": "error",
"unicorn/explicit-length-check": "error",
"unicorn/filename-case": "error",
"unicorn/new-for-builtins": "error",
"unicorn/no-accessor-recursion": "error",
"unicorn/no-anonymous-default-export": "error",
"unicorn/no-array-callback-reference": "error",
"unicorn/no-array-for-each": "error",
"unicorn/no-array-method-this-argument": "error",
"unicorn/no-array-reduce": "error",
"unicorn/no-await-expression-member": "error",
"unicorn/no-console-spaces": "error",
"unicorn/no-document-cookie": "error",
"unicorn/no-hex-escape": "error",
"unicorn/no-instanceof-builtins": "error",
"unicorn/no-length-as-slice-end": "error",
"unicorn/no-lonely-if": "error",
"unicorn/no-magic-array-flat-depth": "error",
"unicorn/no-negated-condition": "error",
"unicorn/no-negation-in-equality-check": "error",
"unicorn/no-new-buffer": "error",
"unicorn/no-object-as-default-parameter": "error",
"unicorn/no-process-exit": "error",
"unicorn/no-static-only-class": "error",
"unicorn/no-this-assignment": "error",
"unicorn/no-typeof-undefined": "error",
"unicorn/no-unreadable-array-destructuring": "error",
"unicorn/no-unreadable-iife": "error",
"unicorn/no-useless-promise-resolve-reject": "error",
"unicorn/no-useless-switch-case": "error",
"unicorn/no-useless-undefined": "error",
"unicorn/no-null": "off",
"unicorn/no-nested-ternary": "off",
"unicorn/no-abusive-eslint-disable": "off",
"unicorn/no-zero-fractions": "error",
"unicorn/number-literal-case": "error",
"unicorn/numeric-separators-style": "error",
"unicorn/prefer-add-event-listener": "error",
"unicorn/prefer-array-find": "error",
"unicorn/prefer-array-flat-map": "error",
"unicorn/prefer-array-flat": "error",
"unicorn/prefer-array-index-of": "error",
"unicorn/prefer-array-some": "error",
"unicorn/prefer-at": "error",
"unicorn/prefer-blob-reading-methods": "error",
"unicorn/prefer-code-point": "error",
"unicorn/prefer-date-now": "error",
"unicorn/prefer-default-parameters": "error",
"unicorn/prefer-dom-node-append": "error",
"unicorn/prefer-dom-node-dataset": "error",
"unicorn/prefer-dom-node-remove": "error",
"unicorn/prefer-dom-node-text-content": "error",
"unicorn/prefer-event-target": "error",
"unicorn/prefer-global-this": "error",
"unicorn/prefer-includes": "error",
"unicorn/prefer-keyboard-event-key": "error",
"unicorn/prefer-logical-operator-over-ternary": "error",
"unicorn/prefer-math-min-max": "error",
"unicorn/prefer-math-trunc": "error",
"unicorn/prefer-modern-dom-apis": "error",
"unicorn/prefer-modern-math-apis": "error",
"unicorn/prefer-module": "error",
"unicorn/prefer-native-coercion-functions": "error",
"unicorn/prefer-negative-index": "error",
"unicorn/prefer-node-protocol": "error",
"unicorn/prefer-number-properties": "error",
"unicorn/prefer-object-from-entries": "error",
"unicorn/prefer-optional-catch-binding": "error",
"unicorn/prefer-prototype-methods": "error",
"unicorn/prefer-query-selector": "error",
"unicorn/prefer-reflect-apply": "error",
"unicorn/prefer-regexp-test": "error",
"unicorn/prefer-set-has": "error",
"unicorn/prefer-spread": "error",
"unicorn/prefer-string-raw": "error",
"unicorn/prefer-string-replace-all": "error",
"unicorn/prefer-string-slice": "error",
"unicorn/prefer-string-trim-start-end": "error",
"unicorn/prefer-structured-clone": "error",
"unicorn/prefer-ternary": "error",
"unicorn/prefer-top-level-await": "off",
"unicorn/prefer-type-error": "error",
"unicorn/relative-url-style": "error",
"unicorn/require-array-join-separator": "error",
"unicorn/require-number-to-fixed-digits-argument": "error",
"unicorn/switch-case-braces": "error",
"unicorn/text-encoding-identifier-case": "error",
"unicorn/throw-new-error": "error"
},
"overrides": [
{
"files": ["packages/react-native-time-to-render/src/*.ts"],
"rules": {
"unicorn/filename-case": "off"
}
}
]
}
================================================
FILE: .zed/settings.json
================================================
{
"lsp": {
"oxlint": {
"initialization_options": {
"settings": {
"configPath": null,
"run": "onType",
"disableNestedConfig": false,
"fixKind": "safe_fix",
"typeAware": true,
"unusedDisableDirectives": "deny"
}
}
},
"oxfmt": {
"initialization_options": {
"settings": {
"fmt.configPath": null,
"run": "onSave"
}
}
}
},
"languages": {
"CSS": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
}
]
},
"GraphQL": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
}
]
},
"Handlebars": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
}
]
},
"HTML": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
}
]
},
"JavaScript": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
},
{
"code_action": "source.fixAll.oxc"
}
]
},
"JSON": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
}
]
},
"JSON5": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
}
]
},
"JSONC": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
}
]
},
"Less": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
}
]
},
"Markdown": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
}
]
},
"MDX": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
}
]
},
"SCSS": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
}
]
},
"TypeScript": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
}
]
},
"TSX": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
}
]
},
"Vue.js": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
}
]
},
"YAML": {
"format_on_save": "on",
"prettier": {
"allowed": false
},
"formatter": [
{
"language_server": {
"name": "oxfmt"
}
}
]
}
}
}
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or advances of
any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email address,
without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[INSERT CONTACT METHOD].
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
Contributions are always welcome, no matter how large or small!
We want this community to be friendly and respectful to each other. Please follow it in all your interactions with the project. Before contributing, please read the [code of conduct](./CODE_OF_CONDUCT.md).
## Development workflow
To get started with the project, run `pnpm install` in the root directory to install the required dependencies for each package:
```sh
pnpm install
```
> While it's possible to use [`npm`](https://github.com/npm/cli), the tooling is built around [`pnpm`](https://pnpm.io/), so you'll have an easier time if you use `pnpm` for development.
While developing, you can run the [example app](/example/) to test your changes.
To have package changes automatically reflected in the example app, run the package build watcher and Expo together:
```sh
pnpm dev
```
This runs `rollup -w` for `packages/react-native-boost` and `expo start` for `apps/example` in parallel.
If you change native code, you'll still need to rebuild the example app.
To start only the example app packager:
```sh
pnpm example start
```
To run the example app on Android:
```sh
pnpm example android
```
To run the example app on iOS:
```sh
pnpm example ios
```
Make sure your code passes TypeScript and Oxlint. Run the following to verify:
```sh
pnpm typecheck
pnpm lint
```
To fix formatting errors, run the following:
```sh
pnpm lint -- --fix
```
Remember to add tests for your change if possible. Run the unit tests by:
```sh
pnpm test
```
### Commit message convention
We follow the [conventional commits specification](https://www.conventionalcommits.org/en) for our commit messages:
- `fix`: bug fixes, e.g. fix crash due to deprecated method.
- `feat`: new features, e.g. add new method to the module.
- `refactor`: code refactor, e.g. migrate from class components to hooks.
- `docs`: changes into documentation, e.g. add usage example for the module..
- `test`: adding or updating tests, e.g. add integration tests using detox.
- `chore`: tooling changes, e.g. change CI config.
Our pre-commit hooks verify that your commit message matches this format when committing.
### Linting and tests
[Oxlint](https://oxc.rs/docs/guide/usage/linter), [Oxfmt](https://oxc.rs/docs/guide/usage/formatter), [TypeScript](https://www.typescriptlang.org/)
We use [TypeScript](https://www.typescriptlang.org/) for type checking, and [Oxlint](https://oxc.rs/docs/guide/usage/linter) with [Oxfmt](https://oxc.rs/docs/guide/usage/formatter) for linting and formatting the code.
Our pre-commit hooks verify that the linter and tests pass when committing.
### Publishing to npm
We use [release-it](https://github.com/release-it/release-it) to make it easier to publish new versions. It handles common tasks like bumping version based on semver, creating tags and releases etc.
To publish new versions, run the following:
```sh
pnpm package release
```
### Scripts
The `package.json` file contains various scripts for common tasks:
- `pnpm install`: install all workspace dependencies.
- `pnpm typecheck`: type-check files with TypeScript.
- `pnpm lint`: lint files with Oxlint.
- `pnpm example start`: start the Metro server for the example app.
- `pnpm dev`: start the example app and watch/rebuild `react-native-boost` package changes.
- `pnpm example android`: run the example app on Android.
- `pnpm example ios`: run the example app on iOS.
### Sending a pull request
> **Working on your first pull request?** You can learn how from this _free_ series: [How to Contribute to an Open Source Project on GitHub](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github).
When you're sending a pull request:
- Prefer small pull requests focused on one change.
- Verify that linters and tests are passing.
- Review the documentation to make sure it looks good.
- Follow the pull request template when opening a pull request.
- For pull requests that change the API or implementation, discuss with maintainers first by opening an issue.
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) Kuatsu App Agency
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# 🚀 react-native-boost
  
A powerful Babel plugin that automatically optimizes React Native apps through static source code analysis. It replaces standard React Native components with their native counterparts where possible, leading to significant performance improvements.
- ⚡ Automatic performance optimization through source code analysis
- 🔒 Safe optimizations that don't break your app
- 🎯 Virtually zero runtime overhead
- 📱 Cross-platform compatible
- 🧪 Works seamlessly with Expo
- 🎨 Configurable optimization strategies
## Documentation
The documentation is available at [react-native-boost.oss.kuatsu.de](https://react-native-boost.oss.kuatsu.de).
## Benchmark
The app in the `apps/example` directory serves as a benchmark for the performance of the plugin.
<div align="center">
<img src="./apps/docs/content/docs/information/img/benchmark-ios.png" width="500" />
</div>
More benchmarks are available in the [docs](https://react-native-boost.oss.kuatsu.de/docs/information/benchmarks).
## Compatibility
| `react-native-boost` | React Native |
| -------------------- | ---------------- |
| `0.x` | All versions[^1] |
| `1.x` | `>=0.83` |
[^1]: Starting from React Native `0.80`, `react-native-boost@0` prints import deprecation warnings.
## Installation
Install the package using your favorite package manager. Please **do not** install the package as a dev dependency. While the Babel plugin itself would work as a dev dependency, it relies on importing the runtime library (`react-native-boost/runtime`) into your code, which requires the package to be installed as a regular dependency. Read more [here](https://react-native-boost.oss.kuatsu.de/docs/runtime-library/).
```sh
npm install react-native-boost
# or
yarn add react-native-boost
```
Then, add the plugin to your Babel configuration (`babel.config.js`):
```js
module.exports = {
plugins: ['react-native-boost/plugin'],
};
```
If you're using Expo and don't see the `babel.config.js` file, run the following command to create it:
```sh
npx expo customize babel.config.js
```
Finally, restart your React Native development server and clear the bundler cache:
```sh
npm start --clear
# or
yarn start --clear
```
That's it! No imports in your code, rebuilding, or anything else is required.
Optionally, you can configure the Babel plugin with a few options described in the [documentation](https://react-native-boost.oss.kuatsu.de/docs/configuration/configure).
## How it works
A technical rundown of how the plugin works can be found in the [docs](https://react-native-boost.oss.kuatsu.de/docs/information/how-it-works).
## Contributing
See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
## License
MIT
================================================
FILE: apps/docs/.gitignore
================================================
# deps
/node_modules
# generated content
.source
# test & build
/coverage
/.next/
/out/
/build
*.tsbuildinfo
# misc
.DS_Store
*.pem
/.pnp
.pnp.js
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# others
.env*.local
.vercel
next-env.d.ts
================================================
FILE: apps/docs/README.md
================================================
# React Native Boost Docs
This app hosts the Fumadocs site for `react-native-boost`.
## Development
```bash
pnpm --filter react-native-boost-docs dev
```
## Build
```bash
pnpm --filter react-native-boost-docs build
```
## Content Layout
- `content/docs`: documentation pages and `meta.json` navigation files
- `app/docs`: docs layout and page rendering routes
- `lib/source.ts`: Fumadocs source loader configuration
================================================
FILE: apps/docs/app/(home)/layout.tsx
================================================
import { HomeLayout } from 'fumadocs-ui/layouts/home';
import { baseOptions } from '@/lib/layout.shared';
export default function Layout({ children }: LayoutProps<'/'>) {
return <HomeLayout {...baseOptions()}>{children}</HomeLayout>;
}
================================================
FILE: apps/docs/app/(home)/page.tsx
================================================
import Link from 'next/link';
import { Rocket, ShieldCheck, Zap } from 'lucide-react';
export default function HomePage() {
return (
<div className="mx-auto flex w-full max-w-5xl flex-col justify-start gap-5 px-4 py-6 md:min-h-[90vh] md:justify-center md:py-10">
<section className="rounded-2xl border border-fd-border bg-linear-to-br from-fd-primary/15 via-fd-background to-fd-background p-6 md:p-8">
<p className="mb-3 inline-flex items-center gap-2 rounded-full bg-fd-primary/12 px-3 py-1 text-sm font-medium text-fd-primary">
<Rocket className="size-4" />
React Native Boost
</p>
<h1 className="text-3xl font-semibold tracking-tight md:text-4xl">
Improve your app's performance with one line of code.
</h1>
<p className="mt-3 max-w-3xl text-fd-muted-foreground md:text-base">
A Babel plugin that replaces analyzes your code and performs safe optimizations to reduce unnecessary runtime
overhead in React Native apps.
</p>
<div className="mt-5 flex items-center">
<Link
href="/docs"
className="inline-flex items-center rounded-xl bg-fd-primary px-5 py-2.5 text-base font-medium text-fd-primary-foreground transition-colors hover:opacity-90">
Read docs
</Link>
</div>
</section>
<section className="grid gap-3 md:grid-cols-3">
<article className="rounded-xl border border-fd-border bg-fd-card p-4">
<p className="mb-2 inline-flex items-center gap-2 text-sm font-medium">
<Zap className="size-4 text-fd-primary" />
Faster renders
</p>
<p className="text-sm text-fd-muted-foreground">
Removes runtime overhead from wrapper components to improve UI-heavy screens.
</p>
</article>
<article className="rounded-xl border border-fd-border bg-fd-card p-4">
<p className="mb-2 inline-flex items-center gap-2 text-sm font-medium">
<ShieldCheck className="size-4 text-fd-primary" />
Safety first
</p>
<p className="text-sm text-fd-muted-foreground">
Conservative analysis skips uncertain optimizations to reduce behavioral risk.
</p>
</article>
<article className="rounded-xl border border-fd-border bg-fd-card p-4">
<p className="mb-2 inline-flex items-center gap-2 text-sm font-medium">
<Rocket className="size-4 text-fd-primary" />
Minimal setup
</p>
<p className="text-sm text-fd-muted-foreground">
Install, add the Babel plugin, get instant improvements. No code changes required.
</p>
</article>
</section>
</div>
);
}
================================================
FILE: apps/docs/app/api/search/route.ts
================================================
import { source } from '@/lib/source';
import { createFromSource } from 'fumadocs-core/search/server';
export const { GET } = createFromSource(source, {
// https://docs.orama.com/docs/orama-js/supported-languages
language: 'english',
});
================================================
FILE: apps/docs/app/docs/[[...slug]]/page.tsx
================================================
import { getPageImage, source } from '@/lib/source';
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';
import { notFound } from 'next/navigation';
import { getMDXComponents } from '@/mdx-components';
import type { Metadata } from 'next';
import { createRelativeLink } from 'fumadocs-ui/mdx';
import type { TOCItemType } from 'fumadocs-core/toc';
import { LLMCopyButton, ViewOptions } from '@/components/ai/page-actions';
import { gitConfig } from '@/lib/layout.shared';
import { getAutoOptionSectionsToc } from '@/components/docs/auto-option-sections';
import { getRuntimeReferenceToc } from '@/components/docs/auto-runtime-reference';
const runtimeReferencePath = '../../packages/react-native-boost/src/runtime/index.ts';
const pluginTypesPath = '../../packages/react-native-boost/src/plugin/types/index.ts';
type TocInsertion = {
afterUrl: string;
items: TOCItemType[];
};
async function getTocInsertions(slug: string): Promise<TocInsertion[]> {
if (slug === 'runtime-library') {
return [
{
afterUrl: '#api-reference',
items: getRuntimeReferenceToc(runtimeReferencePath),
},
];
}
if (slug === 'configuration/configure') {
const [pluginOptionsToc, pluginOptimizationOptionsToc] = await Promise.all([
getAutoOptionSectionsToc({
path: pluginTypesPath,
name: 'PluginOptions',
idPrefix: 'plugin-options',
depth: 3,
}),
getAutoOptionSectionsToc({
path: pluginTypesPath,
name: 'PluginOptimizationOptions',
idPrefix: 'plugin-optimization-options',
depth: 3,
}),
]);
return [
{
afterUrl: '#plugin-options',
items: pluginOptionsToc,
},
{
afterUrl: '#plugin-optimization-options',
items: pluginOptimizationOptionsToc,
},
];
}
return [];
}
function mergeToc(baseToc: TOCItemType[], insertions: TocInsertion[]): TOCItemType[] {
if (insertions.length === 0) {
return baseToc;
}
const remainingInsertions = [...insertions];
const mergedToc: TOCItemType[] = [];
for (const item of baseToc) {
mergedToc.push(item);
for (let index = 0; index < remainingInsertions.length; index += 1) {
const insertion = remainingInsertions[index];
if (insertion.afterUrl !== item.url) {
continue;
}
mergedToc.push(...insertion.items);
remainingInsertions.splice(index, 1);
index -= 1;
}
}
return mergedToc;
}
export default async function Page(props: PageProps<'/docs/[[...slug]]'>) {
const params = await props.params;
const page = source.getPage(params.slug);
if (!page) notFound();
const MDX = page.data.body;
const slug = page.slugs.join('/');
const tocInsertions = await getTocInsertions(slug);
const toc = mergeToc(page.data.toc ?? [], tocInsertions);
return (
<DocsPage toc={toc} full={page.data.full}>
<DocsTitle>{page.data.title}</DocsTitle>
<DocsDescription className="mb-0">{page.data.description}</DocsDescription>
<div className="flex flex-row gap-2 items-center border-b pb-6">
<LLMCopyButton markdownUrl={`${page.url}.mdx`} />
<ViewOptions
markdownUrl={`${page.url}.mdx`}
githubUrl={`https://github.com/${gitConfig.user}/${gitConfig.repo}/blob/${gitConfig.branch}/content/docs/${page.path}`}
/>
</div>
<DocsBody>
<MDX
components={getMDXComponents({
// this allows you to link to other pages with relative file paths
a: createRelativeLink(source, page),
})}
/>
</DocsBody>
</DocsPage>
);
}
export async function generateStaticParams() {
return source.generateParams();
}
export async function generateMetadata(props: PageProps<'/docs/[[...slug]]'>): Promise<Metadata> {
const params = await props.params;
const page = source.getPage(params.slug);
if (!page) notFound();
return {
title: page.data.title,
description: page.data.description,
openGraph: {
images: getPageImage(page).url,
},
};
}
================================================
FILE: apps/docs/app/docs/layout.tsx
================================================
import { source } from '@/lib/source';
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { baseOptions } from '@/lib/layout.shared';
export default function Layout({ children }: LayoutProps<'/docs'>) {
return (
<DocsLayout tree={source.getPageTree()} {...baseOptions()}>
{children}
</DocsLayout>
);
}
================================================
FILE: apps/docs/app/global.css
================================================
@import 'tailwindcss';
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
:root {
--color-fd-primary: #ff9800;
--color-fd-primary-foreground: #2f1d00;
--color-fd-ring: #ff9800;
}
.dark {
--color-fd-primary: #ffb74d;
--color-fd-primary-foreground: #2f1d00;
--color-fd-ring: #ffb74d;
}
================================================
FILE: apps/docs/app/layout.tsx
================================================
import { RootProvider } from 'fumadocs-ui/provider/next';
import './global.css';
import { Inter } from 'next/font/google';
import type { Metadata } from 'next';
const inter = Inter({
subsets: ['latin'],
});
export const metadata: Metadata = {
metadataBase: new URL('https://react-native-boost.oss.kuatsu.de'),
title: {
default: 'React Native Boost',
template: '%s | React Native Boost',
},
description: 'A Babel plugin and runtime toolkit for React Native performance optimizations.',
};
export default function Layout({ children }: LayoutProps<'/'>) {
return (
<html lang="en" className={inter.className} suppressHydrationWarning>
<body className="flex flex-col min-h-screen">
<RootProvider>{children}</RootProvider>
</body>
</html>
);
}
================================================
FILE: apps/docs/app/llms-full.txt/route.ts
================================================
import { getLLMText, source } from '@/lib/source';
export const revalidate = false;
export async function GET() {
const scan = [];
for (const page of source.getPages()) {
scan.push(getLLMText(page));
}
const scanned = await Promise.all(scan);
return new Response(scanned.join('\n\n'));
}
================================================
FILE: apps/docs/app/llms.mdx/docs/[[...slug]]/route.ts
================================================
import { getLLMText, source } from '@/lib/source';
import { notFound } from 'next/navigation';
export const revalidate = false;
export async function GET(_req: Request, { params }: RouteContext<'/llms.mdx/docs/[[...slug]]'>) {
const { slug } = await params;
const page = source.getPage(slug);
if (!page) notFound();
return new Response(await getLLMText(page), {
headers: {
'Content-Type': 'text/markdown',
},
});
}
export function generateStaticParams() {
return source.generateParams();
}
================================================
FILE: apps/docs/app/llms.txt/route.ts
================================================
import { source } from '@/lib/source';
export const revalidate = false;
export async function GET() {
const lines: string[] = [];
lines.push('# Documentation');
lines.push('');
for (const page of source.getPages()) {
lines.push(`- [${page.data.title}](${page.url}): ${page.data.description}`);
}
return new Response(lines.join('\n'));
}
================================================
FILE: apps/docs/app/og/docs/[...slug]/route.tsx
================================================
import { getPageImage, source } from '@/lib/source';
import { notFound } from 'next/navigation';
import { ImageResponse } from 'next/og';
import { generate as DefaultImage } from 'fumadocs-ui/og';
export const revalidate = false;
export async function GET(_req: Request, { params }: RouteContext<'/og/docs/[...slug]'>) {
const { slug } = await params;
const page = source.getPage(slug.slice(0, -1));
if (!page) notFound();
return new ImageResponse(<DefaultImage title={page.data.title} description={page.data.description} site="My App" />, {
width: 1200,
height: 630,
});
}
export function generateStaticParams() {
return source.getPages().map((page) => ({
lang: page.locale,
slug: getPageImage(page).segments,
}));
}
================================================
FILE: apps/docs/components/ai/page-actions.tsx
================================================
'use client';
import { useMemo, useState } from 'react';
import { Check, ChevronDown, Copy, ExternalLinkIcon, TextIcon } from 'lucide-react';
import { cn } from '@/lib/cn';
import { useCopyButton } from 'fumadocs-ui/utils/use-copy-button';
import { buttonVariants } from 'fumadocs-ui/components/ui/button';
import { Popover, PopoverContent, PopoverTrigger } from 'fumadocs-ui/components/ui/popover';
const cache = new Map<string, string>();
export function LLMCopyButton({
/**
* A URL to fetch the raw Markdown/MDX content of page
*/
markdownUrl,
}: {
markdownUrl: string;
}) {
const [isLoading, setLoading] = useState(false);
const [checked, onClick] = useCopyButton(async () => {
const cached = cache.get(markdownUrl);
if (cached) return navigator.clipboard.writeText(cached);
setLoading(true);
try {
await navigator.clipboard.write([
new ClipboardItem({
'text/plain': fetch(markdownUrl).then(async (res) => {
const content = await res.text();
cache.set(markdownUrl, content);
return content;
}),
}),
]);
} finally {
setLoading(false);
}
});
return (
<button
disabled={isLoading}
className={cn(
buttonVariants({
color: 'secondary',
size: 'sm',
className: 'gap-2 [&_svg]:size-3.5 [&_svg]:text-fd-muted-foreground',
})
)}
onClick={onClick}>
{checked ? <Check /> : <Copy />}
Copy Markdown
</button>
);
}
export function ViewOptions({
markdownUrl,
githubUrl,
}: {
/**
* A URL to the raw Markdown/MDX content of page
*/
markdownUrl: string;
/**
* Source file URL on GitHub
*/
githubUrl: string;
}) {
const items = useMemo(() => {
const pageUrl = (globalThis as { location?: { href: string } }).location?.href ?? 'loading';
const q = `Read ${pageUrl}, I want to ask questions about it.`;
return [
{
title: 'Open in GitHub',
href: githubUrl,
icon: (
<svg fill="currentColor" role="img" viewBox="0 0 24 24">
<title>GitHub</title>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
</svg>
),
},
{
title: 'View as Markdown',
href: markdownUrl,
icon: <TextIcon />,
},
{
title: 'Open in Scira AI',
href: `https://scira.ai/?${new URLSearchParams({
q,
})}`,
icon: (
<svg width="910" height="934" viewBox="0 0 910 934" fill="none" xmlns="http://www.w3.org/2000/svg">
<title>Scira AI</title>
<path
d="M647.664 197.775C569.13 189.049 525.5 145.419 516.774 66.8849C508.048 145.419 464.418 189.049 385.884 197.775C464.418 206.501 508.048 250.131 516.774 328.665C525.5 250.131 569.13 206.501 647.664 197.775Z"
fill="currentColor"
stroke="currentColor"
strokeWidth="8"
strokeLinejoin="round"
/>
<path
d="M516.774 304.217C510.299 275.491 498.208 252.087 480.335 234.214C462.462 216.341 439.058 204.251 410.333 197.775C439.059 191.3 462.462 179.209 480.335 161.336C498.208 143.463 510.299 120.06 516.774 91.334C523.25 120.059 535.34 143.463 553.213 161.336C571.086 179.209 594.49 191.3 623.216 197.775C594.49 204.251 571.086 216.341 553.213 234.214C535.34 252.087 523.25 275.491 516.774 304.217Z"
fill="currentColor"
stroke="currentColor"
strokeWidth="8"
strokeLinejoin="round"
/>
<path
d="M857.5 508.116C763.259 497.644 710.903 445.288 700.432 351.047C689.961 445.288 637.605 497.644 543.364 508.116C637.605 518.587 689.961 570.943 700.432 665.184C710.903 570.943 763.259 518.587 857.5 508.116Z"
stroke="currentColor"
strokeWidth="20"
strokeLinejoin="round"
/>
<path
d="M700.432 615.957C691.848 589.05 678.575 566.357 660.383 548.165C642.191 529.973 619.499 516.7 592.593 508.116C619.499 499.533 642.191 486.258 660.383 468.066C678.575 449.874 691.848 427.181 700.432 400.274C709.015 427.181 722.289 449.874 740.481 468.066C758.673 486.258 781.365 499.533 808.271 508.116C781.365 516.7 758.673 529.973 740.481 548.165C722.289 566.357 709.015 589.05 700.432 615.957Z"
stroke="currentColor"
strokeWidth="20"
strokeLinejoin="round"
/>
<path
d="M889.949 121.237C831.049 114.692 798.326 81.9698 791.782 23.0692C785.237 81.9698 752.515 114.692 693.614 121.237C752.515 127.781 785.237 160.504 791.782 219.404C798.326 160.504 831.049 127.781 889.949 121.237Z"
fill="currentColor"
stroke="currentColor"
strokeWidth="8"
strokeLinejoin="round"
/>
<path
d="M791.782 196.795C786.697 176.937 777.869 160.567 765.16 147.858C752.452 135.15 736.082 126.322 716.226 121.237C736.082 116.152 752.452 107.324 765.16 94.6152C777.869 81.9065 786.697 65.5368 791.782 45.6797C796.867 65.5367 805.695 81.9066 818.403 94.6152C831.112 107.324 847.481 116.152 867.338 121.237C847.481 126.322 831.112 135.15 818.403 147.858C805.694 160.567 796.867 176.937 791.782 196.795Z"
fill="currentColor"
stroke="currentColor"
strokeWidth="8"
strokeLinejoin="round"
/>
<path
d="M760.632 764.337C720.719 814.616 669.835 855.1 611.872 882.692C553.91 910.285 490.404 924.255 426.213 923.533C362.022 922.812 298.846 907.419 241.518 878.531C184.19 849.643 134.228 808.026 95.4548 756.863C56.6815 705.7 30.1238 646.346 17.8129 583.343C5.50207 520.339 7.76433 455.354 24.4266 393.359C41.089 331.364 71.7099 274.001 113.947 225.658C156.184 177.315 208.919 139.273 268.117 114.442"
stroke="currentColor"
strokeWidth="30"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
),
},
{
title: 'Open in ChatGPT',
href: `https://chatgpt.com/?${new URLSearchParams({
hints: 'search',
q,
})}`,
icon: (
<svg role="img" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<title>OpenAI</title>
<path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z" />
</svg>
),
},
{
title: 'Open in Claude',
href: `https://claude.ai/new?${new URLSearchParams({
q,
})}`,
icon: (
<svg fill="currentColor" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<title>Anthropic</title>
<path d="M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z" />
</svg>
),
},
{
title: 'Open in Cursor',
icon: (
<svg fill="currentColor" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<title>Cursor</title>
<path d="M11.503.131 1.891 5.678a.84.84 0 0 0-.42.726v11.188c0 .3.162.575.42.724l9.609 5.55a1 1 0 0 0 .998 0l9.61-5.55a.84.84 0 0 0 .42-.724V6.404a.84.84 0 0 0-.42-.726L12.497.131a1.01 1.01 0 0 0-.996 0M2.657 6.338h18.55c.263 0 .43.287.297.515L12.23 22.918c-.062.107-.229.064-.229-.06V12.335a.59.59 0 0 0-.295-.51l-9.11-5.257c-.109-.063-.064-.23.061-.23" />
</svg>
),
href: `https://cursor.com/link/prompt?${new URLSearchParams({
text: q,
})}`,
},
];
}, [githubUrl, markdownUrl]);
return (
<Popover>
<PopoverTrigger
className={cn(
buttonVariants({
color: 'secondary',
size: 'sm',
className: 'gap-2',
})
)}>
Open
<ChevronDown className="size-3.5 text-fd-muted-foreground" />
</PopoverTrigger>
<PopoverContent className="flex flex-col">
{items.map((item) => (
<a
key={item.href}
href={item.href}
rel="noreferrer noopener"
target="_blank"
className="text-sm p-2 rounded-lg inline-flex items-center gap-2 hover:text-fd-accent-foreground hover:bg-fd-accent [&_svg]:size-4">
{item.icon}
{item.title}
<ExternalLinkIcon className="text-fd-muted-foreground size-3.5 ms-auto" />
</a>
))}
</PopoverContent>
</Popover>
);
}
================================================
FILE: apps/docs/components/docs/auto-option-sections.tsx
================================================
import type { DocEntry, TypeTableProps } from 'fumadocs-typescript';
import { typeGenerator } from '../../lib/type-generator';
import { ReferenceSections, buildEntryToc, renderInlineCode, toSlug, type HeadingLevel } from './reference-sections';
type AutoOptionSectionsProps = Pick<TypeTableProps, 'name' | 'path' | 'type'> & {
headingLevel?: HeadingLevel;
idPrefix?: string;
};
type AutoOptionSectionsTocProps = Pick<TypeTableProps, 'name' | 'path' | 'type'> & {
idPrefix?: string;
depth?: HeadingLevel;
};
const optionEntriesCache = new Map<string, Promise<DocEntry[]>>();
function getEntriesCacheKey({ path, name, type }: Pick<TypeTableProps, 'path' | 'name' | 'type'>): string {
return `${path ?? ''}|${name ?? ''}|${type ?? ''}`;
}
async function getOptionEntries(props: Pick<TypeTableProps, 'path' | 'name' | 'type'>): Promise<DocEntry[]> {
const cacheKey = getEntriesCacheKey(props);
const cachedEntries = optionEntriesCache.get(cacheKey);
if (cachedEntries != null) {
return cachedEntries;
}
const entriesPromise = typeGenerator.generateTypeTable(props).then((docs) => docs.flatMap((doc) => doc.entries));
optionEntriesCache.set(cacheKey, entriesPromise);
return entriesPromise;
}
function resolveIdPrefix(props: Pick<TypeTableProps, 'name' | 'type'>, idPrefix?: string): string {
const prefixSource = props.name ?? props.type ?? 'options';
return idPrefix ?? toSlug(prefixSource);
}
function readTagValues(entry: DocEntry, tagName: string): string[] {
const values: string[] = [];
for (const tag of entry.tags) {
if (tag.name !== tagName) {
continue;
}
const value = tag.text.trim();
if (value.length > 0) {
values.push(value);
}
}
return values;
}
export async function AutoOptionSections({ headingLevel = 3, idPrefix, ...props }: AutoOptionSectionsProps) {
const entries = await getOptionEntries(props);
const resolvedIdPrefix = resolveIdPrefix(props, idPrefix);
return (
<ReferenceSections
entries={entries}
idPrefix={resolvedIdPrefix}
emptyMessage="Could not generate options for this type."
headingLevel={headingLevel}
renderMeta={(entry) => {
const defaultValues = readTagValues(entry, 'default');
const extraTags = entry.tags.filter((tag) => tag.name !== 'default');
return (
<>
<ul>
<li>
<strong>Type:</strong> <code>{entry.type}</code>
</li>
{defaultValues.length > 0 ? (
<li>
<strong>Default:</strong> <code>{defaultValues[0]}</code>
</li>
) : null}
{entry.required ? (
<li>
<strong>Required:</strong> <code>true</code>
</li>
) : null}
</ul>
{entry.deprecated ? <p>Deprecated.</p> : null}
{extraTags.length > 0 ? (
<>
<p>
<strong>Additional Notes</strong>
</p>
<ul>
{extraTags.map((tag, index) => (
<li key={`${entry.name}-tag-${tag.name}-${index}`}>
<strong>@{tag.name}:</strong>{' '}
{renderInlineCode(tag.text, `${entry.name}-tag-${tag.name}-${index}`)}
</li>
))}
</ul>
</>
) : null}
</>
);
}}
/>
);
}
export async function getAutoOptionSectionsToc({ idPrefix, depth = 3, ...props }: AutoOptionSectionsTocProps) {
const entries = await getOptionEntries(props);
const resolvedIdPrefix = resolveIdPrefix(props, idPrefix);
return buildEntryToc({
entries,
idPrefix: resolvedIdPrefix,
depth,
});
}
================================================
FILE: apps/docs/components/docs/auto-runtime-reference.tsx
================================================
import { existsSync } from 'node:fs';
import nodePath from 'node:path';
import type { TOCItemType } from 'fumadocs-core/toc';
import { Node, Project, type ExportedDeclarations, type JSDocTag } from 'ts-morph';
import {
ReferenceSections,
buildEntryToc,
getEntryId,
renderInlineCode,
type BaseReferenceEntry,
} from './reference-sections';
type RuntimeExportKind = 'function' | 'component' | 'constant' | 'type';
type RuntimeParameter = {
name: string;
type: string;
description: string;
};
type RuntimeTag = {
name: string;
text: string;
};
type RuntimeExportEntry = BaseReferenceEntry & {
kind: RuntimeExportKind;
typeText: string;
parameters: RuntimeParameter[];
returnType?: string;
returnDescription?: string;
tags: RuntimeTag[];
sourceOrder: number;
declarationOrder: number;
};
type AutoRuntimeReferenceProps = {
path: string;
};
type SupportedDeclaration = Extract<
ExportedDeclarations,
| import('ts-morph').FunctionDeclaration
| import('ts-morph').VariableDeclaration
| import('ts-morph').TypeAliasDeclaration
>;
type ParsedDeclarationDocumentation = {
description: string;
parameterDescriptions: Map<string, string>;
returnDescription?: string;
tags: RuntimeTag[];
};
const GROUP_TITLES: Record<RuntimeExportKind, string> = {
function: 'Functions',
component: 'Components',
constant: 'Constants',
type: 'Types',
};
const GROUP_ORDER: RuntimeExportKind[] = ['function', 'component', 'constant', 'type'];
const RUNTIME_GROUP_ID_PREFIX = 'runtime-group';
const RUNTIME_EXPORT_ID_PREFIX = 'runtime-export';
let cachedProject: Project | undefined;
let cachedTsConfigPath: string | undefined;
const runtimeEntriesCache = new Map<string, RuntimeExportEntry[]>();
function resolveRepositoryRoot(startPath: string): string {
const candidates = [
startPath,
nodePath.resolve(startPath, '..'),
nodePath.resolve(startPath, '..', '..'),
nodePath.resolve(startPath, '..', '..', '..'),
];
for (const candidate of candidates) {
if (existsSync(nodePath.join(candidate, 'packages/react-native-boost/src/runtime/index.ts'))) {
return candidate;
}
}
throw new Error('Could not resolve repository root for runtime docs generation.');
}
function getProject(tsConfigPath: string): Project {
if (cachedProject != null && cachedTsConfigPath === tsConfigPath) {
return cachedProject;
}
cachedProject = new Project({
tsConfigFilePath: tsConfigPath,
});
cachedTsConfigPath = tsConfigPath;
return cachedProject;
}
function isSupportedDeclaration(declaration: ExportedDeclarations): declaration is SupportedDeclaration {
return (
Node.isFunctionDeclaration(declaration) ||
Node.isVariableDeclaration(declaration) ||
Node.isTypeAliasDeclaration(declaration)
);
}
function readTagComment(tag: JSDocTag): string {
const comment = tag.getComment();
if (typeof comment === 'string') {
return comment.trim();
}
if (!Array.isArray(comment)) {
return '';
}
return comment
.map((part) => {
if (part == null) {
return '';
}
if (typeof part === 'string') {
return part;
}
if (typeof part.getText === 'function') {
return part.getText();
}
return '';
})
.join('')
.trim();
}
function normalizeParameterDescription(value: string): string {
return value.replace(/^\s*-\s*/, '').trim();
}
function readDeclarationDocumentation(declaration: SupportedDeclaration): ParsedDeclarationDocumentation {
const jsDocs = Node.isVariableDeclaration(declaration)
? (declaration.getVariableStatement()?.getJsDocs() ?? [])
: declaration.getJsDocs();
const descriptions: string[] = [];
const parameterDescriptions = new Map<string, string>();
const tags: RuntimeTag[] = [];
let returnDescription: string | undefined;
for (const jsDoc of jsDocs) {
const description = jsDoc.getDescription().trim();
if (description.length > 0) {
descriptions.push(description);
}
for (const tag of jsDoc.getTags()) {
const tagName = tag.getTagName();
const text = readTagComment(tag);
if (Node.isJSDocParameterTag(tag)) {
parameterDescriptions.set(tag.getName(), normalizeParameterDescription(text));
continue;
}
if (Node.isJSDocReturnTag(tag)) {
returnDescription = text;
continue;
}
tags.push({
name: tagName,
text,
});
}
}
return {
description: descriptions.join('\n\n'),
parameterDescriptions,
returnDescription,
tags,
};
}
function readKind(declaration: SupportedDeclaration): RuntimeExportKind {
if (Node.isFunctionDeclaration(declaration)) {
return 'function';
}
if (Node.isTypeAliasDeclaration(declaration)) {
return 'type';
}
const sourceFilePath = declaration.getSourceFile().getFilePath().replaceAll('\\', '/');
if (sourceFilePath.includes('/runtime/components/')) {
return 'component';
}
return 'constant';
}
function readTypeText(declaration: SupportedDeclaration): string {
if (Node.isFunctionDeclaration(declaration)) {
const parameterSignature = declaration
.getParameters()
.map((parameter) => `${parameter.getName()}: ${parameter.getType().getText(parameter)}`)
.join(', ');
const returnType = declaration.getReturnType().getText(declaration);
return `(${parameterSignature}) => ${returnType}`;
}
if (Node.isTypeAliasDeclaration(declaration)) {
return declaration.getTypeNode()?.getText() ?? declaration.getType().getText(declaration);
}
return declaration.getType().getText(declaration);
}
function readParameters(
declaration: SupportedDeclaration,
parameterDescriptions: Map<string, string>
): RuntimeParameter[] {
if (!Node.isFunctionDeclaration(declaration)) {
return [];
}
return declaration.getParameters().map((parameter) => ({
name: parameter.getName(),
type: parameter.getType().getText(parameter),
description: parameterDescriptions.get(parameter.getName()) ?? '',
}));
}
function selectDeclaration(
declarations: ExportedDeclarations[],
sourceOrderByPath: Map<string, number>
): SupportedDeclaration | undefined {
const supportedDeclarations = declarations.filter((declaration) => isSupportedDeclaration(declaration));
if (supportedDeclarations.length === 0) {
return undefined;
}
return [...supportedDeclarations].sort((left, right) => {
const leftOrder = sourceOrderByPath.get(left.getSourceFile().getFilePath()) ?? Number.MAX_SAFE_INTEGER;
const rightOrder = sourceOrderByPath.get(right.getSourceFile().getFilePath()) ?? Number.MAX_SAFE_INTEGER;
if (leftOrder !== rightOrder) {
return leftOrder - rightOrder;
}
return left.getStart() - right.getStart();
})[0];
}
function getGroupHeadingId(group: RuntimeExportKind): string {
return getEntryId(RUNTIME_GROUP_ID_PREFIX, group);
}
function getRuntimeExportEntries(indexFilePath: string): RuntimeExportEntry[] {
const repositoryRoot = resolveRepositoryRoot(process.cwd());
const packageTsConfigPath = nodePath.join(repositoryRoot, 'packages/react-native-boost/tsconfig.json');
const docsRoot = nodePath.join(repositoryRoot, 'apps/docs');
const project = getProject(packageTsConfigPath);
const absoluteIndexFilePath = nodePath.resolve(docsRoot, indexFilePath);
const cachedEntries = runtimeEntriesCache.get(absoluteIndexFilePath);
if (cachedEntries != null) {
return cachedEntries;
}
const indexFile = project.getSourceFile(absoluteIndexFilePath) ?? project.addSourceFileAtPath(absoluteIndexFilePath);
const sourceOrderByPath = new Map<string, number>();
sourceOrderByPath.set(indexFile.getFilePath(), 0);
let sourceOrder = 1;
for (const exportDeclaration of indexFile.getExportDeclarations()) {
const sourceFile = exportDeclaration.getModuleSpecifierSourceFile();
if (sourceFile == null) {
continue;
}
const sourceFilePath = sourceFile.getFilePath();
if (!sourceOrderByPath.has(sourceFilePath)) {
sourceOrderByPath.set(sourceFilePath, sourceOrder);
sourceOrder += 1;
}
}
const entries: RuntimeExportEntry[] = [];
for (const [name, declarations] of indexFile.getExportedDeclarations()) {
const declaration = selectDeclaration(declarations, sourceOrderByPath);
if (declaration == null) {
continue;
}
const docs = readDeclarationDocumentation(declaration);
const kind = readKind(declaration);
const typeText = readTypeText(declaration);
const parameters = readParameters(declaration, docs.parameterDescriptions);
const returnType = Node.isFunctionDeclaration(declaration)
? declaration.getReturnType().getText(declaration)
: undefined;
entries.push({
name,
kind,
typeText,
description: docs.description,
parameters,
returnType,
returnDescription: docs.returnDescription,
tags: docs.tags,
sourceOrder: sourceOrderByPath.get(declaration.getSourceFile().getFilePath()) ?? Number.MAX_SAFE_INTEGER,
declarationOrder: declaration.getStart(),
});
}
const sortedEntries = entries.sort((left, right) => {
if (left.sourceOrder !== right.sourceOrder) {
return left.sourceOrder - right.sourceOrder;
}
return left.declarationOrder - right.declarationOrder;
});
runtimeEntriesCache.set(absoluteIndexFilePath, sortedEntries);
return sortedEntries;
}
export function getRuntimeReferenceToc(path: string): TOCItemType[] {
const entries = getRuntimeExportEntries(path);
const toc: TOCItemType[] = [];
for (const group of GROUP_ORDER) {
const groupEntries = entries.filter((entry) => entry.kind === group);
if (groupEntries.length === 0) {
continue;
}
toc.push({
title: GROUP_TITLES[group],
url: `#${getGroupHeadingId(group)}`,
depth: 3,
});
toc.push(
...buildEntryToc({
entries: groupEntries,
idPrefix: RUNTIME_EXPORT_ID_PREFIX,
depth: 4,
})
);
}
return toc;
}
export function AutoRuntimeReference({ path }: AutoRuntimeReferenceProps) {
const exports = getRuntimeExportEntries(path);
if (exports.length === 0) {
return <p>Could not generate runtime reference from the provided entry file.</p>;
}
return (
<>
{GROUP_ORDER.map((group) => {
const groupEntries = exports.filter((entry) => entry.kind === group);
if (groupEntries.length === 0) {
return null;
}
return (
<section key={group} className="mt-10 first:mt-0">
<h2 id={getGroupHeadingId(group)}>{GROUP_TITLES[group]}</h2>
<ReferenceSections
entries={groupEntries}
idPrefix={RUNTIME_EXPORT_ID_PREFIX}
emptyMessage="No runtime exports found for this group."
headingLevel={3}
renderMeta={(entry) => {
const remarks = entry.tags.filter((tag) => tag.name === 'remarks' && tag.text.length > 0);
const additionalTags = entry.tags.filter((tag) => tag.name !== 'remarks' && tag.text.length > 0);
return (
<>
<ul>
<li>
<strong>Type:</strong> <code>{entry.typeText}</code>
</li>
</ul>
{entry.parameters.length > 0 ? (
<>
<h4>Parameters</h4>
<ul>
{entry.parameters.map((parameter) => (
<li key={`${entry.name}-parameter-${parameter.name}`}>
<code>{parameter.name}</code>: <code>{parameter.type}</code>
{parameter.description.length > 0 ? ' - ' : ''}
{parameter.description.length > 0
? renderInlineCode(parameter.description, `${entry.name}-parameter-${parameter.name}`)
: null}
</li>
))}
</ul>
</>
) : null}
{entry.returnType == null ? null : (
<>
<h4>Returns</h4>
<p>
<code>{entry.returnType}</code>
{entry.returnDescription != null && entry.returnDescription.length > 0 ? ': ' : ''}
{entry.returnDescription != null && entry.returnDescription.length > 0
? renderInlineCode(entry.returnDescription, `${entry.name}-returns`)
: null}
</p>
</>
)}
{remarks.length > 0 ? (
<>
<h4>Notes</h4>
{remarks.map((tag, index) => (
<p key={`${entry.name}-remark-${index}`}>
{renderInlineCode(tag.text, `${entry.name}-remark-${index}`)}
</p>
))}
</>
) : null}
{additionalTags.length > 0 ? (
<>
<h4>Additional Tags</h4>
<ul>
{additionalTags.map((tag, index) => (
<li key={`${entry.name}-tag-${tag.name}-${index}`}>
<strong>@{tag.name}:</strong>{' '}
{renderInlineCode(tag.text, `${entry.name}-tag-${tag.name}-${index}`)}
</li>
))}
</ul>
</>
) : null}
</>
);
}}
/>
</section>
);
})}
</>
);
}
================================================
FILE: apps/docs/components/docs/reference-sections.tsx
================================================
import type { TOCItemType } from 'fumadocs-core/toc';
import type { ReactNode } from 'react';
export type HeadingLevel = 2 | 3 | 4 | 5 | 6;
export type BaseReferenceEntry = {
name: string;
description: string;
};
type ReferenceSectionsProps<TEntry extends BaseReferenceEntry> = {
entries: TEntry[];
idPrefix: string;
emptyMessage: string;
headingLevel?: HeadingLevel;
renderMeta: (entry: TEntry) => ReactNode;
};
type BuildEntryTocProps<TEntry extends BaseReferenceEntry> = {
entries: TEntry[];
idPrefix: string;
depth: HeadingLevel;
};
export function toSlug(value: string): string {
const slug = value
.toLowerCase()
.replaceAll(/[^a-z0-9]+/g, '-')
.replace(/^-+/, '')
.replace(/-+$/, '');
return slug.length > 0 ? slug : 'reference-entry';
}
export function getEntryId(idPrefix: string, value: string): string {
return `${idPrefix}-${toSlug(value)}`;
}
function toParagraphs(value: string): string[] {
return value
.split(/\n{2,}/)
.map((paragraph) => paragraph.replaceAll('\n', ' ').trim())
.filter((paragraph) => paragraph.length > 0);
}
export function renderInlineCode(value: string, keyPrefix: string): ReactNode {
const parts = value.split(/`([^`]+)`/g);
return parts.map((part, index) => {
if (index % 2 === 1) {
return <code key={`${keyPrefix}-code-${index}`}>{part}</code>;
}
return <span key={`${keyPrefix}-text-${index}`}>{part}</span>;
});
}
export function buildEntryToc<TEntry extends BaseReferenceEntry>({
entries,
idPrefix,
depth,
}: BuildEntryTocProps<TEntry>): TOCItemType[] {
return entries.map((entry) => ({
title: entry.name,
url: `#${getEntryId(idPrefix, entry.name)}`,
depth,
}));
}
export function ReferenceSections<TEntry extends BaseReferenceEntry>({
entries,
idPrefix,
emptyMessage,
headingLevel = 3,
renderMeta,
}: ReferenceSectionsProps<TEntry>) {
if (entries.length === 0) {
return <p>{emptyMessage}</p>;
}
const HeadingTag = `h${headingLevel}` as 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
return (
<>
{entries.map((entry) => {
const descriptionParagraphs = toParagraphs(entry.description);
return (
<section key={entry.name} id={getEntryId(idPrefix, entry.name)} className="mt-8 first:mt-0">
<HeadingTag>
<code>{entry.name}</code>
</HeadingTag>
{descriptionParagraphs.length > 0 ? (
descriptionParagraphs.map((paragraph, index) => (
<p key={`${entry.name}-description-${index}`}>
{renderInlineCode(paragraph, `${entry.name}-description-${index}`)}
</p>
))
) : (
<p>No description provided.</p>
)}
{renderMeta(entry)}
</section>
);
})}
</>
);
}
================================================
FILE: apps/docs/content/docs/configuration/boost-decorator.mdx
================================================
---
title: "Decorators"
description: Control optimization on individual JSX elements with @boost-ignore and @boost-force.
---
## @boost-ignore
Use `@boost-ignore` to disable optimization on a specific element.
If a line containing `@boost-ignore` appears immediately before a JSX opening tag, that component is skipped.
```jsx
<Text>This will be optimized.</Text>
{/* @boost-ignore */}
<Text>This will not be optimized.</Text>
```
## @boost-force
Use `@boost-force` to force optimization on a specific element, even if it would normally be skipped by a bailout rule (e.g. blacklisted props, unresolvable spreads, or ancestor checks).
The only check that `@boost-force` does **not** override is the `react-native` import check — the component must still be imported from `react-native`.
```jsx
const Component = ({ props }) => {
return (
{/* @boost-force */}
<Text {...props}>This will be optimized despite having unresolvable spread props.</Text>
)
}
```
<Callout type="warn" title="Use with caution">
`@boost-force` bypasses safety checks that exist to prevent behavioral changes.
Only use it when you are confident that the optimization is safe for your specific use case — for example,
when a wrapper component filters or handles props before passing them to the underlying native component.
</Callout>
================================================
FILE: apps/docs/content/docs/configuration/configure.mdx
================================================
---
title: Configure the Babel Plugin
description: Control logging, ignores, and optimization behavior.
---
The Babel plugin (`react-native-boost/plugin`) is the core of React Native Boost.
Defaults are safe and usable out of the box, but you can tune behavior for your app.
## Example Configuration
```js
// babel.config.js
module.exports = {
plugins: [
[
'react-native-boost/plugin',
{
verbose: false,
silent: false,
ignores: ['node_modules/**'],
optimizations: {
text: true,
view: true,
},
},
],
],
};
```
## Plugin Options
<AutoOptionSections path="../../packages/react-native-boost/src/plugin/types/index.ts" name="PluginOptions" idPrefix="plugin-options" />
## Plugin Optimization Options
<AutoOptionSections
path="../../packages/react-native-boost/src/plugin/types/index.ts"
name="PluginOptimizationOptions"
idPrefix="plugin-optimization-options"
/>
## Environment-Specific Enablement
You can enable React Native Boost by environment with Babel `env` config:
```js
module.exports = {
env: {
development: {
plugins: ['react-native-boost/plugin'],
},
},
};
```
See Babel docs: https://babeljs.io/docs/options#env
================================================
FILE: apps/docs/content/docs/configuration/nativewind.mdx
================================================
---
title: Nativewind Support
description: Configure cssInterop for optimized components.
---
If your app uses Nativewind, configure `cssInterop` for optimized components from
`react-native-boost/runtime`.
## Example
```jsx
import { cssInterop } from 'nativewind';
import { NativeText, NativeView } from 'react-native-boost/runtime';
cssInterop(NativeText, { className: 'style' });
cssInterop(NativeView, { className: 'style' });
```
This mirrors Nativewind's own mapping for `Text`/`View`.
## Known Limitations
### `select-*`
Nativewind maps `select-*` classes to `userSelect`. Native `Text` does not accept `userSelect` directly and uses the
`selectable` prop.
#### Recommended Usage
```jsx
// Avoid
<Text className="select-auto">Hello world</Text>
// Use
<Text selectable>Hello world</Text>
// or
<Text style={{ userSelect: 'auto' }}>Hello world</Text>
```
You can map values with `userSelectToSelectableMap` from the runtime package.
### `align-*`
Nativewind maps `align-*` classes to `verticalAlign`, while native `Text` expects `textAlignVertical`.
#### Recommended Usage
```jsx
// Avoid
<Text className="align-center">Hello world</Text>
// Use
<Text style={{ textAlignVertical: 'center' }}>Hello world</Text>
// or
<Text style={{ verticalAlign: 'middle' }}>Hello world</Text>
```
You can map values with `verticalAlignToTextAlignVerticalMap` from the runtime package.
================================================
FILE: apps/docs/content/docs/index.mdx
================================================
---
title: Getting Started
description: Install React Native Boost to boost your app's performance with one line of code.
---
import { Tab, Tabs } from 'fumadocs-ui/components/tabs'
## Introduction
React Native Boost consists of two pieces:
- A Babel plugin that statically analyzes your source code and replaces safe `Text` and `View` components with their direct native counterparts, leading to significant performance improvements compared to the JS-based wrapper components.
- A runtime package used by the plugin for cross-platform-safe imports and helper utilities.
The analyzer is intentionally strict and skips any optimizations that could lead to behavioral changes or other bugs.
## Compatibility
| `react-native-boost` | React Native |
| --- | --- |
| `0.x` | All versions[^1] |
| `1.x` | `>=0.83` |
[^1]: Starting from React Native `0.80`, `react-native-boost@0` prints import deprecation warnings. [See here.](https://github.com/react-native-community/discussions-and-proposals/discussions/893)
## Getting Started
1. Install React Native Boost:
<Tabs items={['npm', 'pnpm', 'yarn', 'bun']} groupId="package-manager" persist>
<Tab value="npm">
```bash
npm install react-native-boost
```
</Tab>
<Tab value="pnpm">
```bash
pnpm add react-native-boost
```
</Tab>
<Tab value="yarn">
```bash
yarn add react-native-boost
```
</Tab>
<Tab value="bun">
```bash
bun add react-native-boost
```
</Tab>
</Tabs>
2. If you use Expo and do not have a `babel.config.js` yet:
```bash
npx expo customize babel.config.js
```
3. Add the plugin:
```js
// babel.config.js
module.exports = {
plugins: ['react-native-boost/plugin'],
};
```
4. Restart the development server and clear cache:
<Tabs items={['npm', 'pnpm', 'yarn', 'bun']} groupId="package-manager" persist>
<Tab value="npm">
```bash
npm start -- --clear
```
</Tab>
<Tab value="pnpm">
```bash
pnpm start -- --clear
```
</Tab>
<Tab value="yarn">
```bash
yarn start --clear
```
</Tab>
<Tab value="bun">
```bash
bun run start --clear
```
</Tab>
</Tabs>
<Callout title="Runtime Dependency">
The Babel plugin imports optimized components via `react-native-boost/runtime`, so `react-native-boost` must be
available at runtime and can therefore **not** be installed as a dev dependency.
</Callout>
## Platform Support
React Native Boost supports iOS and Android projects. On Web, React Native Boost safely falls back to the default components, providing full cross-platform support.
<Cards>
<Card title="How It Works" href="/docs/information/how-it-works" />
<Card title="Coverage & Bailouts" href="/docs/information/optimization-coverage" />
<Card title="Troubleshooting" href="/docs/information/troubleshooting" />
<Card title="Configuration" href="/docs/configuration/configure" />
<Card title="Runtime Library" href="/docs/runtime-library" />
</Cards>
================================================
FILE: apps/docs/content/docs/information/benchmarks.mdx
================================================
---
title: Benchmarks
description: Benchmark results from the repository example app.
---
We run benchmarks with the example app available in the repository to measure render-time improvements.
In recent runs, React Native Boost improved rendering performance on both iOS and Android, with gains up to ~50%
depending on component mix and screen structure.


The more `Text` and `View` components your UI renders (especially in lists), the more measurable the gains are likely
to be.
================================================
FILE: apps/docs/content/docs/information/how-it-works.mdx
================================================
---
title: How It Works
description: Understand why React Native Boost makes your app faster, and how the Babel optimizer decides when transformations are safe.
---
React Native components such as `Text` and `View` are JavaScript wrappers around their native implementations.
Those wrappers handle many edge cases, but they also add a considerable amount of runtime overhead.
React Native Boost analyzes your code at build time and replaces these components with their native equivalents fully automatically. The plugin performs static analysis on your code to determine when it's safe to optimize a component and when it's not.
Optimized components are imported from `react-native-boost/runtime`, not directly from `react-native`, which allows graceful fallback for web targets
and other non-native environments when native internals are unavailable.
## Static Analysis
For each candidate component, the plugin verifies conditions such as:
- Import source checks (for example, imported from `react-native`)
- Prop compatibility checks
- Ancestor and context safety checks
- Children/structure checks
If any safety requirement is not met, the component is left unchanged in order to avoid behavioral changes or other bugs.
================================================
FILE: apps/docs/content/docs/information/optimization-coverage.mdx
================================================
---
title: Optimization Coverage
description: What React Native Boost can optimize today, what it skips, and why.
---
React Native Boost is conservative by design. If it cannot prove an optimization is safe within the possibilities of a Babel plugin, it skips it. While this means it'll often skip optimizations that would be safe in practice, it also means that you can trust that optimizations that do happen are safe and won't cause behavioral changes or other regressions.
## At a Glance
| Component | Optimized when... | Common bailout reasons |
| --- | --- | --- |
| `Text` | Imported from `react-native`, no blacklisted props, string-safe children | `contains blacklisted props`, `contains non-string children`, `is a direct child of expo-router Link with asChild` |
| `View` | Imported from `react-native`, no blacklisted props, safe ancestor chain | `contains blacklisted props`, `has Text ancestor`, `has unresolved ancestor and dangerous optimization is disabled` |
## Global Bailouts
These skip optimization before component-specific checks:
- File path matches `ignores`
- Line is marked with `@boost-ignore`
<Callout title="No log for ignored files">
Files skipped via `ignores` are filtered before optimizer checks, so you will not see per-component skip logs for
those files.
</Callout>
## Overriding Bailouts
Use `@boost-force` to force optimization on a component that would otherwise be skipped. This bypasses all bailout checks except the `react-native` import check. See the [Decorators](/docs/configuration/boost-decorator#boost-force) page for details.
## Text Coverage
`Text` is optimized when all checks pass.
### Text blacklisted props
If any of these are present, the `Text` node is skipped:
- Interaction/responder props (`onPress`, `onLongPress`, `onResponder*`, `pressRetentionOffset`, etc.)
- `selectionColor`
- `id`, `nativeID`
### Text structure checks
- Children must be string-safe.
- `Text` is skipped when used as a direct child of `expo-router` `Link` with `asChild`.
```tsx
import { Link } from 'expo-router';
import { Text } from 'react-native';
<Link asChild>
<Text>Open profile</Text>
</Link>;
```
## View Coverage
`View` has stricter safety checks because `View` inside text-like ancestors can break layout/semantics.
### View blacklisted props
If any of these are present, the `View` node is skipped:
- `style`
- Accessibility props (`accessible`, `accessibilityLabel`, `accessibilityState`, `aria-*`)
- `id`, `nativeID`
### Ancestor safety checks
`View` optimization depends on ancestor classification:
- `safe`: optimize
- `text`: skip (`has Text ancestor`)
- `unknown`: skip by default
Set `dangerouslyOptimizeViewWithUnknownAncestors: true` to optimize `unknown` ancestors too.
<Callout type="warn" title="Dangerous Mode">
Enabling dangerous mode can increase optimization coverage, but it can also introduce regressions if unresolved
ancestors render Text wrappers.
</Callout>
## Spread Props: Resolvable vs Unresolvable
Unresolvable spread props are treated as unsafe and cause bailouts.
```tsx
// Usually optimizable (resolvable object literal)
<Text {...{ selectable: true }}>Hello</Text>
// Usually skipped (cannot be statically resolved)
<Text {...props}>Hello</Text>
```
Same rule applies to `View`.
================================================
FILE: apps/docs/content/docs/information/troubleshooting.mdx
================================================
---
title: Troubleshooting
description: Common setup and optimization issues, plus fast ways to diagnose them.
---
## Quick Diagnostic Flow
1. Set `verbose: true` and `silent: false` in plugin config.
2. Restart Metro with cache clear.
3. Check skip reasons in logs.
4. Compare with the coverage rules in [Optimization Coverage](/docs/information/optimization-coverage).
## Common Issues
### No optimization logs at all
Likely causes:
- Plugin not loaded in `babel.config.js`
- `silent: true`
- File matched by `ignores`
Quick checks:
```js
module.exports = {
plugins: [
[
'react-native-boost/plugin',
{
verbose: true,
silent: false,
},
],
],
};
```
```bash
npm start -- --clear
```
### Skip reason: `contains blacklisted props`
This is expected for unsupported prop sets.
Typical cases:
- `Text` with press/responder props
- `View` with `style` or accessibility props
Fix options:
- Keep component as-is (recommended when semantics matter)
- Move unsupported behavior to a different node when possible
- Use `@boost-ignore` for explicit clarity
### Skip reason: `has unresolved ancestor and dangerous optimization is disabled`
`View` is inside an ancestor React Native Boost cannot statically classify.
Options:
- Keep default behavior (safest)
- Refactor ancestor/component structure to be statically obvious
- Enable `dangerouslyOptimizeViewWithUnknownAncestors` only if you can validate behavior carefully
### Ignores do not work as expected in monorepos
`ignores` are resolved from Babel's working directory.
In nested apps, you may need explicit parent paths:
```js
ignores: ['../../node_modules/**'];
```
### Runtime import errors in app code
The plugin injects imports from `react-native-boost/runtime`.
If you installed `react-native-boost` as a dev dependency, runtime imports can fail in app builds.
Fix: install it as a regular dependency.
================================================
FILE: apps/docs/content/docs/meta.json
================================================
{
"title": "React Native Boost",
"description": "Documentation for React Native Boost",
"root": true,
"pages": [
"index",
"---Information---",
"information/how-it-works",
"information/optimization-coverage",
"information/troubleshooting",
"information/benchmarks",
"---Configuration---",
"configuration/configure",
"configuration/nativewind",
"configuration/boost-decorator",
"---Runtime Library---",
"runtime-library/index"
]
}
================================================
FILE: apps/docs/content/docs/runtime-library/index.mdx
================================================
---
title: Runtime Library
description: Runtime exports used by the Babel plugin and advanced integrations.
---
`react-native-boost/runtime` is used by the Babel plugin to apply optimizations safely across platforms.
Besides re-exporting optimized native components with web-safe fallbacks, it also exposes helper utilities.
Direct usage is supported but generally not recommended unless needed for advanced integrations (for example,
[Nativewind setup](/docs/configuration/nativewind)).
## API Reference
This section is automatically generated from runtime exports.
<AutoRuntimeReference path="../../packages/react-native-boost/src/runtime/index.ts" />
================================================
FILE: apps/docs/lib/cn.ts
================================================
export { twMerge as cn } from 'tailwind-merge';
================================================
FILE: apps/docs/lib/layout.shared.tsx
================================================
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
export const gitConfig = {
user: 'kuatsu',
repo: 'react-native-boost',
branch: 'main',
};
export function baseOptions(): BaseLayoutProps {
return {
nav: {
title: 'React Native Boost',
},
githubUrl: `https://github.com/${gitConfig.user}/${gitConfig.repo}`,
};
}
================================================
FILE: apps/docs/lib/source.ts
================================================
import { docs } from 'fumadocs-mdx:collections/server';
import { type InferPageType, loader } from 'fumadocs-core/source';
import { lucideIconsPlugin } from 'fumadocs-core/source/lucide-icons';
// See https://fumadocs.dev/docs/headless/source-api for more info
export const source = loader({
baseUrl: '/docs',
source: docs.toFumadocsSource(),
plugins: [lucideIconsPlugin()],
});
export function getPageImage(page: InferPageType<typeof source>) {
const segments = [...page.slugs, 'image.png'];
return {
segments,
url: `/og/docs/${segments.join('/')}`,
};
}
export async function getLLMText(page: InferPageType<typeof source>) {
const processed = await page.data.getText('processed');
return `# ${page.data.title}
${processed}`;
}
================================================
FILE: apps/docs/lib/type-generator.ts
================================================
import 'server-only';
import { createFileSystemGeneratorCache, createGenerator, type Generator } from 'fumadocs-typescript';
export const typeGenerator: Generator = createGenerator({
cache: createFileSystemGeneratorCache('.next/fumadocs-typescript'),
});
================================================
FILE: apps/docs/mdx-components.tsx
================================================
import defaultMdxComponents from 'fumadocs-ui/mdx';
import { AutoTypeTable } from 'fumadocs-typescript/ui';
import type { MDXComponents } from 'mdx/types';
import { AutoOptionSections } from '@/components/docs/auto-option-sections';
import { AutoRuntimeReference } from '@/components/docs/auto-runtime-reference';
import { typeGenerator } from '@/lib/type-generator';
export function getMDXComponents(components?: MDXComponents): MDXComponents {
return {
...defaultMdxComponents,
AutoOptionSections,
AutoRuntimeReference,
AutoTypeTable: (props) => <AutoTypeTable {...props} generator={typeGenerator} />,
...components,
};
}
================================================
FILE: apps/docs/next.config.mjs
================================================
import { createMDX } from 'fumadocs-mdx/next';
const withMDX = createMDX();
/** @type {import('next').NextConfig} */
const config = {
reactStrictMode: true,
async rewrites() {
return [
{
source: '/docs/:path*.mdx',
destination: '/llms.mdx/docs/:path*',
},
];
},
};
export default withMDX(config);
================================================
FILE: apps/docs/package.json
================================================
{
"name": "react-native-boost-docs",
"version": "0.0.0",
"private": true,
"scripts": {
"build": "next build",
"dev": "next dev",
"start": "next start",
"typecheck": "pnpm run types:check",
"types:check": "fumadocs-mdx && next typegen && tsc --noEmit",
"postinstall": "fumadocs-mdx"
},
"dependencies": {
"fumadocs-core": "16.6.7",
"fumadocs-mdx": "14.2.8",
"fumadocs-typescript": "^5.1.4",
"fumadocs-ui": "16.6.7",
"lucide-react": "^0.575.0",
"next": "16.1.6",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"ts-morph": "^27.0.2",
"tailwind-merge": "^3.5.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.2.1",
"@types/mdx": "^2.0.13",
"@types/node": "^25.3.1",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"postcss": "^8.5.6",
"tailwindcss": "^4.2.1",
"typescript": "^5.9.3"
}
}
================================================
FILE: apps/docs/postcss.config.mjs
================================================
const config = {
plugins: {
'@tailwindcss/postcss': {},
},
};
export default config;
================================================
FILE: apps/docs/source.config.ts
================================================
import { defineConfig, defineDocs } from 'fumadocs-mdx/config';
import { metaSchema, pageSchema } from 'fumadocs-core/source/schema';
// You can customise Zod schemas for frontmatter and `meta.json` here
// see https://fumadocs.dev/docs/mdx/collections
export const docs = defineDocs({
dir: 'content/docs',
docs: {
schema: pageSchema,
postprocess: {
includeProcessedMarkdown: true,
},
},
meta: {
schema: metaSchema,
},
});
export default defineConfig({
mdxOptions: {
// MDX options
},
});
================================================
FILE: apps/docs/tsconfig.json
================================================
{
"compilerOptions": {
"baseUrl": ".",
"target": "ESNext",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"paths": {
"@/*": ["./*"],
"fumadocs-mdx:collections/*": [".source/*"]
},
"plugins": [
{
"name": "next"
}
]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"],
"exclude": ["node_modules"]
}
================================================
FILE: apps/example/.gitignore
================================================
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
# dependencies
node_modules/
# Expo
.expo/
dist/
web-build/
expo-env.d.ts
# Native
/ios
/android
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
# Metro
.metro-health-check*
# debug
npm-debug.*
yarn-debug.*
yarn-error.*
# macOS
.DS_Store
*.pem
# local env files
.env*.local
# typescript
*.tsbuildinfo
================================================
FILE: apps/example/app.json
================================================
{
"expo": {
"name": "RN Boost",
"slug": "react-native-boost-example",
"version": "0.0.1",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"newArchEnabled": true,
"splash": {
"image": "./assets/splash-icon.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.kuatsu-mkrause.react-native-boost-example"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"package": "com.kuatsumkrause.reactnativeboostexample"
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}
================================================
FILE: apps/example/babel.config.js
================================================
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [['react-native-boost/plugin', { ignores: ['node_modules/**', '../../node_modules/**'] }]],
};
};
================================================
FILE: apps/example/index.ts
================================================
import { registerRootComponent } from 'expo';
import App from './src/app';
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in Expo Go or in a native build,
// the environment is set up appropriately
registerRootComponent(App);
================================================
FILE: apps/example/package.json
================================================
{
"name": "react-native-boost-example",
"version": "0.0.1",
"main": "index.ts",
"scripts": {
"start": "expo start",
"dev": "expo start",
"android": "rm -rf android && expo run:android",
"ios": "rm -rf ios && expo run:ios",
"web": "expo start --web"
},
"dependencies": {
"@expo/metro-runtime": "~55.0.6",
"expo": "^55.0.3",
"expo-status-bar": "~55.0.4",
"react": "19.2.0",
"react-dom": "19.2.0",
"react-native": "0.83.2",
"react-native-safe-area-context": "~5.6.0",
"react-native-boost": "workspace:*",
"react-native-time-to-render": "workspace:*",
"react-native-web": "^0.21.2"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@types/react": "~19.2.14",
"typescript": "~5.9.3"
},
"private": true
}
================================================
FILE: apps/example/src/app.tsx
================================================
import { StatusBar } from 'expo-status-bar';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import HomeScreen from './screens/home';
export default function App() {
return (
<SafeAreaProvider>
<StatusBar style="auto" />
<HomeScreen />
</SafeAreaProvider>
);
}
================================================
FILE: apps/example/src/components/measure-component.tsx
================================================
import React from 'react';
import { TimeToRenderView } from 'react-native-time-to-render';
import { Benchmark, BenchmarkStep } from '../types';
import { View } from 'react-native';
export interface BenchmarkProperties extends Benchmark {
onRenderTimeChange: (renderTime: number) => void;
step: BenchmarkStep;
markerName: string;
}
export default function MeasureComponent(props: BenchmarkProperties) {
const optimizedViews = Array.from({ length: props.count }, (_, index) =>
React.cloneElement(props.optimizedComponent as React.ReactElement, { key: `optimized-${index}` })
);
const unoptimizedViews = Array.from({ length: props.count }, (_, index) =>
React.cloneElement(props.unoptimizedComponent as React.ReactElement, { key: `unoptimized-${index}` })
);
if (props.step === BenchmarkStep.Unoptimized) {
return (
<>
<TimeToRenderView
markerName={props.markerName}
onMarkerPainted={(event) => {
props.onRenderTimeChange(Math.round(event.nativeEvent.paintTime));
}}
/>
<View style={{ display: 'none' }}>{unoptimizedViews}</View>
</>
);
}
return (
<>
<TimeToRenderView
markerName={props.markerName}
onMarkerPainted={(event) => {
props.onRenderTimeChange(Math.round(event.nativeEvent.paintTime));
}}
/>
<View style={{ display: 'none' }}>{optimizedViews}</View>
</>
);
}
================================================
FILE: apps/example/src/screens/home.tsx
================================================
import { Pressable, StyleSheet, Text, View } from 'react-native';
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
import { useMemo, useState } from 'react';
import { startMarker } from 'react-native-time-to-render';
import { Benchmark, BenchmarkStep } from '../types';
import MeasureComponent from '../components/measure-component';
import { getMarkerName } from '../utils/helpers';
const benchmarks = [
{
title: 'Text',
count: 10_000,
// @boost-ignore
unoptimizedComponent: <Text style={{ color: 'red' }}>Nice text</Text>,
optimizedComponent: <Text style={{ color: 'red' }}>Nice text</Text>,
},
{
title: 'View',
count: 10_000,
// @boost-ignore
unoptimizedComponent: <View style={{ borderWidth: 1, borderColor: 'red' }} />,
optimizedComponent: <View style={{ borderWidth: 1, borderColor: 'red' }} />,
},
] satisfies Benchmark[];
export default function HomeScreen() {
const insets = useSafeAreaInsets();
const [currentStepIndex, setCurrentStepIndex] = useState(0);
const [runBenchmark, setRunBenchmark] = useState(false);
const [results, setResults] = useState<Record<number, { unoptimized: number | null; optimized: number | null }>>({});
const totalSteps = benchmarks.length * 2;
const currentBenchmark = useMemo(() => Math.floor(currentStepIndex / 2), [currentStepIndex]);
const currentStep = useMemo<BenchmarkStep>(
() => (currentStepIndex % 2 === 0 ? BenchmarkStep.Unoptimized : BenchmarkStep.Optimized),
[currentStepIndex]
);
const progress = useMemo<[number, number]>(() => {
return [currentStepIndex, totalSteps];
}, [currentStepIndex, totalSteps]);
const buttonTitle = useMemo(() => {
if (currentStepIndex === 0) {
return 'Start Benchmark';
}
if (currentStepIndex === totalSteps - 1) {
return 'Last Step';
}
return 'Next Step';
}, [currentStepIndex, totalSteps]);
const markerName = useMemo(
() => getMarkerName(benchmarks[currentBenchmark].title, currentStep),
[currentBenchmark, currentStep]
);
const resultRows = useMemo(() => {
return benchmarks.map((benchmark, index) => {
const value = results[index];
const unoptimized = value?.unoptimized ?? null;
const optimized = value?.optimized ?? null;
const gainPercent =
unoptimized === null || optimized === null || unoptimized === 0 ? null : (1 - optimized / unoptimized) * 100;
const gain = gainPercent === null ? 'N/A' : `${gainPercent.toFixed(2)}%`;
return {
title: benchmark.title,
unoptimizedText: unoptimized === null ? '--' : `${unoptimized}ms`,
optimizedText: optimized === null ? '--' : `${optimized}ms`,
gain,
gainPercent,
};
});
}, [results]);
const handleRun = (timestamp: number) => {
startMarker(markerName, timestamp);
setRunBenchmark(true);
};
const handleRenderTimeChange = (renderTime: number) => {
setRunBenchmark(false);
setResults((previousResults) => {
const baseResults = currentStepIndex === 0 ? {} : previousResults;
const previousBenchmarkResult = baseResults[currentBenchmark] ?? { unoptimized: null, optimized: null };
return {
...baseResults,
[currentBenchmark]:
currentStep === BenchmarkStep.Unoptimized
? { unoptimized: renderTime, optimized: null }
: { ...previousBenchmarkResult, optimized: renderTime },
};
});
setCurrentStepIndex((previousStepIndex) => (previousStepIndex + 1) % totalSteps);
};
return (
<SafeAreaView style={styles.container}>
<View style={styles.content}>
<View style={styles.headerCard}>
<Text style={styles.title}>React Native Boost Benchmark</Text>
<Text
style={
styles.subtitle
}>{`Step ${progress[0] + 1} / ${progress[1]}: ${benchmarks[currentBenchmark].title} (${currentStep})`}</Text>
</View>
<View style={styles.tableCard}>
<View style={[styles.tableRow, styles.tableHeader]}>
<Text style={[styles.tableCell, styles.benchmarkColumn, styles.tableHeaderText]}>Test</Text>
<Text style={[styles.tableCell, styles.metricColumn, styles.tableHeaderText]}>Unopt.</Text>
<Text style={[styles.tableCell, styles.metricColumn, styles.tableHeaderText]}>Opt.</Text>
<Text style={[styles.tableCell, styles.metricColumn, styles.tableHeaderText]}>Gain</Text>
</View>
{resultRows.map((row, index) => (
<View
key={row.title}
style={[
styles.tableRow,
index % 2 === 0 ? styles.tableStripeLight : styles.tableStripeDark,
index === currentBenchmark && styles.tableActiveRow,
]}>
<Text style={[styles.tableCell, styles.benchmarkColumn, styles.benchmarkText]}>{row.title}</Text>
<Text style={[styles.tableCell, styles.metricColumn, styles.metricText]}>{row.unoptimizedText}</Text>
<Text style={[styles.tableCell, styles.metricColumn, styles.metricText]}>{row.optimizedText}</Text>
<Text
style={[
styles.tableCell,
styles.metricColumn,
styles.metricText,
row.gainPercent === null
? styles.gainNeutral
: row.gainPercent >= 0
? styles.gainPositive
: styles.gainNegative,
]}>
{row.gain}
</Text>
</View>
))}
</View>
</View>
<View style={[styles.footer, { bottom: insets.bottom + 16 }]}>
<Pressable
accessibilityRole="button"
onPress={(event) => handleRun(event.nativeEvent.timestamp)}
style={({ pressed }) => [styles.runButton, pressed && styles.runButtonPressed]}>
<Text style={styles.runButtonText}>{buttonTitle}</Text>
</Pressable>
</View>
{runBenchmark && (
<MeasureComponent
key={markerName}
onRenderTimeChange={handleRenderTimeChange}
step={currentStep}
{...benchmarks[currentBenchmark]}
markerName={markerName}
/>
)}
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff8ef',
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 16,
},
content: {
width: '100%',
maxWidth: 640,
},
headerCard: {
backgroundColor: '#ffffff',
borderRadius: 14,
borderWidth: 1,
borderColor: '#f1d4a3',
paddingHorizontal: 16,
paddingVertical: 14,
marginBottom: 12,
},
title: {
fontSize: 20,
fontWeight: '700',
color: '#5e3c0c',
},
subtitle: {
marginTop: 4,
fontSize: 13,
color: '#7a4b00',
fontWeight: '600',
textTransform: 'capitalize',
},
runButton: {
backgroundColor: '#ff9800',
borderRadius: 12,
paddingVertical: 12,
alignItems: 'center',
width: '100%',
maxWidth: 640,
},
runButtonPressed: {
transform: [{ scale: 0.985 }],
opacity: 0.95,
},
runButtonText: {
color: '#2f1d00',
fontSize: 15,
fontWeight: '700',
},
tableCard: {
borderRadius: 14,
overflow: 'hidden',
borderWidth: 1,
borderColor: '#f1d4a3',
backgroundColor: '#ffffff',
},
footer: {
position: 'absolute',
left: 16,
right: 16,
alignItems: 'center',
},
tableRow: {
flexDirection: 'row',
alignItems: 'center',
minHeight: 42,
},
tableHeader: {
backgroundColor: '#fff0d6',
borderBottomWidth: 1,
borderBottomColor: '#f1d4a3',
},
tableHeaderText: {
fontSize: 12,
fontWeight: '700',
color: '#7a4b00',
},
tableStripeLight: {
backgroundColor: '#ffffff',
},
tableStripeDark: {
backgroundColor: '#fffaf2',
},
tableActiveRow: {
backgroundColor: '#ffe8c2',
},
tableCell: {
paddingHorizontal: 10,
paddingVertical: 8,
},
benchmarkColumn: {
flex: 1.4,
},
metricColumn: {
flex: 1,
alignItems: 'flex-end',
},
benchmarkText: {
fontSize: 14,
color: '#4d3311',
fontWeight: '600',
},
metricText: {
fontSize: 13,
color: '#6e4c1d',
textAlign: 'right',
},
gainPositive: {
color: '#0d7a3b',
fontWeight: '700',
},
gainNegative: {
color: '#b42318',
fontWeight: '700',
},
gainNeutral: {
color: '#6e4c1d',
},
});
================================================
FILE: apps/example/src/types/index.ts
================================================
export interface Benchmark {
title: string;
count: number;
optimizedComponent: React.ReactNode;
unoptimizedComponent: React.ReactNode;
}
export enum BenchmarkStep {
Unoptimized = 'unoptimized',
Optimized = 'optimized',
}
================================================
FILE: apps/example/src/utils/helpers.ts
================================================
import { BenchmarkStep } from '../types';
export const getMarkerName = (title: string, step: BenchmarkStep) => `${title}-${step}`;
================================================
FILE: apps/example/tsconfig.json
================================================
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true
}
}
================================================
FILE: commitlint.config.mjs
================================================
export default { extends: ['@commitlint/config-conventional'] };
================================================
FILE: package.json
================================================
{
"name": "react-native-boost-monorepo",
"version": "0.0.0",
"private": true,
"scripts": {
"build": "pnpm -r --parallel --if-present run build",
"typecheck": "pnpm -r --parallel --if-present run typecheck",
"test": "pnpm -r --parallel --if-present run test",
"example": "pnpm --filter react-native-boost-example run",
"dev": "pnpm --parallel --stream --filter react-native-boost --filter react-native-boost-example run dev",
"docs": "pnpm --filter react-native-boost-docs run",
"package": "pnpm --filter react-native-boost run",
"lint": "oxlint .",
"format": "oxfmt .",
"prepare": "husky"
},
"packageManager": "pnpm@10.28.2",
"devDependencies": {
"@commitlint/cli": "^20.4.2",
"@commitlint/config-conventional": "^20.4.2",
"husky": "^9.1.7",
"lint-staged": "^16.2.7",
"oxfmt": "^0.35.0",
"oxlint": "^1.50.0",
"typescript": "~5.9.3"
}
}
================================================
FILE: packages/react-native-boost/.gitignore
================================================
/dist
/plugin.*
/runtime.*
================================================
FILE: packages/react-native-boost/CHANGELOG.md
================================================
# Changelog
# [1.1.0](https://github.com/kuatsu/react-native-boost/compare/v1.0.0...v1.1.0) (2026-03-18)
### Features
* add `[@boost-force](https://github.com/boost-force)` decorator to enforce optimization ([eb7357c](https://github.com/kuatsu/react-native-boost/commit/eb7357c1fc296aa62658dcc010254c6f1b08e986))
# [1.0.0](https://github.com/kuatsu/react-native-boost/compare/v0.6.2...v1.0.0) (2026-02-27)
### Bug Fixes
* **example:** fix benchmark state machine ([48bb689](https://github.com/kuatsu/react-native-boost/commit/48bb6891d27c6cd7971a45f36d8eda9278b4a54f))
* **example:** fix node_modules being optimized ([9558680](https://github.com/kuatsu/react-native-boost/commit/9558680b6ce0221a367ef64f47cc0ca4dc1bbb67))
* **view:** bail on unknown ancestors by default and add opt-in flag ([#17](https://github.com/kuatsu/react-native-boost/issues/17)) ([bf24fbd](https://github.com/kuatsu/react-native-boost/commit/bf24fbd3d241b0a38d91c5b2ff736c610b7e4132))
### Features
* bail on less props ([1bb7758](https://github.com/kuatsu/react-native-boost/commit/1bb77587185fd6ab5d8d7cb238b5c4dea46553ff))
* **example:** prettier benchmark app ([51e47fd](https://github.com/kuatsu/react-native-boost/commit/51e47fd321507e9d461fd38951cbfaf058ececf2))
* improve logging ([3c9fef4](https://github.com/kuatsu/react-native-boost/commit/3c9fef482c7f20056779cc02bf6e2ea010c59f69))
* skip optimizing Text inside Expo Router Link with `asChild` ([#16](https://github.com/kuatsu/react-native-boost/issues/16)) ([ddc606d](https://github.com/kuatsu/react-native-boost/commit/ddc606d780863b199ab9bf3e6079fb00a366e066))
* **text:** bail less, statically handle userSelect, improve spread prop ([5e93ae5](https://github.com/kuatsu/react-native-boost/commit/5e93ae545d63b9258f27f6831adfa6bba899a124))
## [0.6.2](https://github.com/kuatsu/react-native-boost/compare/v0.6.1...v0.6.2) (2025-06-11)
### Bug Fixes
* fixed react-native 0.79 style flattening ([7b7a5a4](https://github.com/kuatsu/react-native-boost/commit/7b7a5a4def44676382014dfc26f9df1bc989f81e)), closes [#10](https://github.com/kuatsu/react-native-boost/issues/10)
### Reverts
* remove unused package export ([973084e](https://github.com/kuatsu/react-native-boost/commit/973084ee58f9473ffff23a62051d6d99da641456))
## [0.6.1](https://github.com/kuatsu/react-native-boost/compare/v0.6.0...v0.6.1) (2025-06-11)
### Bug Fixes
* fixed type errors in tests ([59e3925](https://github.com/kuatsu/react-native-boost/commit/59e392562331e7e150caad431adc5569f9b7a88d))
# [0.6.0](https://github.com/kuatsu/react-native-boost/compare/v0.5.7...v0.6.0) (2025-06-11)
### Bug Fixes
* fixed bundling issues on web ([efd9933](https://github.com/kuatsu/react-native-boost/commit/efd9933604a6053d5b64cb9faec714c0e3987410))
## [0.5.7](https://github.com/kuatsu/react-native-boost/compare/v0.5.6...v0.5.7) (2025-06-11)
## [0.5.6](https://github.com/kuatsu/react-native-boost/compare/v0.5.5...v0.5.6) (2025-02-26)
## [0.5.5](https://github.com/kuatsu/react-native-boost/compare/v0.5.4...v0.5.5) (2025-02-25)
### Bug Fixes
* don't optimize views with indirect text ancestor (custom component) ([a8d5ced](https://github.com/kuatsu/react-native-boost/commit/a8d5ced7ee4047e9094571257389a2680bd6214e))
## [0.5.4](https://github.com/kuatsu/react-native-boost/compare/v0.5.3...v0.5.4) (2025-02-25)
### Bug Fixes
* fixed optimizing aliased imports ([2eee88b](https://github.com/kuatsu/react-native-boost/commit/2eee88bce014744a13f75ea08d386fba61c5be7c))
## [0.5.3](https://github.com/kuatsu/react-native-boost/compare/v0.5.2...v0.5.3) (2025-02-24)
### Bug Fixes
* fixed react-native-web bundling ([56ab1b3](https://github.com/kuatsu/react-native-boost/commit/56ab1b3b0985f413691edd1ce3de9a02593f7ff8))
## [0.5.2](https://github.com/kuatsu/react-native-boost/compare/v0.5.1...v0.5.2) (2025-02-24)
### Bug Fixes
* allow text string children from variables ([622a201](https://github.com/kuatsu/react-native-boost/commit/622a2011f751f9f28cdda19bf7ea676f537b1fbf))
## [0.5.1](https://github.com/kuatsu/react-native-boost/compare/v0.5.0...v0.5.1) (2025-02-24)
### Bug Fixes
* fixed text style flattening ([83ef501](https://github.com/kuatsu/react-native-boost/commit/83ef501aeaa30c7dc8a59a78e74c7a700fc4b4a3))
# [0.5.0](https://github.com/kuatsu/react-native-boost/compare/v0.4.1...v0.5.0) (2025-02-24)
### Features
* **example:** allow running benchmarks in production ([c21ada0](https://github.com/kuatsu/react-native-boost/commit/c21ada06e1d7ae79fb77512b272da79a15f9fa32))
* optimize components with accessibility props ([d71d027](https://github.com/kuatsu/react-native-boost/commit/d71d027ec613b8baa96e22f155cec317e4c54e13))
## [0.4.1](https://github.com/kuatsu/react-native-boost/compare/v0.4.0...v0.4.1) (2025-02-24)
# [0.4.0](https://github.com/kuatsu/react-native-boost/compare/v0.3.0...v0.4.0) (2025-02-24)
### Bug Fixes
* **docs:** fixed broken link ([a3dde5d](https://github.com/kuatsu/react-native-boost/commit/a3dde5d3c400d525028e18f4cdbcf88fcc373029))
### Features
* added `<View />` optimization support ([46ca834](https://github.com/kuatsu/react-native-boost/commit/46ca834b9d62f5a3abfca7061993f82cdae48deb))
* added `ignores` config option ([7d58a9f](https://github.com/kuatsu/react-native-boost/commit/7d58a9f8db759d3babf747504645b9a4d6ee61bd))
* **docs:** added documentation app w/ styled homepage ([9ce312b](https://github.com/kuatsu/react-native-boost/commit/9ce312b6b6dae38a9ccd3574e72806515a86fa21))
# [0.3.0](https://github.com/kuatsu/react-native-boost/compare/v0.2.0...v0.3.0) (2025-02-24)
### Features
* fix `numberOfLines` prop at build time ([58c2993](https://github.com/kuatsu/react-native-boost/commit/58c299393abaf3a9fcbb2ca933cfa02e4bf08fb3))
### Reverts
* **example:** removed console.log ([4facb6e](https://github.com/kuatsu/react-native-boost/commit/4facb6ed5c773e9b2fef28779d288b43b56612dc))
* removed wrong rollup config ([b4b69c0](https://github.com/kuatsu/react-native-boost/commit/b4b69c01c90a5e11659569a22c5c23805f9df753))
# [0.2.0](https://github.com/kuatsu/react-native-boost/compare/v0.1.0...v0.2.0) (2025-02-23)
### Features
* **example:** added benchmark ([6e56b2a](https://github.com/kuatsu/react-native-boost/commit/6e56b2aaa5c9510d8be0a4898e86382ee637b0c3))
* improved logging & [@boost-ignore](https://github.com/boost-ignore) decorator handling ([6f11cbb](https://github.com/kuatsu/react-native-boost/commit/6f11cbb5b1480b10cd20d2544fa334da1474f44b))
# [0.1.0](https://github.com/kuatsu/react-native-boost/compare/v0.0.5...v0.1.0) (2025-02-23)
### Bug Fixes
* fixed `main` entry ([2727e69](https://github.com/kuatsu/react-native-boost/commit/2727e6965e2d6f7d5fbe308bf5ff5d4c63b8c06d))
### Features
* added ignore decorator comment ([3f7d0dc](https://github.com/kuatsu/react-native-boost/commit/3f7d0dc4a67623fee41f473ca588d6901c5b3e97))
* allow text style prop ([e916da5](https://github.com/kuatsu/react-native-boost/commit/e916da5f6bfee0d5480b660fab70c6e0a67deace))
## [0.0.5](https://github.com/kuatsu/react-native-boost/compare/v0.0.4...v0.0.5) (2025-02-23)
### Features
* minify bundle ([8fd6687](https://github.com/kuatsu/react-native-boost/commit/8fd66878599af4313d428687557bac22a832fd78))
## [0.0.4](https://github.com/kuatsu/react-native-boost/compare/v0.0.3...v0.0.4) (2025-02-23)
### Bug Fixes
* re-add README to npm ([4f39ab5](https://github.com/kuatsu/react-native-boost/commit/4f39ab5162ab412a330aa60f0efa63604f94ec23))
## 0.0.3 (2025-02-23)
### Bug Fixes
* added prettier ([fb73927](https://github.com/kuatsu/react-native-boost/commit/fb73927f2ca613709a2eb181903f52e39903159a))
* **ci:** fixed release workflow ([42d1ce1](https://github.com/kuatsu/react-native-boost/commit/42d1ce1a0691831178a7ef2db78d0258ea4826b3))
* fixed husky hooks ([d0540c9](https://github.com/kuatsu/react-native-boost/commit/d0540c94007e9f13ecd70a22b572084afe58ee0d))
* fixed prettier ([b78e6b4](https://github.com/kuatsu/react-native-boost/commit/b78e6b4c47d0321fa2fa303d5197763aadd4f272))
* fixed tsconfig ([29abcfc](https://github.com/kuatsu/react-native-boost/commit/29abcfcb48b8194d34bdf34af2db4a85fa6a15c5))
* package resolution fix ([bb83508](https://github.com/kuatsu/react-native-boost/commit/bb8350860f2ac952e9fd00702c55357fef013438))
* try to fix lockfile ([16bf4e4](https://github.com/kuatsu/react-native-boost/commit/16bf4e4d9a7bd00c28897ab6ef74377ad307cc00))
### Features
* **example:** added android implementation of benchmarking module ([1c5c4fb](https://github.com/kuatsu/react-native-boost/commit/1c5c4fb2d7165375dffa52f8b6ab0a338e7cdaf1))
* **example:** initialized example app ([19608a9](https://github.com/kuatsu/react-native-boost/commit/19608a94f4e45cf39c13901e472f46181a95115b))
* **example:** ios implementation of benchmarking turbo module ([cd54789](https://github.com/kuatsu/react-native-boost/commit/cd547896b58046a34499b9045c407d4dcf6a5434))
* **example:** scaffolded new turbo module for benchmarks ([187650e](https://github.com/kuatsu/react-native-boost/commit/187650e2d5dc0f4e77520568c4da15c6cd4d602f))
* improved plugin import ([0e97f1e](https://github.com/kuatsu/react-native-boost/commit/0e97f1eea615a2516066fa6a94c9b3685e6576ae))
* initial commit ([3d3c0ad](https://github.com/kuatsu/react-native-boost/commit/3d3c0adcdcc35e3f641312f89292ee72b52142dc))
* optional logging ([c4ad283](https://github.com/kuatsu/react-native-boost/commit/c4ad283db3e7af3f116ba66c90897f2f94362f97))
* try to resolve spread attribute ([2aeb5a1](https://github.com/kuatsu/react-native-boost/commit/2aeb5a1d92f4600f87f6d638ae34db804640ae22))
================================================
FILE: packages/react-native-boost/LICENSE
================================================
MIT License
Copyright (c) Kuatsu App Agency
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: packages/react-native-boost/package.json
================================================
{
"name": "react-native-boost",
"description": "🚀 Boost your React Native app's performance with a single line of code",
"version": "1.1.0",
"main": "dist/index.js",
"module": "dist/esm/index.mjs",
"types": "dist/index.d.ts",
"exports": {
"./package.json": "./package.json",
"./runtime": {
"import": {
"types": "./dist/runtime/index.d.ts",
"default": "./runtime.mjs"
},
"default": "./runtime.js"
},
"./plugin": {
"import": {
"types": "./dist/plugin/index.d.ts",
"default": "./plugin.mjs"
},
"default": "./plugin.js"
}
},
"typesVersions": {
"*": {
"runtime": [
"dist/runtime/index.d.ts"
],
"plugin": [
"dist/plugin/index.d.ts"
]
}
},
"keywords": [
"react-native",
"ios",
"android",
"performance",
"optimization",
"bundle",
"optimize"
],
"scripts": {
"clean": "rm -rf dist",
"build": "pnpm clean && rollup -c",
"build:watch": "rollup -c -w",
"dev": "pnpm build:watch",
"test": "vitest",
"typecheck": "tsc --noEmit",
"release": "release-it",
"prepack": "cp ../../README.md ./README.md",
"postpack": "rm ./README.md"
},
"files": [
"src",
"dist",
"runtime.d.ts",
"runtime.js",
"runtime.mjs",
"plugin.d.ts",
"plugin.js",
"plugin.mjs",
"!**/__tests__",
"!**/__fixtures__",
"!**/__mocks__",
"!**/.*"
],
"repository": {
"type": "git",
"url": "git+https://github.com/kuatsu/react-native-boost.git"
},
"author": "Kuatsu App Agency <hello@kuatsu.de>",
"license": "MIT",
"bugs": {
"url": "https://github.com/kuatsu/react-native-boost/issues"
},
"homepage": "https://github.com/kuatsu/react-native-boost#readme",
"packageManager": "pnpm@10.28.2",
"publishConfig": {
"registry": "https://registry.npmjs.org"
},
"dependencies": {
"@babel/core": "^7.25.0",
"@babel/helper-module-imports": "^7.25.0",
"@babel/helper-plugin-utils": "^7.25.0",
"minimatch": "^10.0.1"
},
"devDependencies": {
"@babel/plugin-syntax-jsx": "^7.25.0",
"@babel/preset-typescript": "^7.25.0",
"@release-it/conventional-changelog": "^10.0.0",
"@rollup/plugin-alias": "^6.0.0",
"@rollup/plugin-node-resolve": "^16.0.0",
"@rollup/plugin-replace": "^6.0.2",
"@rollup/plugin-typescript": "^12.1.2",
"@types/babel__helper-module-imports": "^7.0.0",
"@types/babel__helper-plugin-utils": "^7.0.0",
"@types/node": "^24",
"babel-plugin-tester": "^12.0.0",
"esbuild-node-externals": "^1.18.0",
"react-native": "0.83.2",
"release-it": "^19.2.4",
"rollup": "^4.34.8",
"rollup-plugin-dts": "^6.1.1",
"rollup-plugin-esbuild": "^6.2.0",
"typescript": "~5.9.3",
"vitest": "^4.0.18"
},
"peerDependencies": {
"react": "*",
"react-native": ">=0.83.0"
},
"release-it": {
"git": {
"commitMessage": "chore: release ${version}",
"tagName": "v${version}"
},
"npm": {
"publish": true,
"skipChecks": true,
"versionArgs": [
"--workspaces-update=false"
]
},
"github": {
"release": true
},
"plugins": {
"@release-it/conventional-changelog": {
"preset": {
"name": "angular"
},
"infile": "CHANGELOG.md"
}
}
}
}
================================================
FILE: packages/react-native-boost/rollup.config.mjs
================================================
import path from 'path';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import esbuild from 'rollup-plugin-esbuild';
import dts from 'rollup-plugin-dts';
import fs from 'fs/promises';
const extensions = ['.js', '.ts', '.tsx'];
// Treat all non-relative and non-absolute imports as external
const external = (id) => !id.startsWith('.') && !path.isAbsolute(id);
// Custom plugin to generate entry point files
function generateEntryPoints() {
return {
name: 'generate-entry-points',
writeBundle: async () => {
// Define entry point configurations
const entryPoints = [
{
name: 'runtime',
description: 'runtime',
paths: {
cjs: './dist/runtime/index',
esm: './dist/runtime/esm/index.mjs',
dts: './dist/runtime/index',
},
},
{
name: 'plugin',
description: 'plugin',
paths: {
cjs: './dist/plugin/index',
esm: './dist/plugin/esm/index.mjs',
dts: './dist/plugin/index',
},
},
];
// Helper function to create entry point files
const createEntryPoint = async (config, format) => {
const { name, description, paths } = config;
switch (format) {
case 'cjs':
await fs.writeFile(`${name}.js`, `module.exports = require('${paths.cjs}');\n`);
break;
case 'esm':
await fs.writeFile(`${name}.mjs`, `export * from '${paths.esm}';\n`);
break;
case 'dts':
await fs.writeFile(`${name}.d.ts`, `export * from '${paths.dts}';\n`);
break;
}
};
// Generate all entry points
for (const config of entryPoints) {
await createEntryPoint(config, 'cjs');
await createEntryPoint(config, 'esm');
await createEntryPoint(config, 'dts');
}
},
};
}
const commonPlugins = [
resolve({ extensions }),
replace({
'preventAssignment': true,
'import.meta.env.MODE': JSON.stringify(process.env.NODE_ENV || 'development'),
}),
esbuild({
target: 'es2018',
tsconfig: 'tsconfig.json',
}),
];
// Add the entry point generator to the last build step
const lastBuildPlugins = [...commonPlugins, generateEntryPoints()];
export default [
// Runtime Code Build (CommonJS and ESM)
{
input: 'src/runtime/index.ts',
external,
plugins: commonPlugins,
output: [
{ file: 'dist/runtime/index.js', format: 'cjs', sourcemap: true },
{ file: 'dist/runtime/esm/index.mjs', format: 'esm', sourcemap: true },
],
},
{
input: 'src/runtime/index.web.ts',
external,
plugins: commonPlugins,
output: [
{ file: 'dist/runtime/index.web.js', format: 'cjs', sourcemap: true },
{ file: 'dist/runtime/esm/index.web.mjs', format: 'esm', sourcemap: true },
],
},
// Plugin Code Build (CommonJS and ESM)
{
input: 'src/plugin/index.ts',
external,
plugins: commonPlugins,
output: [
{ file: 'dist/plugin/index.js', format: 'cjs', sourcemap: true },
{ file: 'dist/plugin/esm/index.mjs', format: 'esm', sourcemap: true },
],
},
// Runtime Type Declarations Bundle (creates a single file)
{
input: 'src/runtime/index.ts',
plugins: [dts()],
external,
output: { file: 'dist/runtime/index.d.ts', format: 'esm' },
},
{
input: 'src/runtime/index.web.ts',
plugins: [dts()],
external,
output: { file: 'dist/runtime/index.web.d.ts', format: 'esm' },
},
// Plugin Type Declarations Bundle (creates a single file)
{
input: 'src/plugin/index.ts',
plugins: [dts(), generateEntryPoints()],
external,
output: { file: 'dist/plugin/index.d.ts', format: 'esm' },
},
];
================================================
FILE: packages/react-native-boost/src/plugin/index.ts
================================================
import { declare } from '@babel/helper-plugin-utils';
import { textOptimizer } from './optimizers/text';
import { PluginLogger, PluginOptions } from './types';
import { createLogger } from './utils/logger';
import { viewOptimizer } from './optimizers/view';
import { isIgnoredFile } from './utils/common';
export type { PluginOptimizationOptions, PluginOptions } from './types';
type PluginState = {
opts?: PluginOptions;
__reactNativeBoostLogger?: PluginLogger;
};
export default declare((api) => {
api.assertVersion(7);
return {
name: 'react-native-boost',
visitor: {
JSXOpeningElement(path, state) {
const pluginState = state as PluginState;
const options = (pluginState.opts ?? {}) as PluginOptions;
const logger = getOrCreateLogger(pluginState, options);
if (isIgnoredFile(path, options.ignores ?? [])) return;
if (options.optimizations?.text !== false) textOptimizer(path, logger);
if (options.optimizations?.view !== false) viewOptimizer(path, logger, options);
},
},
};
});
function getOrCreateLogger(state: PluginState, options: PluginOptions): PluginLogger {
if (state.__reactNativeBoostLogger) {
return state.__reactNativeBoostLogger;
}
state.__reactNativeBoostLogger = createLogger({
verbose: options.verbose === true,
silent: options.silent === true,
});
return state.__reactNativeBoostLogger;
}
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/basic/code.js
================================================
import { Text } from 'react-native';
<Text />;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/basic/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'} />;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/complex-example/code.js
================================================
import { Text } from 'react-native';
export default function TextBenchmark(props) {
const optimizedViews = Array.from({ length: props.count }, (_, index) => <Text key={index}>Nice text</Text>);
const unoptimizedViews = Array.from({ length: props.count }, (_, index) => (
// @boost-ignore
<Text key={index}>Nice text</Text>
));
if (props.status === 'pending') return <Text>Pending...</Text>;
return (
<View>
{optimizedViews}
{unoptimizedViews}
</View>
);
}
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/complex-example/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
export default function TextBenchmark(props) {
const optimizedViews = Array.from(
{
length: props.count,
},
(_, index) => (
<_NativeText key={index} allowFontScaling={true} ellipsizeMode={'tail'}>
Nice text
</_NativeText>
)
);
const unoptimizedViews = Array.from(
{
length: props.count,
},
(_, index) => (
// @boost-ignore
<Text key={index}>Nice text</Text>
)
);
if (props.status === 'pending')
return (
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
Pending...
</_NativeText>
);
return (
<View>
{optimizedViews}
{unoptimizedViews}
</View>
);
}
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/default-props/code.js
================================================
import { Text } from 'react-native';
const someFunction = () => ({});
<Text>Hello</Text>;
<Text allowFontScaling={false}>No Scaling</Text>;
const unknownProps = someFunction();
<Text {...unknownProps}>Unknown</Text>;
const partialProps = { color: 'blue', ellipsizeMode: 'clip' };
<Text {...partialProps}>Partial props</Text>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/default-props/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
const someFunction = () => ({});
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
Hello
</_NativeText>;
<_NativeText allowFontScaling={false} ellipsizeMode={'tail'}>
No Scaling
</_NativeText>;
const unknownProps = someFunction();
<Text {...unknownProps}>Unknown</Text>;
const partialProps = {
color: 'blue',
ellipsizeMode: 'clip',
};
<_NativeText {...partialProps} allowFontScaling={true}>
Partial props
</_NativeText>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-alias-as-child/code.js
================================================
import { Text } from 'react-native';
import { Link as RouterLink } from 'expo-router';
<>
<Text>This should be optimized</Text>
<RouterLink asChild>
<Text>This should NOT be optimized due to aliased Link asChild</Text>
</RouterLink>
<RouterLink>
<Text>This should be optimized (aliased Link without asChild)</Text>
</RouterLink>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-alias-as-child/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
import { Link as RouterLink } from 'expo-router';
<>
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
This should be optimized
</_NativeText>
<RouterLink asChild>
<Text>This should NOT be optimized due to aliased Link asChild</Text>
</RouterLink>
<RouterLink>
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
This should be optimized (aliased Link without asChild)
</_NativeText>
</RouterLink>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-as-child/code.js
================================================
import { Text } from 'react-native';
import { Link } from 'expo-router';
<>
<Text>This should be optimized</Text>
<Link asChild>
<Text>This should NOT be optimized due to Link asChild</Text>
</Link>
<Link>
<Text>This should be optimized (Link without asChild)</Text>
</Link>
<Link href="/home" asChild>
<Text>This should NOT be optimized (Link with href and asChild)</Text>
</Link>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-as-child/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
import { Link } from 'expo-router';
<>
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
This should be optimized
</_NativeText>
<Link asChild>
<Text>This should NOT be optimized due to Link asChild</Text>
</Link>
<Link>
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
This should be optimized (Link without asChild)
</_NativeText>
</Link>
<Link href="/home" asChild>
<Text>This should NOT be optimized (Link with href and asChild)</Text>
</Link>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-as-child-false-static/code.js
================================================
import { Text } from 'react-native';
import { Link } from 'expo-router';
<>
<Link asChild={false}>
<Text>This should be optimized because asChild is false</Text>
</Link>
<Link asChild={true}>
<Text>This should NOT be optimized because asChild is true</Text>
</Link>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-as-child-false-static/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
import { Link } from 'expo-router';
<>
<Link asChild={false}>
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
This should be optimized because asChild is false
</_NativeText>
</Link>
<Link asChild={true}>
<Text>This should NOT be optimized because asChild is true</Text>
</Link>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-as-child-nested-view/code.js
================================================
import { Text, View } from 'react-native';
import { Link } from 'expo-router';
<Link asChild href="/home">
<View>
<Text>This should be optimized because View is the direct child</Text>
</View>
</Link>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-as-child-nested-view/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text, View } from 'react-native';
import { Link } from 'expo-router';
<Link asChild href="/home">
<View>
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
This should be optimized because View is the direct child
</_NativeText>
</View>
</Link>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-namespace-as-child/code.js
================================================
import { Text } from 'react-native';
import * as ExpoRouter from 'expo-router';
<>
<ExpoRouter.Link asChild href="/home">
<Text>This should NOT be optimized for namespace Link asChild</Text>
</ExpoRouter.Link>
<ExpoRouter.Link href="/home">
<Text>This should be optimized without asChild</Text>
</ExpoRouter.Link>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-namespace-as-child/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
import * as ExpoRouter from 'expo-router';
<>
<ExpoRouter.Link asChild href="/home">
<Text>This should NOT be optimized for namespace Link asChild</Text>
</ExpoRouter.Link>
<ExpoRouter.Link href="/home">
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
This should be optimized without asChild
</_NativeText>
</ExpoRouter.Link>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/flattens-styles-at-runtime/code.js
================================================
import { Text } from 'react-native';
<Text style={{ color: 'red' }} />;
<Text style={[{ color: 'red' }, { fontSize: 16, userSelect: 'auto' }]} />;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/flattens-styles-at-runtime/output.js
================================================
import { processTextStyle as _processTextStyle, NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
<_NativeText
{..._processTextStyle({
color: 'red',
})}
allowFontScaling={true}
ellipsizeMode={'tail'}
/>;
<_NativeText
{..._processTextStyle([
{
color: 'red',
},
{
fontSize: 16,
},
])}
selectable={true}
allowFontScaling={true}
ellipsizeMode={'tail'}
/>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/force-comment/code.js
================================================
import { Text } from 'react-native';
<>
<Text
onPress={() => {
console.log('pressed');
}}>
Normally skipped due to blacklisted prop
</Text>
{/* @boost-force */}
<Text
onPress={() => {
console.log('pressed');
}}>
Force optimized despite blacklisted prop
</Text>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/force-comment/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
<>
<Text
onPress={() => {
console.log('pressed');
}}>
Normally skipped due to blacklisted prop
</Text>
{/* @boost-force */}
<_NativeText
onPress={() => {
console.log('pressed');
}}
allowFontScaling={true}
ellipsizeMode={'tail'}>
Force optimized despite blacklisted prop
</_NativeText>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/ignore-comment/code.js
================================================
import { Text } from 'react-native';
<>
<Text>Optimize this</Text>
{/* @boost-ignore */}
<Text>But don't optimize this</Text>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/ignore-comment/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
<>
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
Optimize this
</_NativeText>
{/* @boost-ignore */}
<Text>But don't optimize this</Text>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/mixed-children-types/code.js
================================================
import { Text } from 'react-native';
const name = 'John';
<Text>Hello {name}!</Text>;
<Text>
Click here: <SomeComponent />
</Text>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/mixed-children-types/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
const name = 'John';
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
Hello {name}!
</_NativeText>;
<Text>
Click here: <SomeComponent />
</Text>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/nested-in-object-with-ignore-comment/code.js
================================================
import { Text } from 'react-native';
const benchmarks = [
{
title: 'Text',
count: 10_000,
optimizedComponent: <Text>Nice text</Text>,
// @boost-ignore
unoptimizedComponent: <Text>Nice text</Text>,
},
];
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/nested-in-object-with-ignore-comment/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
const benchmarks = [
{
title: 'Text',
count: 10_000,
optimizedComponent: (
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
Nice text
</_NativeText>
),
// @boost-ignore
unoptimizedComponent: <Text>Nice text</Text>,
},
];
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/non-react-native-import/code.js
================================================
import { Text } from 'some-other-package';
import { Text as RNText } from 'react-native';
<Text>Hello, world!</Text>;
<RNText>This is from React Native</RNText>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/non-react-native-import/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'some-other-package';
import { Text as RNText } from 'react-native';
<Text>Hello, world!</Text>;
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
This is from React Native
</_NativeText>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/normalize-accessibility-props/code.js
================================================
import { Text } from 'react-native';
<Text aria-label="test" accessibilityLabel="test" />;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/normalize-accessibility-props/output.js
================================================
import {
processAccessibilityProps as _processAccessibilityProps,
NativeText as _NativeText,
} from 'react-native-boost/runtime';
import { Text } from 'react-native';
<_NativeText
{..._processAccessibilityProps(
Object.assign(
{},
{
'aria-label': 'test',
},
{
accessibilityLabel: 'test',
}
)
)}
allowFontScaling={true}
ellipsizeMode={'tail'}
/>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/normalize-accessibility-props-and-flatten-styles/code.js
================================================
import { Text } from 'react-native';
<Text aria-label="test" accessibilityLabel="test" style={[{ color: 'red' }, { fontSize: 16 }]} />;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/normalize-accessibility-props-and-flatten-styles/output.js
================================================
import {
processAccessibilityProps as _processAccessibilityProps,
processTextStyle as _processTextStyle,
NativeText as _NativeText,
} from 'react-native-boost/runtime';
import { Text } from 'react-native';
<_NativeText
{..._processAccessibilityProps(
Object.assign(
{},
{
'aria-label': 'test',
},
{
accessibilityLabel: 'test',
}
)
)}
{..._processTextStyle([
{
color: 'red',
},
{
fontSize: 16,
},
])}
allowFontScaling={true}
ellipsizeMode={'tail'}
/>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/number-of-lines/code.js
================================================
import { Text } from 'react-native';
<Text numberOfLines={10}>10 lines</Text>;
<Text numberOfLines={-10}>-10 lines</Text>;
<Text numberOfLines={0}>0 lines</Text>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/number-of-lines/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
<_NativeText numberOfLines={10} allowFontScaling={true} ellipsizeMode={'tail'}>
10 lines
</_NativeText>;
<_NativeText numberOfLines={0} allowFontScaling={true} ellipsizeMode={'tail'}>
-10 lines
</_NativeText>;
<_NativeText numberOfLines={0} allowFontScaling={true} ellipsizeMode={'tail'}>
0 lines
</_NativeText>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/pressables/code.js
================================================
import { Text } from 'react-native';
<Text>Hello, world!</Text>;
<Text
onPress={() => {
console.log('pressed');
}}>
Hello, world!
</Text>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/pressables/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
Hello, world!
</_NativeText>;
<Text
onPress={() => {
console.log('pressed');
}}>
Hello, world!
</Text>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/resolvable-spread-props/code.js
================================================
import { Text } from 'react-native';
const props = {
children: 'Hello, world!',
};
<Text {...props} />;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/resolvable-spread-props/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
const props = {
children: 'Hello, world!',
};
<_NativeText {...props} allowFontScaling={true} ellipsizeMode={'tail'} />;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/text-content/code.js
================================================
import { Text } from 'react-native';
<Text>Hello, world!</Text>;
const text = 'Hello again, world!';
<Text>{text}</Text>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/text-content/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
Hello, world!
</_NativeText>;
const text = 'Hello again, world!';
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
{text}
</_NativeText>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/text-content-as-explicit-child-prop/code.js
================================================
import { Text } from 'react-native';
<Text children="Hello, world!" />;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/text-content-as-explicit-child-prop/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
<_NativeText children="Hello, world!" allowFontScaling={true} ellipsizeMode={'tail'} />;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/two-components/code.js
================================================
import { Text } from 'react-native';
<Text />;
<Text></Text>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/two-components/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'} />;
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}></_NativeText>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/unresolvable-spread-props/code.js
================================================
import { Text } from 'react-native';
function MyComponent(props) {
return <Text {...props}>Hello, world!</Text>;
}
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/unresolvable-spread-props/output.js
================================================
import { Text } from 'react-native';
function MyComponent(props) {
return <Text {...props}>Hello, world!</Text>;
}
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/variable-child-no-string/code.js
================================================
import { Text } from 'react-native';
<Text>Hello, world!</Text>;
const test = <Text>Test</Text>;
<Text>{test}</Text>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/variable-child-no-string/output.js
================================================
import { NativeText as _NativeText } from 'react-native-boost/runtime';
import { Text } from 'react-native';
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
Hello, world!
</_NativeText>;
const test = (
<_NativeText allowFontScaling={true} ellipsizeMode={'tail'}>
Test
</_NativeText>
);
<Text>{test}</Text>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/index.test.ts
================================================
import path from 'node:path';
import { pluginTester } from 'babel-plugin-tester';
import { generateTestPlugin } from '../../../utils/generate-test-plugin';
import { formatTestResult } from '../../../utils/format-test-result';
import { textOptimizer } from '..';
pluginTester({
plugin: generateTestPlugin(textOptimizer),
title: 'text',
fixtures: path.resolve(import.meta.dirname, 'fixtures'),
babelOptions: {
plugins: ['@babel/plugin-syntax-jsx'],
},
formatResult: formatTestResult,
});
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/text/index.ts
================================================
import { NodePath, types as t } from '@babel/core';
import { HubFile, Optimizer, PluginLogger } from '../../types';
import PluginError from '../../utils/plugin-error';
import { BailoutCheck, getFirstBailoutReason } from '../../utils/helpers';
import {
addDefaultProperty,
addFileImportHint,
buildPropertiesFromAttributes,
hasAccessibilityProperty,
hasBlacklistedProperty,
isForcedLine,
isIgnoredLine,
isValidJSXComponent,
isReactNativeImport,
replaceWithNativeComponent,
isStringNode,
hasExpoRouterLinkParentWithAsChild,
} from '../../utils/common';
import { RUNTIME_MODULE_NAME } from '../../utils/constants';
import { ACCESSIBILITY_PROPERTIES } from '../../utils/constants';
import { extractStyleAttribute, extractSelectableAndUpdateStyle } from '../../utils/common';
export const textBlacklistedProperties = new Set([
'id',
'nativeID',
'onLongPress',
'onPress',
'onPressIn',
'onPressOut',
'onResponderGrant',
'onResponderMove',
'onResponderRelease',
'onResponderTerminate',
'onResponderTerminationRequest',
'onStartShouldSetResponder',
'pressRetentionOffset',
'suppressHighlighting',
'selectionColor', // TODO: we can use react-native's internal `processColor` to process this at runtime
]);
export const textOptimizer: Optimizer = (path, logger) => {
if (!isValidJSXComponent(path, 'Text')) return;
if (!isReactNativeImport(path, 'Text')) return;
const parent = path.parent as t.JSXElement;
const forced = isForcedLine(path);
const overridableChecks: BailoutCheck[] = [
{
reason: 'contains blacklisted props',
shouldBail: () => hasBlacklistedProperty(path, textBlacklistedProperties),
},
{
reason: 'is a direct child of expo-router Link with asChild',
shouldBail: () => hasExpoRouterLinkParentWithAsChild(path),
},
{
reason: 'contains non-string children',
shouldBail: () => hasInvalidChildren(path, parent),
},
];
if (forced) {
const overriddenReason = getFirstBailoutReason(overridableChecks);
if (overriddenReason) {
logger.forced({ component: 'Text', path, reason: overriddenReason });
}
} else {
const skipReason = getFirstBailoutReason([
{
reason: 'line is marked with @boost-ignore',
shouldBail: () => isIgnoredLine(path),
},
...overridableChecks,
]);
if (skipReason) {
logger.skipped({ component: 'Text', path, reason: skipReason });
return;
}
}
const hub = path.hub as unknown;
const file = typeof hub === 'object' && hub !== null && 'file' in hub ? (hub.file as HubFile) : undefined;
if (!file) {
throw new PluginError('No file found in Babel hub');
}
logger.optimized({
component: 'Text',
path,
});
// Process props
fixNegativeNumberOfLines({ path, logger });
addDefaultProperty(path, 'allowFontScaling', t.booleanLiteral(true));
addDefaultProperty(path, 'ellipsizeMode', t.stringLiteral('tail'));
processProps(path, file);
// Replace the Text component with NativeText
replaceWithNativeComponent(path, parent, file, 'NativeText');
};
/**
* Checks if the Text component has any invalid children or blacklisted properties.
* This function combines the checks for both attribute-based children and JSX children.
*
* @param path - The path to the JSXOpeningElement.
* @param parent - The parent JSX element.
* @returns true if the component has invalid children or blacklisted properties.
*/
function hasInvalidChildren(path: NodePath<t.JSXOpeningElement>, parent: t.JSXElement): boolean {
for (const attribute of path.node.attributes) {
if (t.isJSXSpreadAttribute(attribute)) continue; // Spread attributes are handled in hasBlacklistedProperty
if (
t.isJSXIdentifier(attribute.name) &&
attribute.value &&
// For a "children" attribute, optimization is allowed only if it is a string
attribute.name.name === 'children' &&
!isStringNode(path, attribute.value)
) {
return true;
}
}
// Return true if any child is not a string node
return !parent.children.every((child) => isStringNode(path, child));
}
/**
* Fixes negative numberOfLines values by setting them to 0.
*/
function fixNegativeNumberOfLines({ path, logger }: { path: NodePath<t.JSXOpeningElement>; logger: PluginLogger }) {
for (const attribute of path.node.attributes) {
if (
t.isJSXAttribute(attribute) &&
t.isJSXIdentifier(attribute.name, { name: 'numberOfLines' }) &&
attribute.value &&
t.isJSXExpressionContainer(attribute.value)
) {
let originalValue: number | undefined;
if (t.isNumericLiteral(attribute.value.expression)) {
originalValue = attribute.value.expression.value;
} else if (
t.isUnaryExpression(attribute.value.expression) &&
attribute.value.expression.operator === '-' &&
t.isNumericLiteral(attribute.value.expression.argument)
) {
originalValue = -attribute.value.expression.argument.value;
}
if (originalValue !== undefined && originalValue < 0) {
logger.warning({
component: 'Text',
path,
message: `'numberOfLines' must be a non-negative number, received: ${originalValue}. The value will be set to 0.`,
});
attribute.value.expression = t.numericLiteral(0);
}
}
}
}
/**
* Processes style and accessibility attributes, replacing them with optimized versions.
*/
function processProps(path: NodePath<t.JSXOpeningElement>, file: HubFile) {
// Grab the up-to-date list of attributes
const currentAttributes = [...path.node.attributes];
const { styleExpr, styleAttribute } = extractStyleAttribute(currentAttributes);
const hasA11y = hasAccessibilityProperty(path, currentAttributes);
// ============================================
// 1. Prepare spread attributes (style / a11y)
// ============================================
const spreadAttributes: t.JSXSpreadAttribute[] = [];
// --- Accessibility ---
if (hasA11y) {
const accessibilityAttributes = currentAttributes.filter((attribute) => {
if (!t.isJSXAttribute(attribute)) return false;
return t.isJSXIdentifier(attribute.name) && ACCESSIBILITY_PROPERTIES.has(attribute.name.name as string);
});
const normalizeIdentifier = addFileImportHint({
file,
nameHint: 'processAccessibilityProps',
path,
importName: 'processAccessibilityProps',
moduleName: RUNTIME_MODULE_NAME,
});
const accessibilityObject = buildPropertiesFromAttributes(accessibilityAttributes);
const accessibilityExpr = t.callExpression(t.identifier(normalizeIdentifier.name), [accessibilityObject]);
spreadAttributes.push(t.jsxSpreadAttribute(accessibilityExpr));
}
// --- Style ---
let selectableAttribute: t.JSXAttribute | undefined;
if (styleExpr) {
// Attempt a compile-time extraction of `userSelect`
const selectableValue = extractSelectableAndUpdateStyle(styleExpr);
if (selectableValue != null) {
selectableAttribute = t.jsxAttribute(
t.jsxIdentifier('selectable'),
t.jsxExpressionContainer(t.booleanLiteral(selectableValue))
);
}
const flattenIdentifier = addFileImportHint({
file,
nameHint: 'processTextStyle',
path,
importName: 'processTextStyle',
moduleName: RUNTIME_MODULE_NAME,
});
const flattenedStyleExpr = t.callExpression(t.identifier(flattenIdentifier.name), [styleExpr]);
spreadAttributes.push(t.jsxSpreadAttribute(flattenedStyleExpr));
}
// ============================================
// 2. Collect the remaining (non-processed) attributes
// ============================================
const remainingAttributes: (t.JSXAttribute | t.JSXSpreadAttribute)[] = [];
for (const attribute of currentAttributes) {
// Skip the style attribute (we have replaced it with a spread)
if (styleAttribute && attribute === styleAttribute) continue;
// Skip accessibility attributes if we processed them
if (
hasA11y &&
t.isJSXAttribute(attribute) &&
t.isJSXIdentifier(attribute.name) &&
ACCESSIBILITY_PROPERTIES.has(attribute.name.name as string)
) {
continue;
}
remainingAttributes.push(attribute);
}
path.node.attributes = [...spreadAttributes, selectableAttribute, ...remainingAttributes].filter(
(attribute): attribute is t.JSXAttribute | t.JSXSpreadAttribute => attribute !== undefined
);
}
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/basic/code.js
================================================
import { View } from 'react-native';
<View />;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/basic/output.js
================================================
import { NativeView as _NativeView } from 'react-native-boost/runtime';
import { View } from 'react-native';
<_NativeView />;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/force-comment/code.js
================================================
import { View } from 'react-native';
<>
<View style={{ flex: 1 }}>
<NotOptimized />
</View>
{/* @boost-force */}
<View style={{ flex: 1 }}>
<ForceOptimized />
</View>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/force-comment/output.js
================================================
import { NativeView as _NativeView } from 'react-native-boost/runtime';
import { View } from 'react-native';
<>
<View
style={{
flex: 1,
}}>
<NotOptimized />
</View>
{/* @boost-force */}
<_NativeView
style={{
flex: 1,
}}>
<ForceOptimized />
</_NativeView>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/ignore-comment/code.js
================================================
import { View } from 'react-native';
<>
<View>
<Optimized />
</View>
{/* @boost-ignore */}
<View>
<NotOptimized />
</View>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/ignore-comment/output.js
================================================
import { NativeView as _NativeView } from 'react-native-boost/runtime';
import { View } from 'react-native';
<>
<_NativeView>
<Optimized />
</_NativeView>
{/* @boost-ignore */}
<View>
<NotOptimized />
</View>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/indirect-text-ancestor/code.js
================================================
import { Text, View } from 'react-native';
const Custom = ({ children }) => {
return <Text>{children}</Text>;
};
<>
<View>
<Optimized />
</View>
<Custom>
<View>
<NotOptimized />
</View>
</Custom>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/indirect-text-ancestor/output.js
================================================
import { NativeView as _NativeView } from 'react-native-boost/runtime';
import { Text, View } from 'react-native';
const Custom = ({ children }) => {
return <Text>{children}</Text>;
};
<>
<_NativeView>
<Optimized />
</_NativeView>
<Custom>
<View>
<NotOptimized />
</View>
</Custom>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/react-native-namespace-text-ancestor/code.js
================================================
import * as ReactNative from 'react-native';
import { View } from 'react-native';
<ReactNative.Text>
<View>
<NotOptimized />
</View>
</ReactNative.Text>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/react-native-namespace-text-ancestor/output.js
================================================
import * as ReactNative from 'react-native';
import { View } from 'react-native';
<ReactNative.Text>
<View>
<NotOptimized />
</View>
</ReactNative.Text>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/same-file-safe-ancestor/code.js
================================================
import { View } from 'react-native';
const Wrapper = ({ children }) => <>{children}</>;
<Wrapper>
<View>
<Optimized />
</View>
</Wrapper>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/same-file-safe-ancestor/output.js
================================================
import { NativeView as _NativeView } from 'react-native-boost/runtime';
import { View } from 'react-native';
const Wrapper = ({ children }) => <>{children}</>;
<Wrapper>
<_NativeView>
<Optimized />
</_NativeView>
</Wrapper>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/same-file-unknown-ancestor/code.js
================================================
import { View } from 'react-native';
const Wrapper = ({ children }) => <UnknownContainer>{children}</UnknownContainer>;
<Wrapper>
<View>
<NotOptimized />
</View>
</Wrapper>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/same-file-unknown-ancestor/output.js
================================================
import { View } from 'react-native';
const Wrapper = ({ children }) => <UnknownContainer>{children}</UnknownContainer>;
<Wrapper>
<View>
<NotOptimized />
</View>
</Wrapper>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/text-ancestor/code.js
================================================
import { Text, View } from 'react-native';
<>
<View>
<Optimized />
</View>
<Text>
<View>
<NotOptimized />
</View>
</Text>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/text-ancestor/output.js
================================================
import { NativeView as _NativeView } from 'react-native-boost/runtime';
import { Text, View } from 'react-native';
<>
<_NativeView>
<Optimized />
</_NativeView>
<Text>
<View>
<NotOptimized />
</View>
</Text>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/unknown-imported-ancestor/code.js
================================================
import { View } from 'react-native';
import { ExternalWrapper } from './ExternalWrapper';
<>
<View>
<Optimized />
</View>
<ExternalWrapper>
<View>
<NotOptimized />
</View>
</ExternalWrapper>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/unknown-imported-ancestor/dangerous-output.js
================================================
import { NativeView as _NativeView } from 'react-native-boost/runtime';
import { View } from 'react-native';
import { ExternalWrapper } from './ExternalWrapper';
<>
<_NativeView>
<Optimized />
</_NativeView>
<ExternalWrapper>
<_NativeView>
<NotOptimized />
</_NativeView>
</ExternalWrapper>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/unknown-imported-ancestor/output.js
================================================
import { NativeView as _NativeView } from 'react-native-boost/runtime';
import { View } from 'react-native';
import { ExternalWrapper } from './ExternalWrapper';
<>
<_NativeView>
<Optimized />
</_NativeView>
<ExternalWrapper>
<View>
<NotOptimized />
</View>
</ExternalWrapper>
</>;
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/unresolvable-spread-props/code.js
================================================
import { View } from 'react-native';
function MyComponent(props) {
return (
<View {...props}>
<NotOptimized />
</View>
);
}
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/unresolvable-spread-props/output.js
================================================
import { View } from 'react-native';
function MyComponent(props) {
return (
<View {...props}>
<NotOptimized />
</View>
);
}
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/index.test.ts
================================================
import path from 'node:path';
import { pluginTester } from 'babel-plugin-tester';
import { generateTestPlugin } from '../../../utils/generate-test-plugin';
import { formatTestResult } from '../../../utils/format-test-result';
import { viewOptimizer } from '..';
pluginTester({
plugin: generateTestPlugin(viewOptimizer),
title: 'view',
fixtures: path.resolve(import.meta.dirname, 'fixtures'),
babelOptions: {
plugins: ['@babel/plugin-syntax-jsx'],
},
formatResult: formatTestResult,
});
pluginTester({
plugin: generateTestPlugin(viewOptimizer, {
dangerouslyOptimizeViewWithUnknownAncestors: true,
}),
title: 'view dangerous unknown ancestors',
babelOptions: {
plugins: ['@babel/plugin-syntax-jsx'],
},
formatResult: formatTestResult,
tests: [
{
title: 'optimizes View inside unresolved ancestor when enabled',
fixture: path.resolve(import.meta.dirname, 'fixtures/unknown-imported-ancestor/code.js'),
outputFixture: path.resolve(import.meta.dirname, 'fixtures/unknown-imported-ancestor/dangerous-output.js'),
},
],
});
================================================
FILE: packages/react-native-boost/src/plugin/optimizers/view/index.ts
================================================
import { types as t } from '@babel/core';
import { HubFile, Optimizer } from '../../types';
import PluginError from '../../utils/plugin-error';
import { BailoutCheck, getFirstBailoutReason } from '../../utils/helpers';
import {
hasBlacklistedProperty,
isForcedLine,
isIgnoredLine,
isValidJSXComponent,
isReactNativeImport,
replaceWithNativeComponent,
getViewAncestorClassification,
ViewAncestorClassification,
} from '../../utils/common';
export const viewBlacklistedProperties = new Set([
// TODO: process a11y props at runtime
'accessible',
'accessibilityLabel',
'accessibilityState',
'aria-busy',
'aria-checked',
'aria-disabled',
'aria-expanded',
'aria-label',
'aria-selected',
'id',
'nativeID',
'style', // TODO: process style at runtime
]);
export const viewOptimizer: Optimizer = (path, logger, options) => {
if (!isValidJSXComponent(path, 'View')) return;
if (!isReactNativeImport(path, 'View')) return;
let ancestorClassification: ViewAncestorClassification | undefined;
const getAncestorClassification = () => {
if (!ancestorClassification) {
ancestorClassification = getViewAncestorClassification(path);
}
return ancestorClassification;
};
const forced = isForcedLine(path);
const overridableChecks: BailoutCheck[] = [
{
reason: 'contains blacklisted props',
shouldBail: () => hasBlacklistedProperty(path, viewBlacklistedProperties),
},
{
reason: 'has Text ancestor',
shouldBail: () => getAncestorClassification() === 'text',
},
{
reason: 'has unresolved ancestor and dangerous optimization is disabled',
shouldBail: () =>
getAncestorClassification() === 'unknown' && options?.dangerouslyOptimizeViewWithUnknownAncestors !== true,
},
];
if (forced) {
const overriddenReason = getFirstBailoutReason(overridableChecks);
if (overriddenReason) {
logger.forced({ component: 'View', path, reason: overriddenReason });
}
} else {
const skipReason = getFirstBailoutReason([
{
reason: 'line is marked with @boost-ignore',
shouldBail: () => isIgnoredLine(path),
},
...overridableChecks,
]);
if (skipReason) {
logger.skipped({ component: 'View', path, reason: skipReason });
return;
}
}
const hub = path.hub as unknown;
const file = typeof hub === 'object' && hub !== null && 'file' in hub ? (hub.file as HubFile) : undefined;
if (!file) {
throw new PluginError('No file found in Babel hub');
}
logger.optimized({
component: 'View',
path,
});
const parent = path.parent as t.JSXElement;
replaceWithNativeComponent(path, parent, file, 'NativeView');
};
================================================
FILE: packages/react-native-boost/src/plugin/types/index.ts
================================================
import { NodePath, types as t } from '@babel/core';
export interface PluginOptimizationOptions {
/**
* Whether to optimize the `Text` component.
* @default true
*/
text?: boolean;
/**
* Whether to optimize the `View` component.
* @default true
*/
view?: boolean;
}
export interface PluginOptions {
/**
* Paths to ignore from optimization.
*
* Patterns are resolved from Babel's current working directory.
* In nested monorepo apps, parent segments may be needed, for example `../../node_modules/**`.
* @default []
*/
ignores?: string[];
/**
* Enables verbose logging.
*
* With `silent: false`, optimized components are logged by default.
* When enabled, skipped components and their skip reasons are also logged.
* @default false
*/
verbose?: boolean;
/**
* Disables all plugin logs.
*
* When set to `true`, this overrides `verbose`.
* @default false
*/
silent?: boolean;
/**
* Toggle individual optimizers.
*
* If omitted, all available optimizers are enabled.
*/
optimizations?: PluginOptimizationOptions;
/**
* Opt-in flag that allows View optimization when ancestor components cannot be statically resolved.
*
* This increases optimization coverage, but may introduce behavioral differences
* when unresolved ancestors render React Native `Text` wrappers.
* Prefer targeted ignores first, and enable this only after verifying affected screens.
* @default false
*/
dangerouslyOptimizeViewWithUnknownAncestors?: boolean;
}
export type OptimizableComponent = 'Text' | 'View';
export interface OptimizationLogPayload {
component: OptimizableComponent;
path: NodePath<t.JSXOpeningElement>;
}
export interface SkippedOptimizationLogPayload extends OptimizationLogPayload {
reason: string;
}
export interface WarningLogPayload {
message: string;
component?: OptimizableComponent;
path?: NodePath<t.JSXOpeningElement>;
}
export interface PluginLogger {
optimized: (payload: OptimizationLogPayload) => void;
skipped: (payload: SkippedOptimizationLogPayload) => void;
forced: (payload: SkippedOptimizationLogPayload) => void;
warning: (payload: WarningLogPayload) => void;
}
export type Optimizer = (path: NodePath<t.JSXOpeningElement>, logger: PluginLogger, options?: PluginOptions) => void;
export type HubFile = t.File & {
opts: {
filename: string;
};
__hasImports?: Record<string, t.Identifier>;
__optimized?: boolean;
};
/**
* Options for adding a file import hint.
*/
export interface FileImportOptions {
file: HubFile;
/** The name hint which also acts as the cache key to ensure the import is only added once (e.g. 'processAccessibilityProps') */
nameHint: string;
/** The current Babel NodePath */
path: NodePath;
/**
* The named import string (e.g. 'processAccessibilityProps'). Ignored if importType is "default".
*/
importName: string;
/** The module to import from (e.g. 'react-native-boost/runtime') */
moduleName: string;
/**
* Determines which helper to use:
* - "named" (default) uses addNamed (requires importName)
* - "default" uses addDefault
*/
importType?: 'named' | 'default';
}
================================================
FILE: packages/react-native-boost/src/plugin/utils/__tests__/logger.test.ts
================================================
import { NodePath, types as t } from '@babel/core';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { createLogger } from '../logger';
const originalEnv = {
NO_COLOR: process.env.NO_COLOR,
FORCE_COLOR: process.env.FORCE_COLOR,
CLICOLOR: process.env.CLICOLOR,
CLICOLOR_FORCE: process.env.CLICOLOR_FORCE,
COLORTERM: process.env.COLORTERM,
TERM: process.env.TERM,
};
describe('logger', () => {
afterEach(() => {
restoreEnvVar('NO_COLOR', originalEnv.NO_COLOR);
restoreEnvVar('FORCE_COLOR', originalEnv.FORCE_COLOR);
restoreEnvVar('CLICOLOR', originalEnv.CLICOLOR);
restoreEnvVar('CLICOLOR_FORCE', originalEnv.CLICOLOR_FORCE);
restoreEnvVar('COLORTERM', originalEnv.COLORTERM);
restoreEnvVar('TERM', originalEnv.TERM);
vi.restoreAllMocks();
});
it('logs optimized components by default', () => {
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
const logger = createLogger({
verbose: false,
silent: false,
});
const path = createMockPath('/app/screens/LoginScreen.tsx', 42);
logger.optimized({
component: 'Text',
path,
});
logger.skipped({
component: 'Text',
path,
reason: 'contains non-string children',
});
expect(consoleSpy).toHaveBeenCalledTimes(1);
expect(stripAnsi(String(consoleSpy.mock.calls[0][0]))).toContain(
'Optimized Text in /app/screens/LoginScreen.tsx:42'
);
});
it('logs skipped components and reasons when verbose is enabled', () => {
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
const logger = createLogger({
verbose: true,
silent: false,
});
const path = createMockPath('/app/screens/Settings.tsx', 10);
logger.skipped({
component: 'View',
path,
reason: 'has unresolved ancestor and dangerous optimization is disabled',
});
expect(consoleSpy).toHaveBeenCalledTimes(1);
expect(stripAnsi(String(consoleSpy.mock.calls[0][0]))).toContain(
'Skipped View in /app/screens/Settings.tsx:10 (has unresolved ancestor and dangerous optimization is disabled)'
);
});
it('disables all logs when silent is enabled', () => {
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
const logger = createLogger({
verbose: true,
silent: true,
});
const path = createMockPath('/app/screens/Profile.tsx', 7);
logger.optimized({
component: 'Text',
path,
});
logger.skipped({
component: 'View',
path,
reason: 'line is marked with @boost-ignore',
});
logger.warning({
component: 'Text',
path,
message: 'numberOfLines is invalid',
});
expect(consoleSpy).not.toHaveBeenCalled();
});
it('colorizes log levels when TERM supports colors even without TTY', () => {
delete process.env.NO_COLOR;
delete process.env.FORCE_COLOR;
delete process.env.CLICOLOR;
delete process.env.CLICOLOR_FORCE;
delete process.env.COLORTERM;
process.env.TERM = 'xterm-256color';
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
const logger = createLogger({
verbose: false,
silent: false,
});
const path = createMockPath('/app/screens/Color.tsx', 1);
logger.optimized({
component: 'Text',
path,
});
expect(consoleSpy).toHaveBeenCalledTimes(1);
expect(String(consoleSpy.mock.calls[0][0])).toContain('\u001B[32m[optimized]\u001B[0m');
});
it('does not colorize when NO_COLOR is set', () => {
process.env.NO_COLOR = '1';
process.env.TERM = 'xterm-256color';
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
const logger = createLogger({
verbose: false,
silent: false,
});
const path = createMockPath('/app/screens/NoColor.tsx', 1);
logger.optimized({
component: 'Text',
path,
});
expect(consoleSpy).toHaveBeenCalledTimes(1);
expect(String(consoleSpy.mock.calls[0][0])).not.toContain('\u001B[32m[optimized]\u001B[0m');
});
});
function createMockPath(filename: string, lineNumber: number): NodePath<t.JSXOpeningElement> {
return {
hub: {
file: {
opts: {
filename,
},
},
},
node: {
loc: {
start: {
line: lineNumber,
},
},
},
} as unknown as NodePath<t.JSXOpeningElement>;
}
function stripAnsi(value: string): string {
return value.replace(/\u001B\[[0-9;]*m/g, '');
}
function restoreEnvVar(
key: 'NO_COLOR' | 'FORCE_COLOR' | 'CLICOLOR' | 'CLICOLOR_FORCE' | 'COLORTERM' | 'TERM',
value: string | undefined
): void {
if (value === undefined) {
delete process.env[key];
return;
}
process.env[key] = value;
}
================================================
FILE: packages/react-native-boost/src/plugin/utils/common/attributes.ts
================================================
import { NodePath, types as t } from '@babel/core';
import { ACCESSIBILITY_PROPERTIES } from '../constants';
import { USER_SELECT_STYLE_TO_SELECTABLE_PROP } from '../constants';
/**
* Checks if the JSX element has a blacklisted property.
*
* @param path - The path to the JSXOpeningElement.
* @param blacklist - The set of blacklisted properties.
* @returns true if the JSX element has a blacklisted property.
*/
export const hasBlacklistedProperty = (path: NodePath<t.JSXOpeningElement>, blacklist: Set<string>): boolean => {
return path.node.attributes.some((attribute) => {
// Check direct attributes (e.g., onPress={handler})
if (t.isJSXAttribute(attribute) && t.isJSXIdentifier(attribute.name) && blacklist.has(attribute.name.name)) {
return true;
}
// Check spread attributes (e.g., {...props})
if (t.isJSXSpreadAttribute(attribute)) {
if (t.isIdentifier(attribute.argument)) {
const binding = path.scope.getBinding(attribute.argument.name);
let objectExpression: t.ObjectExpression | undefined;
if (binding) {
// If the binding node is a VariableDeclarator, use its initializer
if (t.isVariableDeclarator(binding.path.node)) {
objectExpression = binding.path.node.init as t.ObjectExpression;
} else if (t.isObjectExpression(binding.path.node)) {
objectExpression = binding.path.node;
}
}
if (objectExpression && t.isObjectExpression(objectExpression)) {
return objectExpression.properties.some((property) => {
if (t.isObjectProperty(property) && t.isIdentifier(property.key)) {
return blacklist.has(property.key.name);
}
return false;
});
}
}
// Bail if we can't resolve the spread attribute
return true;
}
// For other attribute types, assume no blacklisting
return false;
});
};
/**
* Adds a default property to a JSX element if it's not already defined. It avoids adding a default
* if it cannot statically determine whether the property is already set.
*
* @param path - The path to the JSXOpeningElement.
* @param key - The property key.
* @param value - The default value expression.
*/
export const addDefaultProperty = (path: NodePath<t.JSXOpeningElement>, key: string, value: t.Expression) => {
let propertyIsFound = false;
let hasUnresolvableSpread = false;
for (const attribute of path.node.attributes) {
if (t.isJSXAttribute(attribute) && attribute.name.name === key) {
propertyIsFound = true;
break;
}
if (t.isJSXSpreadAttribute(attribute)) {
if (t.isObjectExpression(attribute.argument)) {
const propertyInSpread = attribute.argument.properties.some(
(p) =>
(t.isObjectProperty(p) && t.isIdentifier(p.key) && p.key.name === key) ||
(t.isObjectProperty(p) && t.isStringLiteral(p.key) && p.key.value === key)
);
if (propertyInSpread) {
propertyIsFound = true;
break;
}
} else if (t.isIdentifier(attribute.argument)) {
const binding = path.scope.getBinding(attribute.argument.name);
if (
binding?.path.node &&
t.isVariableDeclarator(binding.path.node) &&
t.isObjectExpression(binding.path.node.init)
) {
const propertyInSpread = binding.path.node.init.properties.some(
(p) =>
(t.isObjectProperty(p) && t.isIdentifier(p.key) && p.key.name === key) ||
(t.isObjectProperty(p) && t.isStringLiteral(p.key) && p.key.value === key)
);
if (propertyInSpread) {
propertyIsFound = true;
break;
}
} else {
hasUnresolvableSpread = true;
break;
}
} else {
hasUnresolvableSpread = true;
break;
}
}
}
if (!propertyIsFound && !hasUnresolvableSpread) {
path.node.attributes.push(t.jsxAttribute(t.jsxIdentifier(key), t.jsxExpressionContainer(value)));
}
};
/**
* Helper that builds an Object.assign expression out of the existing JSX attributes.
* It handles both plain JSXAttributes and spread attributes.
*
* @param attributes - The attributes to build the expression from.
* @returns The Object.assign expression.
*/
export const buildPropertiesFromAttributes = (attributes: (t.JSXAttribute | t.JSXSpreadAttribute)[]): t.Expression => {
const arguments_: t.Expression[] = [];
for (const attribute of attributes) {
if (t.isJSXSpreadAttribute(attribute)) {
arguments_.push(attribute.argument);
} else if (t.isJSXAttribute(attribute)) {
const key = attribute.name.name;
let value: t.Expression;
if (!attribute.value) {
value = t.booleanLiteral(true);
} else if (t.isStringLiteral(attribute.value)) {
value = attribute.value;
} else if (t.isJSXExpressionContainer(attribute.value)) {
value = t.isJSXEmptyExpression(attribute.value.expression)
? t.booleanLiteral(true)
: attribute.value.expression;
} else {
value = t.nullLiteral();
}
// If the key is not a valid JavaScript identifier (e.g. "aria-label"), use a string literal.
const validIdentifierRegex = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
const keyNode =
typeof key === 'string' && validIdentifierRegex.test(key) ? t.identifier(key) : t.stringLiteral(key.toString());
arguments_.push(t.objectExpression([t.objectProperty(keyNode, value)]));
}
}
if (arguments_.length === 0) {
return t.objectExpression([]);
}
return t.callExpression(t.memberExpression(t.identifier('Object'), t.identifier('assign')), [
t.objectExpression([]),
...arguments_,
]);
};
/**
* Checks if the JSX element has an accessibility property.
*
* @param path - The NodePath for the JSXOpeningElement, us
gitextract_wntfy7wt/ ├── .github/ │ ├── FUNDING.yml │ ├── actions/ │ │ └── setup/ │ │ └── action.yml │ └── workflows/ │ ├── release.yml │ ├── stale.yml │ └── test.yml ├── .gitignore ├── .husky/ │ ├── commit-msg │ └── pre-commit ├── .lintstagedrc ├── .npmrc ├── .nvmrc ├── .oxfmtrc.json ├── .oxlintrc.json ├── .zed/ │ └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── apps/ │ ├── docs/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── app/ │ │ │ ├── (home)/ │ │ │ │ ├── layout.tsx │ │ │ │ └── page.tsx │ │ │ ├── api/ │ │ │ │ └── search/ │ │ │ │ └── route.ts │ │ │ ├── docs/ │ │ │ │ ├── [[...slug]]/ │ │ │ │ │ └── page.tsx │ │ │ │ └── layout.tsx │ │ │ ├── global.css │ │ │ ├── layout.tsx │ │ │ ├── llms-full.txt/ │ │ │ │ └── route.ts │ │ │ ├── llms.mdx/ │ │ │ │ └── docs/ │ │ │ │ └── [[...slug]]/ │ │ │ │ └── route.ts │ │ │ ├── llms.txt/ │ │ │ │ └── route.ts │ │ │ └── og/ │ │ │ └── docs/ │ │ │ └── [...slug]/ │ │ │ └── route.tsx │ │ ├── components/ │ │ │ ├── ai/ │ │ │ │ └── page-actions.tsx │ │ │ └── docs/ │ │ │ ├── auto-option-sections.tsx │ │ │ ├── auto-runtime-reference.tsx │ │ │ └── reference-sections.tsx │ │ ├── content/ │ │ │ └── docs/ │ │ │ ├── configuration/ │ │ │ │ ├── boost-decorator.mdx │ │ │ │ ├── configure.mdx │ │ │ │ └── nativewind.mdx │ │ │ ├── index.mdx │ │ │ ├── information/ │ │ │ │ ├── benchmarks.mdx │ │ │ │ ├── how-it-works.mdx │ │ │ │ ├── optimization-coverage.mdx │ │ │ │ └── troubleshooting.mdx │ │ │ ├── meta.json │ │ │ └── runtime-library/ │ │ │ └── index.mdx │ │ ├── lib/ │ │ │ ├── cn.ts │ │ │ ├── layout.shared.tsx │ │ │ ├── source.ts │ │ │ └── type-generator.ts │ │ ├── mdx-components.tsx │ │ ├── next.config.mjs │ │ ├── package.json │ │ ├── postcss.config.mjs │ │ ├── source.config.ts │ │ └── tsconfig.json │ └── example/ │ ├── .gitignore │ ├── app.json │ ├── babel.config.js │ ├── index.ts │ ├── package.json │ ├── src/ │ │ ├── app.tsx │ │ ├── components/ │ │ │ └── measure-component.tsx │ │ ├── screens/ │ │ │ └── home.tsx │ │ ├── types/ │ │ │ └── index.ts │ │ └── utils/ │ │ └── helpers.ts │ └── tsconfig.json ├── commitlint.config.mjs ├── package.json ├── packages/ │ ├── react-native-boost/ │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── package.json │ │ ├── rollup.config.mjs │ │ ├── src/ │ │ │ ├── plugin/ │ │ │ │ ├── index.ts │ │ │ │ ├── optimizers/ │ │ │ │ │ ├── text/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── fixtures/ │ │ │ │ │ │ │ │ ├── basic/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── complex-example/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── default-props/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── expo-router-link-alias-as-child/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── expo-router-link-as-child/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── expo-router-link-as-child-false-static/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── expo-router-link-as-child-nested-view/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── expo-router-link-namespace-as-child/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── flattens-styles-at-runtime/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── force-comment/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── ignore-comment/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── mixed-children-types/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── nested-in-object-with-ignore-comment/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── non-react-native-import/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── normalize-accessibility-props/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── normalize-accessibility-props-and-flatten-styles/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── number-of-lines/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── pressables/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── resolvable-spread-props/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── text-content/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── text-content-as-explicit-child-prop/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── two-components/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ ├── unresolvable-spread-props/ │ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ │ └── variable-child-no-string/ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ └── index.test.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── view/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── fixtures/ │ │ │ │ │ │ │ ├── basic/ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ ├── force-comment/ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ ├── ignore-comment/ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ ├── indirect-text-ancestor/ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ ├── react-native-namespace-text-ancestor/ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ ├── same-file-safe-ancestor/ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ ├── same-file-unknown-ancestor/ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ ├── text-ancestor/ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ ├── unknown-imported-ancestor/ │ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ │ ├── dangerous-output.js │ │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ │ └── unresolvable-spread-props/ │ │ │ │ │ │ │ ├── code.js │ │ │ │ │ │ │ └── output.js │ │ │ │ │ │ └── index.test.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── types/ │ │ │ │ │ └── index.ts │ │ │ │ └── utils/ │ │ │ │ ├── __tests__/ │ │ │ │ │ └── logger.test.ts │ │ │ │ ├── common/ │ │ │ │ │ ├── attributes.ts │ │ │ │ │ ├── base.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── validation.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── format-test-result.ts │ │ │ │ ├── generate-test-plugin.ts │ │ │ │ ├── helpers.ts │ │ │ │ ├── logger.ts │ │ │ │ └── plugin-error.ts │ │ │ └── runtime/ │ │ │ ├── __tests__/ │ │ │ │ ├── index.test.ts │ │ │ │ └── mocks/ │ │ │ │ └── react-native.ts │ │ │ ├── components/ │ │ │ │ ├── native-text.tsx │ │ │ │ └── native-view.tsx │ │ │ ├── index.ts │ │ │ ├── index.web.ts │ │ │ ├── types/ │ │ │ │ ├── index.ts │ │ │ │ └── react-native.d.ts │ │ │ └── utils/ │ │ │ └── constants.ts │ │ ├── tsconfig.build.json │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ └── react-native-time-to-render/ │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── TimeToRender.podspec │ ├── android/ │ │ ├── build.gradle │ │ ├── gradle.properties │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── AndroidManifestNew.xml │ │ └── java/ │ │ └── com/ │ │ └── timetorender/ │ │ ├── MarkerStore.kt │ │ ├── OnMarkerPaintedEvent.kt │ │ ├── TimeToRenderModule.kt │ │ ├── TimeToRenderPackage.kt │ │ ├── TimeToRenderView.kt │ │ └── TimeToRenderViewManager.kt │ ├── ios/ │ │ ├── MarkerPaintComponentView.h │ │ ├── MarkerPaintComponentView.mm │ │ ├── MarkerStore.h │ │ ├── MarkerStore.m │ │ ├── PaintMarkerView.h │ │ ├── PaintMarkerView.m │ │ ├── TimeToRender.h │ │ ├── TimeToRender.mm │ │ ├── TimeToRenderManager.h │ │ └── TimeToRenderManager.m │ ├── package.json │ ├── react-native.config.js │ └── src/ │ ├── NativeTimeToRender.ts │ ├── TimeToRenderNativeComponent.ts │ └── index.tsx ├── pnpm-workspace.yaml └── tsconfig.json
SYMBOL INDEX (166 symbols across 47 files)
FILE: apps/docs/app/(home)/layout.tsx
function Layout (line 4) | function Layout({ children }: LayoutProps<'/'>) {
FILE: apps/docs/app/(home)/page.tsx
function HomePage (line 4) | function HomePage() {
FILE: apps/docs/app/docs/[[...slug]]/page.tsx
type TocInsertion (line 16) | type TocInsertion = {
function getTocInsertions (line 21) | async function getTocInsertions(slug: string): Promise<TocInsertion[]> {
function mergeToc (line 62) | function mergeToc(baseToc: TOCItemType[], insertions: TocInsertion[]): T...
function Page (line 88) | async function Page(props: PageProps<'/docs/[[...slug]]'>) {
function generateStaticParams (line 121) | async function generateStaticParams() {
function generateMetadata (line 125) | async function generateMetadata(props: PageProps<'/docs/[[...slug]]'>): ...
FILE: apps/docs/app/docs/layout.tsx
function Layout (line 5) | function Layout({ children }: LayoutProps<'/docs'>) {
FILE: apps/docs/app/layout.tsx
function Layout (line 19) | function Layout({ children }: LayoutProps<'/'>) {
FILE: apps/docs/app/llms-full.txt/route.ts
function GET (line 5) | async function GET() {
FILE: apps/docs/app/llms.mdx/docs/[[...slug]]/route.ts
function GET (line 6) | async function GET(_req: Request, { params }: RouteContext<'/llms.mdx/do...
function generateStaticParams (line 18) | function generateStaticParams() {
FILE: apps/docs/app/llms.txt/route.ts
function GET (line 5) | async function GET() {
FILE: apps/docs/app/og/docs/[...slug]/route.tsx
function GET (line 8) | async function GET(_req: Request, { params }: RouteContext<'/og/docs/[.....
function generateStaticParams (line 19) | function generateStaticParams() {
FILE: apps/docs/components/ai/page-actions.tsx
function LLMCopyButton (line 11) | function LLMCopyButton({
function ViewOptions (line 59) | function ViewOptions({
FILE: apps/docs/components/docs/auto-option-sections.tsx
type AutoOptionSectionsProps (line 5) | type AutoOptionSectionsProps = Pick<TypeTableProps, 'name' | 'path' | 't...
type AutoOptionSectionsTocProps (line 10) | type AutoOptionSectionsTocProps = Pick<TypeTableProps, 'name' | 'path' |...
function getEntriesCacheKey (line 17) | function getEntriesCacheKey({ path, name, type }: Pick<TypeTableProps, '...
function getOptionEntries (line 21) | async function getOptionEntries(props: Pick<TypeTableProps, 'path' | 'na...
function resolveIdPrefix (line 33) | function resolveIdPrefix(props: Pick<TypeTableProps, 'name' | 'type'>, i...
function readTagValues (line 38) | function readTagValues(entry: DocEntry, tagName: string): string[] {
function AutoOptionSections (line 55) | async function AutoOptionSections({ headingLevel = 3, idPrefix, ...props...
function getAutoOptionSectionsToc (line 111) | async function getAutoOptionSectionsToc({ idPrefix, depth = 3, ...props ...
FILE: apps/docs/components/docs/auto-runtime-reference.tsx
type RuntimeExportKind (line 13) | type RuntimeExportKind = 'function' | 'component' | 'constant' | 'type';
type RuntimeParameter (line 15) | type RuntimeParameter = {
type RuntimeTag (line 21) | type RuntimeTag = {
type RuntimeExportEntry (line 26) | type RuntimeExportEntry = BaseReferenceEntry & {
type AutoRuntimeReferenceProps (line 37) | type AutoRuntimeReferenceProps = {
type SupportedDeclaration (line 41) | type SupportedDeclaration = Extract<
type ParsedDeclarationDocumentation (line 48) | type ParsedDeclarationDocumentation = {
constant GROUP_TITLES (line 55) | const GROUP_TITLES: Record<RuntimeExportKind, string> = {
constant GROUP_ORDER (line 62) | const GROUP_ORDER: RuntimeExportKind[] = ['function', 'component', 'cons...
constant RUNTIME_GROUP_ID_PREFIX (line 63) | const RUNTIME_GROUP_ID_PREFIX = 'runtime-group';
constant RUNTIME_EXPORT_ID_PREFIX (line 64) | const RUNTIME_EXPORT_ID_PREFIX = 'runtime-export';
function resolveRepositoryRoot (line 70) | function resolveRepositoryRoot(startPath: string): string {
function getProject (line 87) | function getProject(tsConfigPath: string): Project {
function isSupportedDeclaration (line 99) | function isSupportedDeclaration(declaration: ExportedDeclarations): decl...
function readTagComment (line 107) | function readTagComment(tag: JSDocTag): string {
function normalizeParameterDescription (line 138) | function normalizeParameterDescription(value: string): string {
function readDeclarationDocumentation (line 142) | function readDeclarationDocumentation(declaration: SupportedDeclaration)...
function readKind (line 187) | function readKind(declaration: SupportedDeclaration): RuntimeExportKind {
function readTypeText (line 204) | function readTypeText(declaration: SupportedDeclaration): string {
function readParameters (line 222) | function readParameters(
function selectDeclaration (line 237) | function selectDeclaration(
function getGroupHeadingId (line 258) | function getGroupHeadingId(group: RuntimeExportKind): string {
function getRuntimeExportEntries (line 262) | function getRuntimeExportEntries(indexFilePath: string): RuntimeExportEn...
function getRuntimeReferenceToc (line 335) | function getRuntimeReferenceToc(path: string): TOCItemType[] {
function AutoRuntimeReference (line 363) | function AutoRuntimeReference({ path }: AutoRuntimeReferenceProps) {
FILE: apps/docs/components/docs/reference-sections.tsx
type HeadingLevel (line 4) | type HeadingLevel = 2 | 3 | 4 | 5 | 6;
type BaseReferenceEntry (line 6) | type BaseReferenceEntry = {
type ReferenceSectionsProps (line 11) | type ReferenceSectionsProps<TEntry extends BaseReferenceEntry> = {
type BuildEntryTocProps (line 19) | type BuildEntryTocProps<TEntry extends BaseReferenceEntry> = {
function toSlug (line 25) | function toSlug(value: string): string {
function getEntryId (line 35) | function getEntryId(idPrefix: string, value: string): string {
function toParagraphs (line 39) | function toParagraphs(value: string): string[] {
function renderInlineCode (line 46) | function renderInlineCode(value: string, keyPrefix: string): ReactNode {
function buildEntryToc (line 58) | function buildEntryToc<TEntry extends BaseReferenceEntry>({
function ReferenceSections (line 70) | function ReferenceSections<TEntry extends BaseReferenceEntry>({
FILE: apps/docs/lib/layout.shared.tsx
function baseOptions (line 9) | function baseOptions(): BaseLayoutProps {
FILE: apps/docs/lib/source.ts
function getPageImage (line 12) | function getPageImage(page: InferPageType<typeof source>) {
function getLLMText (line 21) | async function getLLMText(page: InferPageType<typeof source>) {
FILE: apps/docs/mdx-components.tsx
function getMDXComponents (line 8) | function getMDXComponents(components?: MDXComponents): MDXComponents {
FILE: apps/docs/next.config.mjs
method rewrites (line 8) | async rewrites() {
FILE: apps/example/src/app.tsx
function App (line 5) | function App() {
FILE: apps/example/src/components/measure-component.tsx
type BenchmarkProperties (line 6) | interface BenchmarkProperties extends Benchmark {
function MeasureComponent (line 11) | function MeasureComponent(props: BenchmarkProperties) {
FILE: apps/example/src/screens/home.tsx
function HomeScreen (line 26) | function HomeScreen() {
FILE: apps/example/src/types/index.ts
type Benchmark (line 1) | interface Benchmark {
type BenchmarkStep (line 8) | enum BenchmarkStep {
FILE: packages/react-native-boost/rollup.config.mjs
function generateEntryPoints (line 14) | function generateEntryPoints() {
FILE: packages/react-native-boost/src/plugin/index.ts
type PluginState (line 10) | type PluginState = {
method JSXOpeningElement (line 21) | JSXOpeningElement(path, state) {
function getOrCreateLogger (line 34) | function getOrCreateLogger(state: PluginState, options: PluginOptions): ...
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/complex-example/code.js
function TextBenchmark (line 3) | function TextBenchmark(props) {
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/complex-example/output.js
function TextBenchmark (line 3) | function TextBenchmark(props) {
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/unresolvable-spread-props/code.js
function MyComponent (line 2) | function MyComponent(props) {
FILE: packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/unresolvable-spread-props/output.js
function MyComponent (line 2) | function MyComponent(props) {
FILE: packages/react-native-boost/src/plugin/optimizers/text/index.ts
function hasInvalidChildren (line 114) | function hasInvalidChildren(path: NodePath<t.JSXOpeningElement>, parent:...
function fixNegativeNumberOfLines (line 136) | function fixNegativeNumberOfLines({ path, logger }: { path: NodePath<t.J...
function processProps (line 169) | function processProps(path: NodePath<t.JSXOpeningElement>, file: HubFile) {
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/unresolvable-spread-props/code.js
function MyComponent (line 2) | function MyComponent(props) {
FILE: packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/unresolvable-spread-props/output.js
function MyComponent (line 2) | function MyComponent(props) {
FILE: packages/react-native-boost/src/plugin/types/index.ts
type PluginOptimizationOptions (line 3) | interface PluginOptimizationOptions {
type PluginOptions (line 16) | interface PluginOptions {
type OptimizableComponent (line 57) | type OptimizableComponent = 'Text' | 'View';
type OptimizationLogPayload (line 59) | interface OptimizationLogPayload {
type SkippedOptimizationLogPayload (line 64) | interface SkippedOptimizationLogPayload extends OptimizationLogPayload {
type WarningLogPayload (line 68) | interface WarningLogPayload {
type PluginLogger (line 74) | interface PluginLogger {
type Optimizer (line 81) | type Optimizer = (path: NodePath<t.JSXOpeningElement>, logger: PluginLog...
type HubFile (line 83) | type HubFile = t.File & {
type FileImportOptions (line 94) | interface FileImportOptions {
FILE: packages/react-native-boost/src/plugin/utils/__tests__/logger.test.ts
function createMockPath (line 146) | function createMockPath(filename: string, lineNumber: number): NodePath<...
function stripAnsi (line 165) | function stripAnsi(value: string): string {
function restoreEnvVar (line 169) | function restoreEnvVar(
FILE: packages/react-native-boost/src/plugin/utils/common/attributes.ts
function extractStyleAttribute (line 213) | function extractStyleAttribute(attributes: Array<t.JSXAttribute | t.JSXS...
function extractSelectableAndUpdateStyle (line 243) | function extractSelectableAndUpdateStyle(styleExpr: t.Expression): boole...
FILE: packages/react-native-boost/src/plugin/utils/common/base.ts
function addFileImportHint (line 19) | function addFileImportHint({
FILE: packages/react-native-boost/src/plugin/utils/common/validation.ts
function hasDecoratorComment (line 56) | function hasDecoratorComment(path: NodePath<t.JSXOpeningElement>, decora...
type AncestorClassification (line 180) | type AncestorClassification = 'safe' | 'text' | 'unknown';
type ViewAncestorClassification (line 181) | type ViewAncestorClassification = AncestorClassification;
type ScopeBinding (line 182) | type ScopeBinding = NonNullable<ReturnType<NodePath<t.Node>['scope']['ge...
type AncestorAnalysisContext (line 184) | type AncestorAnalysisContext = {
function classifyViewAncestors (line 194) | function classifyViewAncestors(path: NodePath<t.JSXOpeningElement>): Anc...
function classifyJSXElementAsAncestor (line 218) | function classifyJSXElementAsAncestor(
function classifyJSXIdentifierAsAncestor (line 235) | function classifyJSXIdentifierAsAncestor(
function classifyJSXMemberExpressionAsAncestor (line 248) | function classifyJSXMemberExpressionAsAncestor(
function classifyBindingAsAncestor (line 275) | function classifyBindingAsAncestor(binding: ScopeBinding, context: Ances...
function classifyModuleBindingAsAncestor (line 283) | function classifyModuleBindingAsAncestor(binding: ScopeBinding): Ancesto...
function classifyLocalBindingAsAncestor (line 310) | function classifyLocalBindingAsAncestor(
function analyzeVariableDeclaratorComponent (line 339) | function analyzeVariableDeclaratorComponent(
function analyzeCallWrappedComponent (line 364) | function analyzeCallWrappedComponent(
function isReactMemoOrForwardRefCall (line 391) | function isReactMemoOrForwardRefCall(path: NodePath<t.CallExpression>): ...
function isMemoOrForwardRefName (line 415) | function isMemoOrForwardRefName(name: string): boolean {
function isReactImportBinding (line 419) | function isReactImportBinding(binding: ScopeBinding | undefined): bindin...
function analyzeFunctionComponent (line 426) | function analyzeFunctionComponent(
function analyzeRenderExpression (line 453) | function analyzeRenderExpression(path: NodePath<t.Node>, context: Ancest...
function analyzeJSXChildren (line 503) | function analyzeJSXChildren(
function analyzeIdentifierRenderExpression (line 534) | function analyzeIdentifierRenderExpression(
function isPropsChildrenMemberExpression (line 564) | function isPropsChildrenMemberExpression(expression: t.MemberExpression)...
function mergeAncestorClassification (line 570) | function mergeAncestorClassification(
function getImportSpecifierImportedName (line 579) | function getImportSpecifierImportedName(specifier: t.ImportSpecifier): s...
function isExpoRouterLinkElement (line 615) | function isExpoRouterLinkElement(path: NodePath<t.JSXElement>): boolean {
function hasTruthyAsChildAttribute (line 645) | function hasTruthyAsChildAttribute(attributes: (t.JSXAttribute | t.JSXSp...
function isJSXAttributeValueTruthy (line 659) | function isJSXAttributeValueTruthy(value: t.JSXAttribute['value']): bool...
function getStaticExpressionTruthiness (line 672) | function getStaticExpressionTruthiness(expression: t.Expression | t.JSXE...
FILE: packages/react-native-boost/src/plugin/utils/constants.ts
constant RUNTIME_MODULE_NAME (line 1) | const RUNTIME_MODULE_NAME = 'react-native-boost/runtime';
constant ACCESSIBILITY_PROPERTIES (line 6) | const ACCESSIBILITY_PROPERTIES = new Set([
constant USER_SELECT_STYLE_TO_SELECTABLE_PROP (line 19) | const USER_SELECT_STYLE_TO_SELECTABLE_PROP: Record<string, boolean> = {
FILE: packages/react-native-boost/src/plugin/utils/format-test-result.ts
type RootOxfmtConfig (line 5) | type RootOxfmtConfig = FormatOptions & {
function buildOxfmtOptions (line 23) | function buildOxfmtOptions(config: RootOxfmtConfig): FormatOptions {
FILE: packages/react-native-boost/src/plugin/utils/generate-test-plugin.ts
method JSXOpeningElement (line 17) | JSXOpeningElement(path) {
FILE: packages/react-native-boost/src/plugin/utils/helpers.ts
type BailoutCheck (line 6) | type BailoutCheck = {
FILE: packages/react-native-boost/src/plugin/utils/logger.ts
constant LOG_PREFIX (line 9) | const LOG_PREFIX = '[react-native-boost]';
constant ANSI_RESET (line 11) | const ANSI_RESET = '\u001B[0m';
constant ANSI_GREEN (line 12) | const ANSI_GREEN = '\u001B[32m';
constant ANSI_YELLOW (line 13) | const ANSI_YELLOW = '\u001B[33m';
constant ANSI_MAGENTA (line 14) | const ANSI_MAGENTA = '\u001B[35m';
constant ANSI_RED (line 15) | const ANSI_RED = '\u001B[31m';
method optimized (line 18) | optimized() {}
method skipped (line 19) | skipped() {}
method forced (line 20) | forced() {}
method warning (line 21) | warning() {}
method optimized (line 28) | optimized(payload) {
method skipped (line 31) | skipped(payload) {
method forced (line 35) | forced(payload) {
method warning (line 41) | warning(payload) {
function formatWarningContext (line 49) | function formatWarningContext(payload: WarningLogPayload): string {
type LogLevel (line 63) | type LogLevel = 'optimized' | 'skipped' | 'forced' | 'warning';
function writeLog (line 65) | function writeLog(level: LogLevel, message: string): void {
function formatLevel (line 70) | function formatLevel(level: LogLevel): string {
function colorize (line 86) | function colorize(value: string, colorCode: string): string {
function shouldUseColor (line 91) | function shouldUseColor(): boolean {
function formatPathLocation (line 113) | function formatPathLocation(
FILE: packages/react-native-boost/src/plugin/utils/plugin-error.ts
class PluginError (line 1) | class PluginError extends Error {
method constructor (line 2) | constructor(message: string) {
FILE: packages/react-native-boost/src/runtime/index.ts
function processTextStyle (line 17) | function processTextStyle(style: GenericStyleProp<TextStyle>): Partial<T...
function processAccessibilityProps (line 62) | function processAccessibilityProps(props: Record<string, any>): Record<s...
FILE: packages/react-native-boost/src/runtime/index.web.ts
function processAccessibilityProps (line 9) | function processAccessibilityProps(props: Record<string, any>): Record<s...
FILE: packages/react-native-boost/src/runtime/types/index.ts
type GenericStyleProp (line 6) | type GenericStyleProp<T> = null | void | T | false | '' | ReadonlyArray<...
FILE: packages/react-native-time-to-render/src/NativeTimeToRender.ts
type Spec (line 4) | interface Spec extends TurboModule {
FILE: packages/react-native-time-to-render/src/TimeToRenderNativeComponent.ts
type NativeProps (line 4) | interface NativeProps extends ViewProps {
FILE: packages/react-native-time-to-render/src/index.tsx
function startMarker (line 4) | function startMarker(name: string, time: number): void {
Condensed preview — 202 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (276K chars).
[
{
"path": ".github/FUNDING.yml",
"chars": 17,
"preview": "github: mfkrause\n"
},
{
"path": ".github/actions/setup/action.yml",
"chars": 473,
"preview": "name: Setup\ndescription: Setup Node.js and install dependencies\n\nruns:\n using: composite\n steps:\n - uses: pnpm/acti"
},
{
"path": ".github/workflows/release.yml",
"chars": 5368,
"preview": "name: Release\non:\n workflow_dispatch:\n inputs:\n release_type:\n description: 'Release type (patch, minor,"
},
{
"path": ".github/workflows/stale.yml",
"chars": 1464,
"preview": "name: 'Close stale issues and PRs'\non:\n schedule:\n - cron: '30 1 * * *'\n\njobs:\n stale:\n runs-on: ubuntu-latest\n "
},
{
"path": ".github/workflows/test.yml",
"chars": 966,
"preview": "name: Test & build\non:\n push:\n branches:\n - main\n pull_request:\n branches:\n - main\n\njobs:\n lint:\n "
},
{
"path": ".gitignore",
"chars": 198,
"preview": "*.tgz\npackage-lock.json\nyarn.lock\n\n# OSX\n\n.DS_Store\n\n# VSCode\n.vscode/\njsconfig.json\n\n# node.js\n#\nnode_modules/\nnpm-debu"
},
{
"path": ".husky/commit-msg",
"chars": 38,
"preview": "npx --no-install commitlint --edit $1\n"
},
{
"path": ".husky/pre-commit",
"chars": 29,
"preview": "npx --no-install lint-staged\n"
},
{
"path": ".lintstagedrc",
"chars": 128,
"preview": "{\n \"*.{js,mjs,cjs,jsx,ts,tsx}\": [\"pnpm exec oxlint --fix\", \"pnpm exec oxfmt --write\"],\n \"*.json\": \"pnpm exec oxfmt --w"
},
{
"path": ".npmrc",
"chars": 20,
"preview": "node-linker=hoisted\n"
},
{
"path": ".nvmrc",
"chars": 4,
"preview": "v24\n"
},
{
"path": ".oxfmtrc.json",
"chars": 484,
"preview": "{\n \"$schema\": \"./node_modules/oxfmt/configuration_schema.json\",\n \"printWidth\": 120,\n \"tabWidth\": 2,\n \"useTabs\": fals"
},
{
"path": ".oxlintrc.json",
"chars": 5526,
"preview": "{\n \"$schema\": \"./node_modules/oxlint/configuration_schema.json\",\n \"plugins\": [\"eslint\", \"typescript\", \"unicorn\"],\n \"c"
},
{
"path": ".zed/settings.json",
"chars": 4187,
"preview": "{\n \"lsp\": {\n \"oxlint\": {\n \"initialization_options\": {\n \"settings\": {\n \"configPath\": null,\n "
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 5488,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": "CONTRIBUTING.md",
"chars": 4069,
"preview": "# Contributing\n\nContributions are always welcome, no matter how large or small!\n\nWe want this community to be friendly a"
},
{
"path": "LICENSE",
"chars": 1068,
"preview": "MIT License\n\nCopyright (c) Kuatsu App Agency\nPermission is hereby granted, free of charge, to any person obtaining a cop"
},
{
"path": "README.md",
"chars": 3113,
"preview": "# 🚀 react-native-boost\n\n"
},
{
"path": "apps/docs/.gitignore",
"chars": 239,
"preview": "# deps\n/node_modules\n\n# generated content\n.source\n\n# test & build\n/coverage\n/.next/\n/out/\n/build\n*.tsbuildinfo\n\n# misc\n."
},
{
"path": "apps/docs/README.md",
"chars": 423,
"preview": "# React Native Boost Docs\n\nThis app hosts the Fumadocs site for `react-native-boost`.\n\n## Development\n\n```bash\npnpm --fi"
},
{
"path": "apps/docs/app/(home)/layout.tsx",
"chars": 239,
"preview": "import { HomeLayout } from 'fumadocs-ui/layouts/home';\nimport { baseOptions } from '@/lib/layout.shared';\n\nexport defaul"
},
{
"path": "apps/docs/app/(home)/page.tsx",
"chars": 2801,
"preview": "import Link from 'next/link';\nimport { Rocket, ShieldCheck, Zap } from 'lucide-react';\n\nexport default function HomePage"
},
{
"path": "apps/docs/app/api/search/route.ts",
"chars": 243,
"preview": "import { source } from '@/lib/source';\nimport { createFromSource } from 'fumadocs-core/search/server';\n\nexport const { G"
},
{
"path": "apps/docs/app/docs/[[...slug]]/page.tsx",
"chars": 4122,
"preview": "import { getPageImage, source } from '@/lib/source';\nimport { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fum"
},
{
"path": "apps/docs/app/docs/layout.tsx",
"chars": 332,
"preview": "import { source } from '@/lib/source';\nimport { DocsLayout } from 'fumadocs-ui/layouts/docs';\nimport { baseOptions } fro"
},
{
"path": "apps/docs/app/global.css",
"chars": 324,
"preview": "@import 'tailwindcss';\n@import 'fumadocs-ui/css/neutral.css';\n@import 'fumadocs-ui/css/preset.css';\n\n:root {\n --color-f"
},
{
"path": "apps/docs/app/layout.tsx",
"chars": 792,
"preview": "import { RootProvider } from 'fumadocs-ui/provider/next';\nimport './global.css';\nimport { Inter } from 'next/font/google"
},
{
"path": "apps/docs/app/llms-full.txt/route.ts",
"chars": 305,
"preview": "import { getLLMText, source } from '@/lib/source';\n\nexport const revalidate = false;\n\nexport async function GET() {\n co"
},
{
"path": "apps/docs/app/llms.mdx/docs/[[...slug]]/route.ts",
"chars": 520,
"preview": "import { getLLMText, source } from '@/lib/source';\nimport { notFound } from 'next/navigation';\n\nexport const revalidate "
},
{
"path": "apps/docs/app/llms.txt/route.ts",
"chars": 355,
"preview": "import { source } from '@/lib/source';\n\nexport const revalidate = false;\n\nexport async function GET() {\n const lines: s"
},
{
"path": "apps/docs/app/og/docs/[...slug]/route.tsx",
"chars": 752,
"preview": "import { getPageImage, source } from '@/lib/source';\nimport { notFound } from 'next/navigation';\nimport { ImageResponse "
},
{
"path": "apps/docs/components/ai/page-actions.tsx",
"chars": 10784,
"preview": "'use client';\nimport { useMemo, useState } from 'react';\nimport { Check, ChevronDown, Copy, ExternalLinkIcon, TextIcon }"
},
{
"path": "apps/docs/components/docs/auto-option-sections.tsx",
"chars": 3818,
"preview": "import type { DocEntry, TypeTableProps } from 'fumadocs-typescript';\nimport { typeGenerator } from '../../lib/type-gener"
},
{
"path": "apps/docs/components/docs/auto-runtime-reference.tsx",
"chars": 14059,
"preview": "import { existsSync } from 'node:fs';\nimport nodePath from 'node:path';\nimport type { TOCItemType } from 'fumadocs-core/"
},
{
"path": "apps/docs/components/docs/reference-sections.tsx",
"chars": 2856,
"preview": "import type { TOCItemType } from 'fumadocs-core/toc';\nimport type { ReactNode } from 'react';\n\nexport type HeadingLevel "
},
{
"path": "apps/docs/content/docs/configuration/boost-decorator.mdx",
"chars": 1333,
"preview": "---\ntitle: \"Decorators\"\ndescription: Control optimization on individual JSX elements with @boost-ignore and @boost-force"
},
{
"path": "apps/docs/content/docs/configuration/configure.mdx",
"chars": 1244,
"preview": "---\ntitle: Configure the Babel Plugin\ndescription: Control logging, ignores, and optimization behavior.\n---\n\nThe Babel p"
},
{
"path": "apps/docs/content/docs/configuration/nativewind.mdx",
"chars": 1393,
"preview": "---\ntitle: Nativewind Support\ndescription: Configure cssInterop for optimized components.\n---\n\nIf your app uses Nativewi"
},
{
"path": "apps/docs/content/docs/index.mdx",
"chars": 2932,
"preview": "---\ntitle: Getting Started\ndescription: Install React Native Boost to boost your app's performance with one line of code"
},
{
"path": "apps/docs/content/docs/information/benchmarks.mdx",
"chars": 617,
"preview": "---\ntitle: Benchmarks\ndescription: Benchmark results from the repository example app.\n---\n\nWe run benchmarks with the ex"
},
{
"path": "apps/docs/content/docs/information/how-it-works.mdx",
"chars": 1230,
"preview": "---\ntitle: How It Works\ndescription: Understand why React Native Boost makes your app faster, and how the Babel optimize"
},
{
"path": "apps/docs/content/docs/information/optimization-coverage.mdx",
"chars": 3298,
"preview": "---\ntitle: Optimization Coverage\ndescription: What React Native Boost can optimize today, what it skips, and why.\n---\n\nR"
},
{
"path": "apps/docs/content/docs/information/troubleshooting.mdx",
"chars": 1925,
"preview": "---\ntitle: Troubleshooting\ndescription: Common setup and optimization issues, plus fast ways to diagnose them.\n---\n\n## Q"
},
{
"path": "apps/docs/content/docs/meta.json",
"chars": 487,
"preview": "{\n \"title\": \"React Native Boost\",\n \"description\": \"Documentation for React Native Boost\",\n \"root\": true,\n \"pages\": ["
},
{
"path": "apps/docs/content/docs/runtime-library/index.mdx",
"chars": 660,
"preview": "---\ntitle: Runtime Library\ndescription: Runtime exports used by the Babel plugin and advanced integrations.\n---\n\n`react-"
},
{
"path": "apps/docs/lib/cn.ts",
"chars": 48,
"preview": "export { twMerge as cn } from 'tailwind-merge';\n"
},
{
"path": "apps/docs/lib/layout.shared.tsx",
"chars": 358,
"preview": "import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';\n\nexport const gitConfig = {\n user: 'kuatsu',\n repo:"
},
{
"path": "apps/docs/lib/source.ts",
"chars": 759,
"preview": "import { docs } from 'fumadocs-mdx:collections/server';\nimport { type InferPageType, loader } from 'fumadocs-core/source"
},
{
"path": "apps/docs/lib/type-generator.ts",
"chars": 258,
"preview": "import 'server-only';\nimport { createFileSystemGeneratorCache, createGenerator, type Generator } from 'fumadocs-typescri"
},
{
"path": "apps/docs/mdx-components.tsx",
"chars": 649,
"preview": "import defaultMdxComponents from 'fumadocs-ui/mdx';\nimport { AutoTypeTable } from 'fumadocs-typescript/ui';\nimport type "
},
{
"path": "apps/docs/next.config.mjs",
"chars": 342,
"preview": "import { createMDX } from 'fumadocs-mdx/next';\n\nconst withMDX = createMDX();\n\n/** @type {import('next').NextConfig} */\nc"
},
{
"path": "apps/docs/package.json",
"chars": 909,
"preview": "{\n \"name\": \"react-native-boost-docs\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"scripts\": {\n \"build\": \"next build\""
},
{
"path": "apps/docs/postcss.config.mjs",
"chars": 94,
"preview": "const config = {\n plugins: {\n '@tailwindcss/postcss': {},\n },\n};\n\nexport default config;\n"
},
{
"path": "apps/docs/source.config.ts",
"chars": 531,
"preview": "import { defineConfig, defineDocs } from 'fumadocs-mdx/config';\nimport { metaSchema, pageSchema } from 'fumadocs-core/so"
},
{
"path": "apps/docs/tsconfig.json",
"chars": 743,
"preview": "{\n \"compilerOptions\": {\n \"baseUrl\": \".\",\n \"target\": \"ESNext\",\n \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n \""
},
{
"path": "apps/example/.gitignore",
"chars": 403,
"preview": "# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files\n\n# dependencies\nnode_modules"
},
{
"path": "apps/example/app.json",
"chars": 764,
"preview": "{\n \"expo\": {\n \"name\": \"RN Boost\",\n \"slug\": \"react-native-boost-example\",\n \"version\": \"0.0.1\",\n \"orientation"
},
{
"path": "apps/example/babel.config.js",
"chars": 213,
"preview": "module.exports = function (api) {\n api.cache(true);\n return {\n presets: ['babel-preset-expo'],\n plugins: [['reac"
},
{
"path": "apps/example/index.ts",
"chars": 311,
"preview": "import { registerRootComponent } from 'expo';\n\nimport App from './src/app';\n\n// registerRootComponent calls AppRegistry."
},
{
"path": "apps/example/package.json",
"chars": 792,
"preview": "{\n \"name\": \"react-native-boost-example\",\n \"version\": \"0.0.1\",\n \"main\": \"index.ts\",\n \"scripts\": {\n \"start\": \"expo "
},
{
"path": "apps/example/src/app.tsx",
"chars": 305,
"preview": "import { StatusBar } from 'expo-status-bar';\nimport { SafeAreaProvider } from 'react-native-safe-area-context';\nimport H"
},
{
"path": "apps/example/src/components/measure-component.tsx",
"chars": 1445,
"preview": "import React from 'react';\nimport { TimeToRenderView } from 'react-native-time-to-render';\nimport { Benchmark, Benchmark"
},
{
"path": "apps/example/src/screens/home.tsx",
"chars": 8584,
"preview": "import { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { SafeAreaView, useSafeAreaInsets } from 'react"
},
{
"path": "apps/example/src/types/index.ts",
"chars": 234,
"preview": "export interface Benchmark {\n title: string;\n count: number;\n optimizedComponent: React.ReactNode;\n unoptimizedCompo"
},
{
"path": "apps/example/src/utils/helpers.ts",
"chars": 132,
"preview": "import { BenchmarkStep } from '../types';\n\nexport const getMarkerName = (title: string, step: BenchmarkStep) => `${title"
},
{
"path": "apps/example/tsconfig.json",
"chars": 85,
"preview": "{\n \"extends\": \"expo/tsconfig.base\",\n \"compilerOptions\": {\n \"strict\": true\n }\n}\n"
},
{
"path": "commitlint.config.mjs",
"chars": 65,
"preview": "export default { extends: ['@commitlint/config-conventional'] };\n"
},
{
"path": "package.json",
"chars": 920,
"preview": "{\n \"name\": \"react-native-boost-monorepo\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"scripts\": {\n \"build\": \"pnpm -r"
},
{
"path": "packages/react-native-boost/.gitignore",
"chars": 27,
"preview": "/dist\n/plugin.*\n/runtime.*\n"
},
{
"path": "packages/react-native-boost/CHANGELOG.md",
"chars": 9596,
"preview": "# Changelog\n\n# [1.1.0](https://github.com/kuatsu/react-native-boost/compare/v1.0.0...v1.1.0) (2026-03-18)\n\n\n### Features"
},
{
"path": "packages/react-native-boost/LICENSE",
"chars": 1068,
"preview": "MIT License\n\nCopyright (c) Kuatsu App Agency\nPermission is hereby granted, free of charge, to any person obtaining a cop"
},
{
"path": "packages/react-native-boost/package.json",
"chars": 3395,
"preview": "{\n \"name\": \"react-native-boost\",\n \"description\": \"🚀 Boost your React Native app's performance with a single line of co"
},
{
"path": "packages/react-native-boost/rollup.config.mjs",
"chars": 3825,
"preview": "import path from 'path';\nimport resolve from '@rollup/plugin-node-resolve';\nimport replace from '@rollup/plugin-replace'"
},
{
"path": "packages/react-native-boost/src/plugin/index.ts",
"chars": 1421,
"preview": "import { declare } from '@babel/helper-plugin-utils';\nimport { textOptimizer } from './optimizers/text';\nimport { Plugin"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/basic/code.js",
"chars": 47,
"preview": "import { Text } from 'react-native';\n<Text />;\n"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/basic/output.js",
"chars": 173,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\n<_NativeTex"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/complex-example/code.js",
"chars": 499,
"preview": "import { Text } from 'react-native';\n\nexport default function TextBenchmark(props) {\n const optimizedViews = Array.from"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/complex-example/output.js",
"chars": 806,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\nexport defa"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/default-props/code.js",
"chars": 328,
"preview": "import { Text } from 'react-native';\n\nconst someFunction = () => ({});\n\n<Text>Hello</Text>;\n<Text allowFontScaling={fals"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/default-props/output.js",
"chars": 551,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\nconst someF"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-alias-as-child/code.js",
"chars": 353,
"preview": "import { Text } from 'react-native';\nimport { Link as RouterLink } from 'expo-router';\n\n<>\n <Text>This should be optimi"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-alias-as-child/output.js",
"chars": 566,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\nimport { Li"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-as-child/code.js",
"chars": 414,
"preview": "import { Text } from 'react-native';\nimport { Link } from 'expo-router';\n\n<>\n <Text>This should be optimized</Text>\n <"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-as-child/output.js",
"chars": 627,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\nimport { Li"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-as-child-false-static/code.js",
"chars": 288,
"preview": "import { Text } from 'react-native';\nimport { Link } from 'expo-router';\n\n<>\n <Link asChild={false}>\n <Text>This sho"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-as-child-false-static/output.js",
"chars": 432,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\nimport { Li"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-as-child-nested-view/code.js",
"chars": 211,
"preview": "import { Text, View } from 'react-native';\nimport { Link } from 'expo-router';\n\n<Link asChild href=\"/home\">\n <View>\n "
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-as-child-nested-view/output.js",
"chars": 355,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text, View } from 'react-native';\nimpor"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-namespace-as-child/code.js",
"chars": 336,
"preview": "import { Text } from 'react-native';\nimport * as ExpoRouter from 'expo-router';\n\n<>\n <ExpoRouter.Link asChild href=\"/ho"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/expo-router-link-namespace-as-child/output.js",
"chars": 480,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\nimport * as"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/flattens-styles-at-runtime/code.js",
"chars": 147,
"preview": "import { Text } from 'react-native';\n<Text style={{ color: 'red' }} />;\n<Text style={[{ color: 'red' }, { fontSize: 16, "
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/flattens-styles-at-runtime/output.js",
"chars": 452,
"preview": "import { processTextStyle as _processTextStyle, NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { "
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/force-comment/code.js",
"chars": 312,
"preview": "import { Text } from 'react-native';\n<>\n <Text\n onPress={() => {\n console.log('pressed');\n }}>\n Normally "
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/force-comment/output.js",
"chars": 453,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\n<>\n <Text\n"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/ignore-comment/code.js",
"chars": 137,
"preview": "import { Text } from 'react-native';\n<>\n <Text>Optimize this</Text>\n {/* @boost-ignore */}\n <Text>But don't optimize "
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/ignore-comment/output.js",
"chars": 278,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\n<>\n <_Nati"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/mixed-children-types/code.js",
"chars": 134,
"preview": "import { Text } from 'react-native';\nconst name = 'John';\n<Text>Hello {name}!</Text>;\n<Text>\n Click here: <SomeComponen"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/mixed-children-types/output.js",
"chars": 271,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\nconst name "
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/nested-in-object-with-ignore-comment/code.js",
"chars": 227,
"preview": "import { Text } from 'react-native';\nconst benchmarks = [\n {\n title: 'Text',\n count: 10_000,\n optimizedCompone"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/nested-in-object-with-ignore-comment/output.js",
"chars": 390,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\nconst bench"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/non-react-native-import/code.js",
"chars": 162,
"preview": "import { Text } from 'some-other-package';\nimport { Text as RNText } from 'react-native';\n<Text>Hello, world!</Text>;\n<R"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/non-react-native-import/output.js",
"chars": 295,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'some-other-package';\nimpor"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/normalize-accessibility-props/code.js",
"chars": 91,
"preview": "import { Text } from 'react-native';\n<Text aria-label=\"test\" accessibilityLabel=\"test\" />;\n"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/normalize-accessibility-props/output.js",
"chars": 412,
"preview": "import {\n processAccessibilityProps as _processAccessibilityProps,\n NativeText as _NativeText,\n} from 'react-native-bo"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/normalize-accessibility-props-and-flatten-styles/code.js",
"chars": 136,
"preview": "import { Text } from 'react-native';\n<Text aria-label=\"test\" accessibilityLabel=\"test\" style={[{ color: 'red' }, { fontS"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/normalize-accessibility-props-and-flatten-styles/output.js",
"chars": 551,
"preview": "import {\n processAccessibilityProps as _processAccessibilityProps,\n processTextStyle as _processTextStyle,\n NativeTex"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/number-of-lines/code.js",
"chars": 163,
"preview": "import { Text } from 'react-native';\n<Text numberOfLines={10}>10 lines</Text>;\n<Text numberOfLines={-10}>-10 lines</Text"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/number-of-lines/output.js",
"chars": 428,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\n<_NativeTex"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/pressables/code.js",
"chars": 149,
"preview": "import { Text } from 'react-native';\n<Text>Hello, world!</Text>;\n<Text\n onPress={() => {\n console.log('pressed');\n "
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/pressables/output.js",
"chars": 286,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\n<_NativeTex"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/resolvable-spread-props/code.js",
"chars": 106,
"preview": "import { Text } from 'react-native';\nconst props = {\n children: 'Hello, world!',\n};\n<Text {...props} />;\n"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/resolvable-spread-props/output.js",
"chars": 232,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\nconst props"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/text-content/code.js",
"chars": 122,
"preview": "import { Text } from 'react-native';\n<Text>Hello, world!</Text>;\nconst text = 'Hello again, world!';\n<Text>{text}</Text>"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/text-content/output.js",
"chars": 324,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\n<_NativeTex"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/text-content-as-explicit-child-prop/code.js",
"chars": 72,
"preview": "import { Text } from 'react-native';\n<Text children=\"Hello, world!\" />;\n"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/text-content-as-explicit-child-prop/output.js",
"chars": 198,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\n<_NativeTex"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/two-components/code.js",
"chars": 62,
"preview": "import { Text } from 'react-native';\n<Text />;\n<Text></Text>;\n"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/two-components/output.js",
"chars": 249,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\n<_NativeTex"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/unresolvable-spread-props/code.js",
"chars": 117,
"preview": "import { Text } from 'react-native';\nfunction MyComponent(props) {\n return <Text {...props}>Hello, world!</Text>;\n}\n"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/unresolvable-spread-props/output.js",
"chars": 117,
"preview": "import { Text } from 'react-native';\nfunction MyComponent(props) {\n return <Text {...props}>Hello, world!</Text>;\n}\n"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/variable-child-no-string/code.js",
"chars": 118,
"preview": "import { Text } from 'react-native';\n<Text>Hello, world!</Text>;\nconst test = <Text>Test</Text>;\n<Text>{test}</Text>;\n"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/fixtures/variable-child-no-string/output.js",
"chars": 330,
"preview": "import { NativeText as _NativeText } from 'react-native-boost/runtime';\nimport { Text } from 'react-native';\n<_NativeTex"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/__tests__/index.test.ts",
"chars": 503,
"preview": "import path from 'node:path';\nimport { pluginTester } from 'babel-plugin-tester';\nimport { generateTestPlugin } from '.."
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/text/index.ts",
"chars": 8509,
"preview": "import { NodePath, types as t } from '@babel/core';\nimport { HubFile, Optimizer, PluginLogger } from '../../types';\nimpo"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/basic/code.js",
"chars": 47,
"preview": "import { View } from 'react-native';\n<View />;\n"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/basic/output.js",
"chars": 126,
"preview": "import { NativeView as _NativeView } from 'react-native-boost/runtime';\nimport { View } from 'react-native';\n<_NativeVie"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/force-comment/code.js",
"chars": 190,
"preview": "import { View } from 'react-native';\n<>\n <View style={{ flex: 1 }}>\n <NotOptimized />\n </View>\n {/* @boost-force *"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/force-comment/output.js",
"chars": 306,
"preview": "import { NativeView as _NativeView } from 'react-native-boost/runtime';\nimport { View } from 'react-native';\n<>\n <View\n"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/ignore-comment/code.js",
"chars": 146,
"preview": "import { View } from 'react-native';\n<>\n <View>\n <Optimized />\n </View>\n {/* @boost-ignore */}\n <View>\n <NotOp"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/ignore-comment/output.js",
"chars": 232,
"preview": "import { NativeView as _NativeView } from 'react-native-boost/runtime';\nimport { View } from 'react-native';\n<>\n <_Nati"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/indirect-text-ancestor/code.js",
"chars": 229,
"preview": "import { Text, View } from 'react-native';\nconst Custom = ({ children }) => {\n return <Text>{children}</Text>;\n};\n<>\n "
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/indirect-text-ancestor/output.js",
"chars": 315,
"preview": "import { NativeView as _NativeView } from 'react-native-boost/runtime';\nimport { Text, View } from 'react-native';\nconst"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/react-native-namespace-text-ancestor/code.js",
"chars": 162,
"preview": "import * as ReactNative from 'react-native';\nimport { View } from 'react-native';\n<ReactNative.Text>\n <View>\n <NotOp"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/react-native-namespace-text-ancestor/output.js",
"chars": 162,
"preview": "import * as ReactNative from 'react-native';\nimport { View } from 'react-native';\n<ReactNative.Text>\n <View>\n <NotOp"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/same-file-safe-ancestor/code.js",
"chars": 147,
"preview": "import { View } from 'react-native';\nconst Wrapper = ({ children }) => <>{children}</>;\n<Wrapper>\n <View>\n <Optimize"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/same-file-safe-ancestor/output.js",
"chars": 233,
"preview": "import { NativeView as _NativeView } from 'react-native-boost/runtime';\nimport { View } from 'react-native';\nconst Wrapp"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/same-file-unknown-ancestor/code.js",
"chars": 182,
"preview": "import { View } from 'react-native';\nconst Wrapper = ({ children }) => <UnknownContainer>{children}</UnknownContainer>;\n"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/same-file-unknown-ancestor/output.js",
"chars": 182,
"preview": "import { View } from 'react-native';\nconst Wrapper = ({ children }) => <UnknownContainer>{children}</UnknownContainer>;\n"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/text-ancestor/code.js",
"chars": 153,
"preview": "import { Text, View } from 'react-native';\n<>\n <View>\n <Optimized />\n </View>\n <Text>\n <View>\n <NotOptimiz"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/text-ancestor/output.js",
"chars": 239,
"preview": "import { NativeView as _NativeView } from 'react-native-boost/runtime';\nimport { Text, View } from 'react-native';\n<>\n "
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/unknown-imported-ancestor/code.js",
"chars": 222,
"preview": "import { View } from 'react-native';\nimport { ExternalWrapper } from './ExternalWrapper';\n<>\n <View>\n <Optimized />\n"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/unknown-imported-ancestor/dangerous-output.js",
"chars": 322,
"preview": "import { NativeView as _NativeView } from 'react-native-boost/runtime';\nimport { View } from 'react-native';\nimport { Ex"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/unknown-imported-ancestor/output.js",
"chars": 308,
"preview": "import { NativeView as _NativeView } from 'react-native-boost/runtime';\nimport { View } from 'react-native';\nimport { Ex"
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/unresolvable-spread-props/code.js",
"chars": 142,
"preview": "import { View } from 'react-native';\nfunction MyComponent(props) {\n return (\n <View {...props}>\n <NotOptimized "
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/fixtures/unresolvable-spread-props/output.js",
"chars": 142,
"preview": "import { View } from 'react-native';\nfunction MyComponent(props) {\n return (\n <View {...props}>\n <NotOptimized "
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/__tests__/index.test.ts",
"chars": 1085,
"preview": "import path from 'node:path';\nimport { pluginTester } from 'babel-plugin-tester';\nimport { generateTestPlugin } from '.."
},
{
"path": "packages/react-native-boost/src/plugin/optimizers/view/index.ts",
"chars": 2723,
"preview": "import { types as t } from '@babel/core';\nimport { HubFile, Optimizer } from '../../types';\nimport PluginError from '../"
},
{
"path": "packages/react-native-boost/src/plugin/types/index.ts",
"chars": 3210,
"preview": "import { NodePath, types as t } from '@babel/core';\n\nexport interface PluginOptimizationOptions {\n /**\n * Whether to "
},
{
"path": "packages/react-native-boost/src/plugin/utils/__tests__/logger.test.ts",
"chars": 4828,
"preview": "import { NodePath, types as t } from '@babel/core';\nimport { afterEach, describe, expect, it, vi } from 'vitest';\nimport"
},
{
"path": "packages/react-native-boost/src/plugin/utils/common/attributes.ts",
"chars": 11078,
"preview": "import { NodePath, types as t } from '@babel/core';\nimport { ACCESSIBILITY_PROPERTIES } from '../constants';\nimport { US"
},
{
"path": "packages/react-native-boost/src/plugin/utils/common/base.ts",
"chars": 3053,
"preview": "import { NodePath, types as t } from '@babel/core';\nimport { addDefault, addNamed } from '@babel/helper-module-imports';"
},
{
"path": "packages/react-native-boost/src/plugin/utils/common/index.ts",
"chars": 84,
"preview": "export * from './validation';\nexport * from './attributes';\nexport * from './base';\n"
},
{
"path": "packages/react-native-boost/src/plugin/utils/common/validation.ts",
"chars": 23573,
"preview": "import { NodePath, types as t } from '@babel/core';\nimport { ensureArray } from '../helpers';\nimport { HubFile } from '."
},
{
"path": "packages/react-native-boost/src/plugin/utils/constants.ts",
"chars": 608,
"preview": "export const RUNTIME_MODULE_NAME = 'react-native-boost/runtime';\n\n/**\n * The set of accessibility properties that need t"
},
{
"path": "packages/react-native-boost/src/plugin/utils/format-test-result.ts",
"chars": 836,
"preview": "import type { ResultFormatter } from 'babel-plugin-tester';\nimport { format, type FormatOptions } from 'oxfmt';\nimport o"
},
{
"path": "packages/react-native-boost/src/plugin/utils/generate-test-plugin.ts",
"chars": 550,
"preview": "import { declare } from '@babel/helper-plugin-utils';\nimport { Optimizer, PluginOptions } from '../types';\nimport { crea"
},
{
"path": "packages/react-native-boost/src/plugin/utils/helpers.ts",
"chars": 410,
"preview": "export const ensureArray = <T>(value: T | T[]): T[] => {\n if (Array.isArray(value)) return value;\n return [value];\n};\n"
},
{
"path": "packages/react-native-boost/src/plugin/utils/logger.ts",
"chars": 3532,
"preview": "import {\n HubFile,\n OptimizationLogPayload,\n PluginLogger,\n SkippedOptimizationLogPayload,\n WarningLogPayload,\n} fr"
},
{
"path": "packages/react-native-boost/src/plugin/utils/plugin-error.ts",
"chars": 189,
"preview": "export default class PluginError extends Error {\n constructor(message: string) {\n super(`[react-native-boost] Babel "
},
{
"path": "packages/react-native-boost/src/runtime/__tests__/index.test.ts",
"chars": 5573,
"preview": "import { vi, describe, it, expect } from 'vitest';\nimport {\n processTextStyle,\n processAccessibilityProps,\n userSelec"
},
{
"path": "packages/react-native-boost/src/runtime/__tests__/mocks/react-native.ts",
"chars": 178,
"preview": "export const View = () => 'View';\nexport const Text = () => 'Text';\n\nexport const Platform = {\n OS: 'ios',\n};\n\nexport c"
},
{
"path": "packages/react-native-boost/src/runtime/components/native-text.tsx",
"chars": 761,
"preview": "/* eslint-disable @typescript-eslint/no-require-imports,unicorn/prefer-module */\n\nimport type { ComponentType } from 're"
},
{
"path": "packages/react-native-boost/src/runtime/components/native-view.tsx",
"chars": 761,
"preview": "/* eslint-disable @typescript-eslint/no-require-imports,unicorn/prefer-module */\n\nimport type { ComponentType } from 're"
},
{
"path": "packages/react-native-boost/src/runtime/index.ts",
"chars": 3735,
"preview": "import { TextProps, TextStyle, StyleSheet } from 'react-native';\nimport { GenericStyleProp } from './types';\nimport { us"
},
{
"path": "packages/react-native-boost/src/runtime/index.web.ts",
"chars": 970,
"preview": "// This is a dummy file to ensure that nothing breaks when using the runtime in a web environment.\n\nimport { TextProps, "
},
{
"path": "packages/react-native-boost/src/runtime/types/index.ts",
"chars": 213,
"preview": "/**\n * Recursive style prop shape accepted by runtime style helpers.\n *\n * @template T - Style object type.\n */\nexport t"
},
{
"path": "packages/react-native-boost/src/runtime/types/react-native.d.ts",
"chars": 258,
"preview": "declare module 'react-native/Libraries/Text/TextNativeComponent' {\n export const NativeText: React.ComponentType<TextPr"
},
{
"path": "packages/react-native-boost/src/runtime/utils/constants.ts",
"chars": 415,
"preview": "/**\n * Maps CSS-like `userSelect` values to React Native's `selectable` prop.\n */\nexport const userSelectToSelectableMap"
},
{
"path": "packages/react-native-boost/tsconfig.build.json",
"chars": 235,
"preview": "{\n \"extends\": \"../../tsconfig.json\",\n \"compilerOptions\": {\n \"noEmit\": false,\n \"outDir\": \"./dist\",\n \"emitDecla"
},
{
"path": "packages/react-native-boost/tsconfig.json",
"chars": 155,
"preview": "{\n \"extends\": \"../../tsconfig.json\",\n \"compilerOptions\": {},\n \"include\": [\"src/**/*\"],\n \"exclude\": [\"node_modules\", "
},
{
"path": "packages/react-native-boost/vitest.config.ts",
"chars": 464,
"preview": "import { fileURLToPath } from 'node:url';\nimport { resolve } from 'node:path';\nimport { defineConfig } from 'vitest/conf"
},
{
"path": "packages/react-native-time-to-render/.gitignore",
"chars": 15,
"preview": "/android/build\n"
},
{
"path": "packages/react-native-time-to-render/LICENSE",
"chars": 1068,
"preview": "MIT License\n\nCopyright (c) Kuatsu App Agency\nPermission is hereby granted, free of charge, to any person obtaining a cop"
},
{
"path": "packages/react-native-time-to-render/README.md",
"chars": 390,
"preview": "# Time to Render Benchmarking Module\n\nThis module is used by the React Native Boost example app to create render benchma"
},
{
"path": "packages/react-native-time-to-render/TimeToRender.podspec",
"chars": 1735,
"preview": "require \"json\"\n\npackage = JSON.parse(File.read(File.join(__dir__, \"package.json\")))\nfolly_compiler_flags = '-DFOLLY_NO_C"
},
{
"path": "packages/react-native-time-to-render/android/build.gradle",
"chars": 2517,
"preview": "buildscript {\n ext.getExtOrDefault = {name ->\n return rootProject.ext.has(name) ? rootProject.ext.get(name) : projec"
},
{
"path": "packages/react-native-time-to-render/android/gradle.properties",
"chars": 169,
"preview": "TimeToRender_kotlinVersion=2.0.21\nTimeToRender_minSdkVersion=24\nTimeToRender_targetSdkVersion=34\nTimeToRender_compileSdk"
},
{
"path": "packages/react-native-time-to-render/android/src/main/AndroidManifest.xml",
"chars": 119,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package=\"com.timetorender\">\n</manifest>\n"
},
{
"path": "packages/react-native-time-to-render/android/src/main/AndroidManifestNew.xml",
"chars": 82,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n</manifest>\n"
},
{
"path": "packages/react-native-time-to-render/android/src/main/java/com/timetorender/MarkerStore.kt",
"chars": 674,
"preview": "package com.timetorender\n\nimport java.util.Date\nimport kotlin.collections.mutableMapOf\nimport android.os.SystemClock\n\ncl"
},
{
"path": "packages/react-native-time-to-render/android/src/main/java/com/timetorender/OnMarkerPaintedEvent.kt",
"chars": 794,
"preview": "package com.timetorender\n\nimport com.facebook.react.bridge.Arguments\nimport com.facebook.react.bridge.WritableMap\nimport"
},
{
"path": "packages/react-native-time-to-render/android/src/main/java/com/timetorender/TimeToRenderModule.kt",
"chars": 495,
"preview": "package com.timetorender\n\nimport com.facebook.react.bridge.Promise\nimport com.facebook.react.bridge.ReactApplicationCont"
},
{
"path": "packages/react-native-time-to-render/android/src/main/java/com/timetorender/TimeToRenderPackage.kt",
"chars": 1369,
"preview": "package com.timetorender;\n\nimport com.facebook.react.BaseReactPackage\nimport com.facebook.react.bridge.NativeModule\nimpo"
},
{
"path": "packages/react-native-time-to-render/android/src/main/java/com/timetorender/TimeToRenderView.kt",
"chars": 1552,
"preview": "package com.timetorender\n\nimport android.content.Context\nimport android.graphics.Canvas\nimport android.util.AttributeSet"
},
{
"path": "packages/react-native-time-to-render/android/src/main/java/com/timetorender/TimeToRenderViewManager.kt",
"chars": 1924,
"preview": "package com.timetorender\n\nimport com.facebook.react.bridge.ReactApplicationContext\nimport com.facebook.react.module.anno"
},
{
"path": "packages/react-native-time-to-render/ios/MarkerPaintComponentView.h",
"chars": 177,
"preview": "#import <UIKit/UIKit.h>\n#import <React/RCTViewComponentView.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface MarkerPaintComponent"
},
{
"path": "packages/react-native-time-to-render/ios/MarkerPaintComponentView.mm",
"chars": 1867,
"preview": "#import \"MarkerPaintComponentView.h\"\n#import \"MarkerStore.h\"\n\n#import <React/RCTConversions.h>\n\n#import <react/renderer/"
},
{
"path": "packages/react-native-time-to-render/ios/MarkerStore.h",
"chars": 315,
"preview": "#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface MarkerStore : NSObject\n\n+ (id)mainStore;\n+ (NSTim"
},
{
"path": "packages/react-native-time-to-render/ios/MarkerStore.m",
"chars": 964,
"preview": "#import \"MarkerStore.h\"\n\n@implementation MarkerStore {\n NSMutableDictionary <NSString *, NSNumber*> *_markers;\n}\n\n+ ("
},
{
"path": "packages/react-native-time-to-render/ios/PaintMarkerView.h",
"chars": 259,
"preview": "#import <UIKit/UIKit.h>\n#import <React/RCTView.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface PaintMarkerView : UIView\n\n@proper"
},
{
"path": "packages/react-native-time-to-render/ios/PaintMarkerView.m",
"chars": 905,
"preview": "#import \"PaintMarkerView.h\"\n#import \"MarkerStore.h\"\n\n@implementation PaintMarkerView {\n BOOL _alreadyLogged;\n}\n\n- (void"
},
{
"path": "packages/react-native-time-to-render/ios/TimeToRender.h",
"chars": 118,
"preview": "\n#import \"RNTimeToRenderSpec/RNTimeToRenderSpec.h\"\n\n@interface TimeToRender : NSObject <NativeTimeToRenderSpec>\n\n@end\n"
},
{
"path": "packages/react-native-time-to-render/ios/TimeToRender.mm",
"chars": 451,
"preview": "#import \"TimeToRender.h\"\n#import \"MarkerStore.h\"\n\n@implementation TimeToRender\nRCT_EXPORT_MODULE()\n\n- (void)startMarker:"
},
{
"path": "packages/react-native-time-to-render/ios/TimeToRenderManager.h",
"chars": 87,
"preview": "#import <React/RCTViewManager.h>\n\n@interface TimeToRenderManager : RCTViewManager\n@end\n"
},
{
"path": "packages/react-native-time-to-render/ios/TimeToRenderManager.m",
"chars": 331,
"preview": "#import <React/RCTViewManager.h>\n#import \"TimeToRenderManager.h\"\n#import \"PaintMarkerView.h\"\n\n@implementation TimeToRend"
},
{
"path": "packages/react-native-time-to-render/package.json",
"chars": 480,
"preview": "{\n \"name\": \"react-native-time-to-render\",\n \"version\": \"0.0.1\",\n \"description\": \"Benchmarks the time to render\",\n \"pr"
},
{
"path": "packages/react-native-time-to-render/react-native.config.js",
"chars": 254,
"preview": "/**\n * @type {import('@react-native-community/cli-types').UserDependencyConfig}\n */\nmodule.exports = {\n dependency: {\n "
},
{
"path": "packages/react-native-time-to-render/src/NativeTimeToRender.ts",
"chars": 269,
"preview": "import type { TurboModule } from 'react-native';\nimport { TurboModuleRegistry } from 'react-native';\n\nexport interface S"
},
{
"path": "packages/react-native-time-to-render/src/TimeToRenderNativeComponent.ts",
"chars": 364,
"preview": "import { codegenNativeComponent, type ViewProps } from 'react-native';\nimport { DirectEventHandler, Double } from 'react"
},
{
"path": "packages/react-native-time-to-render/src/index.tsx",
"chars": 240,
"preview": "import TimeToRender from './NativeTimeToRender';\nexport { default as TimeToRenderView } from './TimeToRenderNativeCompon"
}
]
// ... and 2 more files (download for full content)
About this extraction
This page contains the full source code of the kuatsu/react-native-boost GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 202 files (240.4 KB), approximately 71.2k tokens, and a symbol index with 166 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.