├── .nvmrc ├── .watchmanconfig ├── example ├── .watchmanconfig ├── jest.config.js ├── .bundle │ └── config ├── app.json ├── ios │ ├── File.swift │ ├── .xcode.env.local │ ├── FastUrlExample │ │ ├── Images.xcassets │ │ │ ├── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── AppDelegate.h │ │ ├── main.m │ │ ├── AppDelegate.mm │ │ ├── PrivacyInfo.xcprivacy │ │ ├── Info.plist │ │ └── LaunchScreen.storyboard │ ├── FastUrlExample-Bridging-Header.h │ ├── FastUrlExample.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── .xcode.env │ ├── FastUrlExampleTests │ │ ├── Info.plist │ │ └── FastUrlExampleTests.m │ ├── Podfile │ └── FastUrlExample.xcodeproj │ │ └── xcshareddata │ │ └── xcschemes │ │ └── FastUrlExample.xcscheme ├── android │ ├── app │ │ ├── debug.keystore │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── values │ │ │ │ │ │ ├── strings.xml │ │ │ │ │ │ └── styles.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ └── drawable │ │ │ │ │ │ └── rn_edit_text_material.xml │ │ │ │ ├── java │ │ │ │ │ └── com │ │ │ │ │ │ └── fasturlexample │ │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ │ └── MainApplication.kt │ │ │ │ └── AndroidManifest.xml │ │ │ └── debug │ │ │ │ └── AndroidManifest.xml │ │ ├── proguard-rules.pro │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── settings.gradle │ ├── build.gradle │ ├── gradle.properties │ └── gradlew.bat ├── react-native.config.js ├── src │ ├── screens │ │ ├── params.ts │ │ ├── Tests │ │ │ ├── types.ts │ │ │ ├── testList.tsx │ │ │ ├── Tests.tsx │ │ │ └── tests │ │ │ │ └── urlSearchParamsTests.ts │ │ ├── Benchmarks │ │ │ ├── bench.ts │ │ │ └── Benchmarks.tsx │ │ └── Home.tsx │ ├── components │ │ ├── useColorTheme.ts │ │ ├── Text.tsx │ │ ├── Indentator.tsx │ │ ├── Suite.tsx │ │ ├── CorrectResultItem.tsx │ │ ├── IncorrectResultItem.tsx │ │ ├── Button.tsx │ │ └── TestItem.tsx │ ├── App.tsx │ └── testing │ │ ├── MochaRnAdapter.ts │ │ └── MochaSetup.ts ├── index.js ├── Gemfile ├── babel.config.js ├── metro.config.js ├── package.json ├── README.md └── Gemfile.lock ├── example80 ├── .watchmanconfig ├── app.json ├── jest.config.js ├── tsconfig.json ├── .bundle │ └── config ├── .eslintrc.js ├── .prettierrc.js ├── android │ ├── app │ │ ├── debug.keystore │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── values │ │ │ │ │ │ ├── strings.xml │ │ │ │ │ │ └── styles.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ └── drawable │ │ │ │ │ │ └── rn_edit_text_material.xml │ │ │ │ ├── java │ │ │ │ │ └── com │ │ │ │ │ │ └── example2 │ │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ │ └── MainApplication.kt │ │ │ │ └── AndroidManifest.xml │ │ │ └── debug │ │ │ │ └── AndroidManifest.xml │ │ ├── proguard-rules.pro │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── settings.gradle │ ├── build.gradle │ ├── gradle.properties │ └── gradlew.bat ├── ios │ ├── example2 │ │ ├── Images.xcassets │ │ │ ├── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── PrivacyInfo.xcprivacy │ │ ├── AppDelegate.swift │ │ ├── Info.plist │ │ └── LaunchScreen.storyboard │ ├── example2.xcworkspace │ │ └── contents.xcworkspacedata │ ├── .xcode.env │ ├── Podfile │ └── example2.xcodeproj │ │ └── xcshareddata │ │ └── xcschemes │ │ └── example2.xcscheme ├── react-native.config.js ├── src │ ├── screens │ │ ├── params.ts │ │ ├── Tests │ │ │ ├── types.ts │ │ │ ├── testList.tsx │ │ │ ├── Tests.tsx │ │ │ └── tests │ │ │ │ └── urlSearchParamsTests.ts │ │ ├── Benchmarks │ │ │ ├── bench.ts │ │ │ └── Benchmarks.tsx │ │ └── Home.tsx │ ├── components │ │ ├── useColorTheme.ts │ │ ├── Text.tsx │ │ ├── Indentator.tsx │ │ ├── Suite.tsx │ │ ├── CorrectResultItem.tsx │ │ ├── IncorrectResultItem.tsx │ │ ├── Button.tsx │ │ └── TestItem.tsx │ ├── App.tsx │ └── testing │ │ ├── MochaRnAdapter.ts │ │ └── MochaSetup.ts ├── index.js ├── babel.config.js ├── Gemfile ├── .gitignore ├── metro.config.js ├── package.json └── README.md ├── src └── polyfill.ts ├── .gitattributes ├── tsconfig.build.json ├── babel.config.js ├── android ├── src │ ├── main │ │ ├── AndroidManifestNew.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── fasturl │ │ │ ├── FastUrlModuleImpl.java │ │ │ ├── FastUrlBridge.java │ │ │ ├── FastUrlPackage.java │ │ │ └── FastUrlModule.java │ └── oldarch │ │ └── java │ │ └── com │ │ └── fasturl │ │ └── FastUrlModule.java ├── gradle.properties ├── cpp-adapter.cpp ├── CMakeLists.txt └── build.gradle ├── cpp ├── fast-url.h ├── utils.h ├── URLHostObjects.h └── fast-url.cpp ├── lefthook.yml ├── .editorconfig ├── ios ├── FastUrl.h └── FastUrl.mm ├── .yarnrc.yml ├── tsconfig.json ├── turbo.json ├── scripts └── pod-install.cjs ├── .gitignore ├── LICENSE ├── react-native-fast-url.podspec ├── README.md ├── package.json ├── CONTRIBUTING.md └── CODE_OF_CONDUCT.md /.nvmrc: -------------------------------------------------------------------------------- 1 | v18 2 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /example80/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /example/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'react-native', 3 | }; 4 | -------------------------------------------------------------------------------- /example80/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example2", 3 | "displayName": "example2" 4 | } 5 | -------------------------------------------------------------------------------- /example80/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'react-native', 3 | }; 4 | -------------------------------------------------------------------------------- /example80/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@react-native/typescript-config" 3 | } 4 | -------------------------------------------------------------------------------- /src/polyfill.ts: -------------------------------------------------------------------------------- 1 | import { setupPolyfill } from './index'; 2 | 3 | setupPolyfill(); 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | # specific for windows script files 3 | *.bat text eol=crlf -------------------------------------------------------------------------------- /example/.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /example80/.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "FastUrlExample", 3 | "displayName": "FastUrlExample" 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "extends": "./tsconfig", 4 | "exclude": ["example"] 5 | } 6 | -------------------------------------------------------------------------------- /example80/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native', 4 | }; 5 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /example/ios/File.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // FastUrlExample 4 | // 5 | 6 | import Foundation 7 | -------------------------------------------------------------------------------- /example/ios/.xcode.env.local: -------------------------------------------------------------------------------- 1 | export NODE_BINARY=/Users/kuss/Library/Caches/fnm_multishells/46158_1744212788779/bin/node 2 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifestNew.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /example/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example/android/app/debug.keystore -------------------------------------------------------------------------------- /example80/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'avoid', 3 | singleQuote: true, 4 | trailingComma: 'all', 5 | }; 6 | -------------------------------------------------------------------------------- /example80/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example80/android/app/debug.keystore -------------------------------------------------------------------------------- /example80/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | example2 3 | 4 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | FastUrlExample 3 | 4 | -------------------------------------------------------------------------------- /example/ios/FastUrlExample/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /example80/ios/example2/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/ios/FastUrlExample-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | -------------------------------------------------------------------------------- /example/ios/FastUrlExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : RCTAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /example80/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example80/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | FastUrl_kotlinVersion=1.7.0 2 | FastUrl_minSdkVersion=21 3 | FastUrl_targetSdkVersion=31 4 | FastUrl_compileSdkVersion=31 5 | FastUrl_ndkversion=21.4.7075529 6 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example80/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example80/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example80/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example80/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example80/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example80/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example80/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example80/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example80/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example80/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example80/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example80/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example80/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example80/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example80/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example80/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example80/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example80/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example80/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KusStar/react-native-fast-url/HEAD/example80/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /cpp/fast-url.h: -------------------------------------------------------------------------------- 1 | #ifndef FASTURL_H 2 | #define FASTURL_H 3 | 4 | #include "utils.h" 5 | 6 | namespace fasturl { 7 | void install(facebook::jsi::Runtime &runtime); 8 | } 9 | 10 | #endif /* FASTURLPARSER_H */ 11 | -------------------------------------------------------------------------------- /example/react-native.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = { 5 | dependencies: { 6 | [pak.name]: { 7 | root: path.join(__dirname, '..'), 8 | }, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /example/src/screens/params.ts: -------------------------------------------------------------------------------- 1 | export type TestingScreenProps = { 2 | testRegistrators: Array<() => void>; 3 | }; 4 | 5 | export type RootStackParamList = { 6 | Home: undefined; 7 | Benchmarks: undefined; 8 | Tests: TestingScreenProps; 9 | }; 10 | -------------------------------------------------------------------------------- /example80/react-native.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = { 5 | dependencies: { 6 | [pak.name]: { 7 | root: path.join(__dirname, '..'), 8 | }, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /example80/src/screens/params.ts: -------------------------------------------------------------------------------- 1 | export type TestingScreenProps = { 2 | testRegistrators: Array<() => void>; 3 | }; 4 | 5 | export type RootStackParamList = { 6 | Home: undefined; 7 | Benchmarks: undefined; 8 | Tests: TestingScreenProps; 9 | }; 10 | -------------------------------------------------------------------------------- /example/ios/FastUrlExample/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | @autoreleasepool { 8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /example/src/components/useColorTheme.ts: -------------------------------------------------------------------------------- 1 | import { useColorScheme } from 'react-native'; 2 | 3 | import { DefaultTheme, DarkTheme } from '@react-navigation/native'; 4 | 5 | export const useColorTheme = () => { 6 | const isDark = useColorScheme() === 'dark'; 7 | return isDark ? DarkTheme : DefaultTheme; 8 | }; 9 | -------------------------------------------------------------------------------- /example80/ios/example2.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example80/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /example80/src/components/useColorTheme.ts: -------------------------------------------------------------------------------- 1 | import { useColorScheme } from 'react-native'; 2 | 3 | import { DefaultTheme, DarkTheme, type Theme } from '@react-navigation/native'; 4 | 5 | export const useColorTheme = (): Theme => { 6 | const isDark = useColorScheme() === 'dark'; 7 | return isDark ? DarkTheme : DefaultTheme; 8 | }; 9 | -------------------------------------------------------------------------------- /example/ios/FastUrlExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/FastUrlExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/src/screens/Tests/types.ts: -------------------------------------------------------------------------------- 1 | export type RowItemType = { 2 | type: 'correct' | 'incorrect' | 'grouping'; 3 | description: string; 4 | errorMsg?: string; 5 | indentation: number; 6 | key: string; 7 | }; 8 | 9 | export type TestItemType = { 10 | description: string; 11 | registrator: () => void; 12 | value: boolean; 13 | }; 14 | -------------------------------------------------------------------------------- /example80/src/screens/Tests/types.ts: -------------------------------------------------------------------------------- 1 | export type RowItemType = { 2 | type: 'correct' | 'incorrect' | 'grouping'; 3 | description: string; 4 | errorMsg?: string; 5 | indentation: number; 6 | key: string; 7 | }; 8 | 9 | export type TestItemType = { 10 | description: string; 11 | registrator: () => void; 12 | value: boolean; 13 | }; 14 | -------------------------------------------------------------------------------- /lefthook.yml: -------------------------------------------------------------------------------- 1 | pre-commit: 2 | parallel: true 3 | commands: 4 | lint: 5 | glob: "*.{js,ts,jsx,tsx}" 6 | run: npx eslint {staged_files} 7 | types: 8 | glob: "*.{js,ts, jsx, tsx}" 9 | run: npx tsc --noEmit 10 | commit-msg: 11 | parallel: true 12 | commands: 13 | commitlint: 14 | run: npx commitlint --edit 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | indent_style = space 10 | indent_size = 2 11 | 12 | end_of_line = lf 13 | charset = utf-8 14 | trim_trailing_whitespace = true 15 | insert_final_newline = true 16 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /example80/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ios/FastUrl.h: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | #import "fast-url.h" 3 | #endif 4 | 5 | #ifdef RCT_NEW_ARCH_ENABLED 6 | #import "RNFastUrlSpec.h" 7 | 8 | @interface FastUrl : NSObject 9 | #else 10 | #import 11 | #import 12 | 13 | @interface FastUrl : RCTEventEmitter 14 | #endif 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /example80/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") } 2 | plugins { id("com.facebook.react.settings") } 3 | extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() } 4 | rootProject.name = 'example2' 5 | include ':app' 6 | includeBuild('../node_modules/@react-native/gradle-plugin') 7 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") } 2 | plugins { id("com.facebook.react.settings") } 3 | extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() } 4 | rootProject.name = 'FastUrlExample' 5 | include ':app' 6 | includeBuild('../node_modules/@react-native/gradle-plugin') 7 | -------------------------------------------------------------------------------- /example80/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | nmHoistingLimits: workspaces 3 | 4 | plugins: 5 | - path: scripts/pod-install.cjs 6 | - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs 7 | spec: "@yarnpkg/plugin-interactive-tools" 8 | - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs 9 | spec: "@yarnpkg/plugin-workspace-tools" 10 | 11 | yarnPath: .yarn/releases/yarn-3.6.1.cjs 12 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /android/src/main/java/com/fasturl/FastUrlModuleImpl.java: -------------------------------------------------------------------------------- 1 | package com.fasturl; 2 | 3 | public class FastUrlModuleImpl { 4 | public static final String NAME = "FastUrl"; 5 | 6 | public static boolean install() { 7 | try { 8 | System.loadLibrary("fast-url"); 9 | return true; 10 | } catch (Exception exception) { 11 | return false; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | import { AppRegistry } from 'react-native'; 2 | import App from './src/App'; 3 | import { name as appName } from './app.json'; 4 | import { Buffer } from '@craftzdog/react-native-buffer'; 5 | 6 | global.process = { 7 | cwd: () => 'sxsx', 8 | env: { NODE_ENV: 'production' }, 9 | }; 10 | global.location = {}; 11 | global.Buffer = Buffer; 12 | 13 | AppRegistry.registerComponent(appName, () => App); 14 | -------------------------------------------------------------------------------- /example/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby ">= 2.6.10" 5 | 6 | # Exclude problematic versions of cocoapods and activesupport that causes build failures. 7 | gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' 8 | gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' 9 | gem 'xcodeproj', '< 1.26.0' 10 | gem 'concurrent-ruby', '< 1.3.4' 11 | -------------------------------------------------------------------------------- /example80/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import { AppRegistry } from 'react-native'; 6 | import App from './src/App'; 7 | import { name as appName } from './app.json'; 8 | import { Buffer } from '@craftzdog/react-native-buffer'; 9 | 10 | global.process = { 11 | cwd: () => 'sxsx', 12 | env: { NODE_ENV: 'production' }, 13 | }; 14 | global.location = {}; 15 | global.Buffer = Buffer; 16 | 17 | AppRegistry.registerComponent(appName, () => App); 18 | -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = { 5 | presets: ['module:@react-native/babel-preset'], 6 | plugins: [ 7 | [ 8 | 'module-resolver', 9 | { 10 | extensions: ['.tsx', '.ts', '.js', '.json'], 11 | alias: { 12 | [pak.name]: path.join(__dirname, '..', pak.source), 13 | }, 14 | }, 15 | ], 16 | '@babel/plugin-transform-class-static-block', 17 | ], 18 | }; 19 | -------------------------------------------------------------------------------- /example/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /example80/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /example80/babel.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = { 5 | presets: ['module:@react-native/babel-preset'], 6 | plugins: [ 7 | [ 8 | 'module-resolver', 9 | { 10 | extensions: ['.tsx', '.ts', '.js', '.json'], 11 | alias: { 12 | [pak.name]: path.join(__dirname, '..', pak.source), 13 | }, 14 | }, 15 | ], 16 | '@babel/plugin-transform-class-static-block', 17 | ], 18 | }; 19 | -------------------------------------------------------------------------------- /example/src/screens/Tests/testList.tsx: -------------------------------------------------------------------------------- 1 | import { registerURLSearchParamsTests } from './tests/urlSearchParamsTests'; 2 | import { registerURLTests } from './tests/urlTests'; 3 | import { type TestItemType } from './types'; 4 | 5 | export const TEST_LIST: Array = [ 6 | { 7 | description: 'URL tests', 8 | value: false, 9 | registrator: registerURLTests, 10 | }, 11 | { 12 | description: 'URLSearchParams tests', 13 | value: false, 14 | registrator: registerURLSearchParamsTests, 15 | }, 16 | ]; 17 | -------------------------------------------------------------------------------- /example80/src/screens/Tests/testList.tsx: -------------------------------------------------------------------------------- 1 | import { registerURLSearchParamsTests } from './tests/urlSearchParamsTests'; 2 | import { registerURLTests } from './tests/urlTests'; 3 | import { type TestItemType } from './types'; 4 | 5 | export const TEST_LIST: Array = [ 6 | { 7 | description: 'URL tests', 8 | value: false, 9 | registrator: registerURLTests, 10 | }, 11 | { 12 | description: 'URLSearchParams tests', 13 | value: false, 14 | registrator: registerURLSearchParamsTests, 15 | }, 16 | ]; 17 | -------------------------------------------------------------------------------- /example80/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /example/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | export RCT_NEW_ARCH_ENABLED=true -------------------------------------------------------------------------------- /example80/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby ">= 2.6.10" 5 | 6 | # Exclude problematic versions of cocoapods and activesupport that causes build failures. 7 | gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' 8 | gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' 9 | gem 'xcodeproj', '< 1.26.0' 10 | gem 'concurrent-ruby', '< 1.3.4' 11 | 12 | # Ruby 3.4.0 has removed some libraries from the standard library. 13 | gem 'bigdecimal' 14 | gem 'logger' 15 | gem 'benchmark' 16 | gem 'mutex_m' 17 | -------------------------------------------------------------------------------- /cpp/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef FASTURL_UTILS_H 2 | #define FASTURL_UTILS_H 3 | 4 | #include 5 | 6 | #include "ada.h" 7 | 8 | #define HOST_FN(rt, name, functionArgCount, hostFunctionBody) \ 9 | jsi::Function::createFromHostFunction( \ 10 | rt, jsi::PropNameID::forAscii(rt, name), (functionArgCount), \ 11 | [=](jsi::Runtime & rt, const jsi::Value &thisValue, \ 12 | const jsi::Value *args, \ 13 | size_t count) -> jsi::Value hostFunctionBody) 14 | 15 | #define HOST_STR(str) jsi::String::createFromAscii(rt, str) 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /example80/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | buildToolsVersion = "35.0.0" 4 | minSdkVersion = 24 5 | compileSdkVersion = 35 6 | targetSdkVersion = 35 7 | ndkVersion = "27.1.12297006" 8 | kotlinVersion = "2.1.20" 9 | } 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle") 16 | classpath("com.facebook.react:react-native-gradle-plugin") 17 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") 18 | } 19 | } 20 | 21 | apply plugin: "com.facebook.react.rootproject" 22 | -------------------------------------------------------------------------------- /android/src/main/java/com/fasturl/FastUrlBridge.java: -------------------------------------------------------------------------------- 1 | package com.fasturl; 2 | 3 | import android.util.Log; 4 | 5 | import com.facebook.react.bridge.ReactApplicationContext; 6 | import com.facebook.react.bridge.ReactContext; 7 | import com.facebook.react.turbomodule.core.CallInvokerHolderImpl; 8 | 9 | public class FastUrlBridge { 10 | private native void installNativeJsi(long jsContextNativePointer); 11 | 12 | public static final FastUrlBridge instance = new FastUrlBridge(); 13 | 14 | public void install(ReactContext context) { 15 | long jsContextPointer = context.getJavaScriptContextHolder().get(); 16 | installNativeJsi(jsContextPointer); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /example/src/components/Text.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { StyleSheet, Text as TextNative, type TextStyle } from 'react-native'; 3 | 4 | type Props = { 5 | children: React.ReactNode; 6 | style?: TextStyle | TextStyle[]; 7 | }; 8 | 9 | export function Text({ children, style }: Props) { 10 | const styles = React.useMemo(() => { 11 | const res: TextStyle[] = [textStyles.text]; 12 | if (style) { 13 | res.concat(style); 14 | } 15 | return res; 16 | }, [style]); 17 | 18 | return {children}; 19 | } 20 | 21 | const textStyles = StyleSheet.create({ 22 | text: { 23 | color: 'black', 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /example80/src/components/Text.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { StyleSheet, Text as TextNative, type TextStyle } from 'react-native'; 3 | 4 | type Props = { 5 | children: React.ReactNode; 6 | style?: TextStyle | TextStyle[]; 7 | }; 8 | 9 | export function Text({ children, style }: Props) { 10 | const styles = React.useMemo(() => { 11 | const res: TextStyle[] = [textStyles.text]; 12 | if (style) { 13 | res.concat(style); 14 | } 15 | return res; 16 | }, [style]); 17 | 18 | return {children}; 19 | } 20 | 21 | const textStyles = StyleSheet.create({ 22 | text: { 23 | color: 'black', 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /example/src/components/Indentator.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, StyleSheet } from 'react-native'; 3 | 4 | type IndentatorProps = { 5 | indentation: number; 6 | children: React.ReactChild; 7 | }; 8 | 9 | export const Indentator: React.FC = ({ 10 | indentation, 11 | children, 12 | }: IndentatorProps) => { 13 | return ( 14 | 15 | 16 | {children} 17 | 18 | ); 19 | }; 20 | 21 | const styles = StyleSheet.create({ 22 | container: { 23 | width: '100%', 24 | padding: 5, 25 | flexDirection: 'row', 26 | alignContent: 'center', 27 | }, 28 | }); 29 | -------------------------------------------------------------------------------- /example80/src/components/Indentator.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, StyleSheet } from 'react-native'; 3 | 4 | type IndentatorProps = { 5 | indentation: number; 6 | children: React.ReactChild; 7 | }; 8 | 9 | export const Indentator: React.FC = ({ 10 | indentation, 11 | children, 12 | }: IndentatorProps) => { 13 | return ( 14 | 15 | 16 | {children} 17 | 18 | ); 19 | }; 20 | 21 | const styles = StyleSheet.create({ 22 | container: { 23 | width: '100%', 24 | padding: 5, 25 | flexDirection: 'row', 26 | alignContent: 'center', 27 | }, 28 | }); 29 | -------------------------------------------------------------------------------- /android/src/oldarch/java/com/fasturl/FastUrlModule.java: -------------------------------------------------------------------------------- 1 | package com.fasturl; 2 | 3 | import androidx.annotation.NonNull; 4 | import com.facebook.react.bridge.ReactApplicationContext; 5 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 6 | import com.facebook.react.bridge.ReactMethod; 7 | 8 | public class FastUrlModule extends ReactContextBaseJavaModule { 9 | FastUrlModule(ReactApplicationContext context) { 10 | super(context); 11 | } 12 | 13 | @NonNull 14 | @Override 15 | public String getName() { 16 | return FastUrlModuleImpl.NAME; 17 | } 18 | 19 | @ReactMethod(isBlockingSynchronousMethod = true) 20 | public boolean install() { 21 | return FastUrlModuleImpl.install(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | buildToolsVersion = "35.0.0" 6 | minSdkVersion = 24 7 | compileSdkVersion = 35 8 | targetSdkVersion = 34 9 | ndkVersion = "26.1.10909125" 10 | kotlinVersion = "1.9.25" 11 | } 12 | repositories { 13 | google() 14 | mavenCentral() 15 | } 16 | dependencies { 17 | classpath("com.android.tools.build:gradle") 18 | classpath("com.facebook.react:react-native-gradle-plugin") 19 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") 20 | } 21 | } 22 | 23 | apply plugin: "com.facebook.react.rootproject" 24 | -------------------------------------------------------------------------------- /example/src/components/Suite.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, StyleSheet } from 'react-native'; 3 | import { Text } from './Text'; 4 | 5 | type SuiteProps = { 6 | description: string; 7 | }; 8 | 9 | export const Suite: React.FC = ({ description }: SuiteProps) => { 10 | const emoji = '↘️ '; 11 | const fullText = emoji + description; 12 | 13 | return ( 14 | 15 | {fullText} 16 | 17 | ); 18 | }; 19 | 20 | const styles = StyleSheet.create({ 21 | scroll: { 22 | flex: 1, 23 | }, 24 | itemContainer: { 25 | borderWidth: 1, 26 | margin: 10, 27 | marginBottom: 0, 28 | flexDirection: 'column', 29 | borderRadius: 5, 30 | padding: 5, 31 | }, 32 | text: { 33 | flexShrink: 1, 34 | }, 35 | }); 36 | -------------------------------------------------------------------------------- /example80/src/components/Suite.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, StyleSheet } from 'react-native'; 3 | import { Text } from './Text'; 4 | 5 | type SuiteProps = { 6 | description: string; 7 | }; 8 | 9 | export const Suite: React.FC = ({ description }: SuiteProps) => { 10 | const emoji = '↘️ '; 11 | const fullText = emoji + description; 12 | 13 | return ( 14 | 15 | {fullText} 16 | 17 | ); 18 | }; 19 | 20 | const styles = StyleSheet.create({ 21 | scroll: { 22 | flex: 1, 23 | }, 24 | itemContainer: { 25 | borderWidth: 1, 26 | margin: 10, 27 | marginBottom: 0, 28 | flexDirection: 'column', 29 | borderRadius: 5, 30 | padding: 5, 31 | }, 32 | text: { 33 | flexShrink: 1, 34 | }, 35 | }); 36 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": ".", 4 | "paths": { 5 | "react-native-fast-url": ["./src/index"] 6 | }, 7 | "allowUnreachableCode": false, 8 | "allowUnusedLabels": false, 9 | "esModuleInterop": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "jsx": "react", 12 | "lib": ["esnext"], 13 | "module": "esnext", 14 | "moduleResolution": "node", 15 | "noFallthroughCasesInSwitch": true, 16 | "noImplicitReturns": true, 17 | "noImplicitUseStrict": false, 18 | "noStrictGenericChecks": false, 19 | "noUncheckedIndexedAccess": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "resolveJsonModule": true, 23 | "skipLibCheck": true, 24 | "strict": true, 25 | "target": "esnext", 26 | "verbatimModuleSyntax": true 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "pipeline": { 4 | "build:android": { 5 | "inputs": [ 6 | "package.json", 7 | "android", 8 | "!android/build", 9 | "src/*.ts", 10 | "src/*.tsx", 11 | "example/package.json", 12 | "example/android", 13 | "!example/android/.gradle", 14 | "!example/android/build", 15 | "!example/android/app/build" 16 | ], 17 | "outputs": [] 18 | }, 19 | "build:ios": { 20 | "inputs": [ 21 | "package.json", 22 | "*.podspec", 23 | "ios", 24 | "src/*.ts", 25 | "src/*.tsx", 26 | "example/package.json", 27 | "example/ios", 28 | "!example/ios/build", 29 | "!example/ios/Pods" 30 | ], 31 | "outputs": [] 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /example/ios/FastUrlExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/FastUrl.mm: -------------------------------------------------------------------------------- 1 | #import "FastUrl.h" 2 | 3 | #import 4 | #import 5 | #import 6 | #import "../cpp/fast-url.h" 7 | 8 | @implementation FastUrl 9 | RCT_EXPORT_MODULE(FastUrl) 10 | 11 | RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install) { 12 | NSLog(@"Initializing FastUrl module..."); 13 | 14 | RCTBridge *bridge = [RCTBridge currentBridge]; 15 | RCTCxxBridge *cxxBridge = (RCTCxxBridge *)bridge; 16 | if (cxxBridge == nil) { 17 | return @false; 18 | } 19 | 20 | using namespace facebook; 21 | 22 | auto jsiRuntime = (jsi::Runtime *)cxxBridge.runtime; 23 | if (jsiRuntime == nil) { 24 | return @false; 25 | } 26 | auto &runtime = *jsiRuntime; 27 | 28 | fasturl::install(runtime); 29 | 30 | NSLog(@"FastUrl initialized"); 31 | return @true; 32 | } 33 | 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /android/src/main/java/com/fasturl/FastUrlPackage.java: -------------------------------------------------------------------------------- 1 | package com.fasturl; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.facebook.react.ReactPackage; 6 | import com.facebook.react.bridge.NativeModule; 7 | import com.facebook.react.bridge.ReactApplicationContext; 8 | import com.facebook.react.uimanager.ViewManager; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Collections; 12 | import java.util.List; 13 | 14 | public class FastUrlPackage implements ReactPackage { 15 | @NonNull 16 | @Override 17 | public List createNativeModules(@NonNull ReactApplicationContext reactContext) { 18 | List modules = new ArrayList<>(); 19 | modules.add(new FastUrlModule(reactContext)); 20 | return modules; 21 | } 22 | 23 | @NonNull 24 | @Override 25 | public List createViewManagers(@NonNull ReactApplicationContext reactContext) { 26 | return Collections.emptyList(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /example/src/components/CorrectResultItem.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, StyleSheet } from 'react-native'; 3 | import { Text } from './Text'; 4 | 5 | type CorrectResultItemProps = { 6 | description: string; 7 | }; 8 | 9 | export const CorrectResultItem: React.FC = ({ 10 | description, 11 | }: CorrectResultItemProps) => { 12 | const emoji = '✅'; 13 | const fullText = emoji + ' [' + description + ']'; 14 | 15 | return ( 16 | 17 | {fullText} 18 | 19 | ); 20 | }; 21 | 22 | const styles = StyleSheet.create({ 23 | scroll: { 24 | flex: 1, 25 | }, 26 | itemContainer: { 27 | borderWidth: 1, 28 | margin: 10, 29 | marginRight: 55, 30 | marginBottom: 0, 31 | flexDirection: 'column', 32 | borderRadius: 5, 33 | padding: 5, 34 | }, 35 | text: { 36 | flexShrink: 1, 37 | }, 38 | }); 39 | -------------------------------------------------------------------------------- /example80/src/components/CorrectResultItem.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, StyleSheet } from 'react-native'; 3 | import { Text } from './Text'; 4 | 5 | type CorrectResultItemProps = { 6 | description: string; 7 | }; 8 | 9 | export const CorrectResultItem: React.FC = ({ 10 | description, 11 | }: CorrectResultItemProps) => { 12 | const emoji = '✅'; 13 | const fullText = emoji + ' [' + description + ']'; 14 | 15 | return ( 16 | 17 | {fullText} 18 | 19 | ); 20 | }; 21 | 22 | const styles = StyleSheet.create({ 23 | scroll: { 24 | flex: 1, 25 | }, 26 | itemContainer: { 27 | borderWidth: 1, 28 | margin: 10, 29 | marginRight: 55, 30 | marginBottom: 0, 31 | flexDirection: 'column', 32 | borderRadius: 5, 33 | padding: 5, 34 | }, 35 | text: { 36 | flexShrink: 1, 37 | }, 38 | }); 39 | -------------------------------------------------------------------------------- /example/ios/FastUrlExample/AppDelegate.mm: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | 3 | #import 4 | 5 | @implementation AppDelegate 6 | 7 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 8 | { 9 | self.moduleName = @"FastUrlExample"; 10 | // You can add your custom initial props in the dictionary below. 11 | // They will be passed down to the ViewController used by React Native. 12 | self.initialProps = @{}; 13 | 14 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 15 | } 16 | 17 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 18 | { 19 | return [self bundleURL]; 20 | } 21 | - (NSURL *)bundleURL 22 | { 23 | #if DEBUG 24 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; 25 | #else 26 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 27 | #endif 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /android/cpp-adapter.cpp: -------------------------------------------------------------------------------- 1 | #include "fast-url.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace facebook; 8 | 9 | struct FastUrlBridge : jni::JavaClass { 10 | static constexpr auto kJavaDescriptor = 11 | "Lcom/fasturl/FastUrlBridge;"; 12 | 13 | static void registerNatives() { 14 | javaClassStatic()->registerNatives( 15 | {// initialization for JSI 16 | makeNativeMethod("installNativeJsi", 17 | FastUrlBridge::installNativeJsi) 18 | }); 19 | } 20 | 21 | private: 22 | static void installNativeJsi( 23 | jni::alias_ref thiz, jlong jsiRuntimePtr) { 24 | auto jsiRuntime = reinterpret_cast(jsiRuntimePtr); 25 | 26 | fasturl::install(*jsiRuntime); 27 | } 28 | }; 29 | 30 | JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) { 31 | return jni::initialize(vm, [] { FastUrlBridge::registerNatives(); }); 32 | } 33 | -------------------------------------------------------------------------------- /android/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(FastURL) 2 | cmake_minimum_required(VERSION 3.9.0) 3 | 4 | set(PACKAGE_NAME "fast-url") 5 | set(CMAKE_VERBOSE_MAKEFILE ON) 6 | set(CMAKE_CXX_STANDARD 17) 7 | set(BUILD_DIR ${CMAKE_SOURCE_DIR}/build) 8 | 9 | # Specifies a path to native header files. 10 | include_directories(../cpp) 11 | 12 | add_library(${PACKAGE_NAME} SHARED ../cpp/fast-url.cpp ../cpp/ada.cpp ../cpp/URLHostObjects.cpp cpp-adapter.cpp ) 13 | 14 | set_target_properties( 15 | ${PACKAGE_NAME} 16 | PROPERTIES CXX_STANDARD 17 17 | CXX_EXTENSIONS OFF 18 | POSITION_INDEPENDENT_CODE ON) 19 | 20 | find_package(ReactAndroid REQUIRED CONFIG) 21 | find_package(fbjni REQUIRED CONFIG) 22 | 23 | target_link_libraries(${PACKAGE_NAME} fbjni::fbjni ReactAndroid::jsi android) 24 | 25 | # Enable Android 16kb native library alignment 26 | if(CMAKE_ANDROID_NDK_VERSION VERSION_LESS "27") 27 | target_link_options(${PACKAGE_NAME} PRIVATE "-Wl,-z,max-page-size=16384") 28 | endif() 29 | -------------------------------------------------------------------------------- /example/src/App.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { NavigationContainer } from '@react-navigation/native'; 3 | import { createNativeStackNavigator } from '@react-navigation/native-stack'; 4 | 5 | import { Home } from './screens/Home'; 6 | import { Benchmarks } from './screens/Benchmarks/Benchmarks'; 7 | import { Tests } from './screens/Tests/Tests'; 8 | import type { RootStackParamList } from './screens/params'; 9 | import { useColorTheme } from './components/useColorTheme'; 10 | 11 | const Stack = createNativeStackNavigator(); 12 | 13 | export default function App() { 14 | const theme = useColorTheme(); 15 | return ( 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /example80/src/App.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { NavigationContainer } from '@react-navigation/native'; 3 | import { createNativeStackNavigator } from '@react-navigation/native-stack'; 4 | 5 | import { Home } from './screens/Home'; 6 | import { Benchmarks } from './screens/Benchmarks/Benchmarks'; 7 | import { Tests } from './screens/Tests/Tests'; 8 | import type { RootStackParamList } from './screens/params'; 9 | import { useColorTheme } from './components/useColorTheme'; 10 | 11 | const Stack = createNativeStackNavigator(); 12 | 13 | export default function App() { 14 | const theme = useColorTheme(); 15 | return ( 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/fasturlexample/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.fasturlexample 2 | 3 | import com.facebook.react.ReactActivity 4 | import com.facebook.react.ReactActivityDelegate 5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled 6 | import com.facebook.react.defaults.DefaultReactActivityDelegate 7 | 8 | class MainActivity : ReactActivity() { 9 | 10 | /** 11 | * Returns the name of the main component registered from JavaScript. This is used to schedule 12 | * rendering of the component. 13 | */ 14 | override fun getMainComponentName(): String = "FastUrlExample" 15 | 16 | /** 17 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] 18 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] 19 | */ 20 | override fun createReactActivityDelegate(): ReactActivityDelegate = 21 | DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) 22 | } 23 | -------------------------------------------------------------------------------- /example/src/components/IncorrectResultItem.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, StyleSheet } from 'react-native'; 3 | import { Text } from './Text'; 4 | 5 | type IncorrectResultItemProps = { 6 | description: string; 7 | errorMsg: string; 8 | }; 9 | 10 | export const IncorrectResultItem: React.FC = ({ 11 | description, 12 | errorMsg, 13 | }: IncorrectResultItemProps) => { 14 | const emoji = '❌'; 15 | const fullText = emoji + ' [' + description + '] ---> ' + errorMsg; 16 | 17 | return ( 18 | 19 | {fullText} 20 | 21 | ); 22 | }; 23 | 24 | const styles = StyleSheet.create({ 25 | scroll: { 26 | flex: 1, 27 | }, 28 | itemContainer: { 29 | borderWidth: 1, 30 | margin: 10, 31 | marginRight: 55, 32 | marginBottom: 0, 33 | flexDirection: 'column', 34 | borderRadius: 5, 35 | padding: 5, 36 | }, 37 | text: { 38 | flexShrink: 1, 39 | }, 40 | }); 41 | -------------------------------------------------------------------------------- /example80/src/components/IncorrectResultItem.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, StyleSheet } from 'react-native'; 3 | import { Text } from './Text'; 4 | 5 | type IncorrectResultItemProps = { 6 | description: string; 7 | errorMsg: string; 8 | }; 9 | 10 | export const IncorrectResultItem: React.FC = ({ 11 | description, 12 | errorMsg, 13 | }: IncorrectResultItemProps) => { 14 | const emoji = '❌'; 15 | const fullText = emoji + ' [' + description + '] ---> ' + errorMsg; 16 | 17 | return ( 18 | 19 | {fullText} 20 | 21 | ); 22 | }; 23 | 24 | const styles = StyleSheet.create({ 25 | scroll: { 26 | flex: 1, 27 | }, 28 | itemContainer: { 29 | borderWidth: 1, 30 | margin: 10, 31 | marginRight: 55, 32 | marginBottom: 0, 33 | flexDirection: 'column', 34 | borderRadius: 5, 35 | padding: 5, 36 | }, 37 | text: { 38 | flexShrink: 1, 39 | }, 40 | }); 41 | -------------------------------------------------------------------------------- /scripts/pod-install.cjs: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process'); 2 | 3 | module.exports = { 4 | name: 'pod-install', 5 | factory() { 6 | return { 7 | hooks: { 8 | afterAllInstalled(project, options) { 9 | if (process.env.POD_INSTALL === '0') { 10 | return; 11 | } 12 | 13 | if ( 14 | options && 15 | (options.mode === 'update-lockfile' || 16 | options.mode === 'skip-build') 17 | ) { 18 | return; 19 | } 20 | 21 | const result = child_process.spawnSync( 22 | 'yarn', 23 | ['pod-install', 'example/ios'], 24 | { 25 | cwd: project.cwd, 26 | env: process.env, 27 | stdio: 'inherit', 28 | encoding: 'utf-8', 29 | shell: true, 30 | } 31 | ); 32 | 33 | if (result.status !== 0) { 34 | throw new Error('Failed to run pod-install'); 35 | } 36 | }, 37 | }, 38 | }; 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /example/src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, TouchableOpacity, StyleSheet } from 'react-native'; 3 | import { Text } from './Text'; 4 | import { useColorTheme } from './useColorTheme'; 5 | 6 | type ButtonProps = { 7 | title: string; 8 | onPress: () => void; 9 | }; 10 | 11 | export const Button: React.FC = ({ 12 | title, 13 | onPress, 14 | }: ButtonProps) => { 15 | const theme = useColorTheme(); 16 | return ( 17 | 18 | 27 | {title} 28 | 29 | 30 | ); 31 | }; 32 | 33 | const styles = StyleSheet.create({ 34 | container: { 35 | backgroundColor: '#d1e8ff', 36 | padding: 10, 37 | borderRadius: 5, 38 | alignContent: 'center', 39 | justifyContent: 'center', 40 | borderWidth: 1, 41 | borderColor: 'black', 42 | }, 43 | }); 44 | -------------------------------------------------------------------------------- /example80/src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, TouchableOpacity, StyleSheet } from 'react-native'; 3 | import { Text } from './Text'; 4 | import { useColorTheme } from './useColorTheme'; 5 | 6 | type ButtonProps = { 7 | title: string; 8 | onPress: () => void; 9 | }; 10 | 11 | export const Button: React.FC = ({ 12 | title, 13 | onPress, 14 | }: ButtonProps) => { 15 | const theme = useColorTheme(); 16 | return ( 17 | 18 | 27 | {title} 28 | 29 | 30 | ); 31 | }; 32 | 33 | const styles = StyleSheet.create({ 34 | container: { 35 | backgroundColor: '#d1e8ff', 36 | padding: 10, 37 | borderRadius: 5, 38 | alignContent: 'center', 39 | justifyContent: 'center', 40 | borderWidth: 1, 41 | borderColor: 'black', 42 | }, 43 | }); 44 | -------------------------------------------------------------------------------- /example/src/testing/MochaRnAdapter.ts: -------------------------------------------------------------------------------- 1 | import 'mocha'; 2 | import type * as MochaTypes from 'mocha'; 3 | 4 | export const rootSuite = new Mocha.Suite('') as MochaTypes.Suite; 5 | 6 | let mochaContext = rootSuite; 7 | let only = false; 8 | 9 | export const clearTests = () => { 10 | rootSuite.suites = []; 11 | rootSuite.tests = []; 12 | mochaContext = rootSuite; 13 | only = false; 14 | }; 15 | 16 | export const it = (name: string, f: () => void): void => { 17 | if (!only) { 18 | mochaContext.addTest(new Mocha.Test(name, f) as MochaTypes.Test); 19 | } 20 | }; 21 | 22 | export const itOnly = (name: string, f: () => void): void => { 23 | clearTests(); 24 | mochaContext.addTest(new Mocha.Test(name, f) as MochaTypes.Test); 25 | only = true; 26 | }; 27 | 28 | export const describe = (name: string, f: () => void): void => { 29 | const prevMochaContext = mochaContext; 30 | mochaContext = new Mocha.Suite( 31 | name, 32 | prevMochaContext.ctx 33 | ) as MochaTypes.Suite; 34 | prevMochaContext.addSuite(mochaContext); 35 | f(); 36 | mochaContext = prevMochaContext; 37 | }; 38 | -------------------------------------------------------------------------------- /example80/src/testing/MochaRnAdapter.ts: -------------------------------------------------------------------------------- 1 | import 'mocha'; 2 | import type * as MochaTypes from 'mocha'; 3 | 4 | export const rootSuite = new Mocha.Suite('') as MochaTypes.Suite; 5 | 6 | let mochaContext = rootSuite; 7 | let only = false; 8 | 9 | export const clearTests = () => { 10 | rootSuite.suites = []; 11 | rootSuite.tests = []; 12 | mochaContext = rootSuite; 13 | only = false; 14 | }; 15 | 16 | export const it = (name: string, f: () => void): void => { 17 | if (!only) { 18 | mochaContext.addTest(new Mocha.Test(name, f) as MochaTypes.Test); 19 | } 20 | }; 21 | 22 | export const itOnly = (name: string, f: () => void): void => { 23 | clearTests(); 24 | mochaContext.addTest(new Mocha.Test(name, f) as MochaTypes.Test); 25 | only = true; 26 | }; 27 | 28 | export const describe = (name: string, f: () => void): void => { 29 | const prevMochaContext = mochaContext; 30 | mochaContext = new Mocha.Suite( 31 | name, 32 | prevMochaContext.ctx 33 | ) as MochaTypes.Suite; 34 | prevMochaContext.addSuite(mochaContext); 35 | f(); 36 | mochaContext = prevMochaContext; 37 | }; 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # XDE 6 | .expo/ 7 | 8 | # VSCode 9 | .vscode/ 10 | jsconfig.json 11 | 12 | # Xcode 13 | # 14 | build/ 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | xcuserdata 24 | *.xccheckout 25 | *.moved-aside 26 | DerivedData 27 | *.hmap 28 | *.ipa 29 | *.xcuserstate 30 | project.xcworkspace 31 | 32 | # Android/IJ 33 | # 34 | .classpath 35 | .cxx 36 | .gradle 37 | .idea 38 | .project 39 | .settings 40 | local.properties 41 | android.iml 42 | 43 | # Cocoapods 44 | # 45 | **/ios/Pods 46 | 47 | # Ruby 48 | **/vendor/ 49 | 50 | # node.js 51 | # 52 | node_modules/ 53 | npm-debug.log 54 | yarn-debug.log 55 | yarn-error.log 56 | 57 | # BUCK 58 | buck-out/ 59 | \.buckd/ 60 | android/app/libs 61 | android/keystores/debug.keystore 62 | 63 | # Yarn 64 | .yarn/* 65 | !.yarn/patches 66 | !.yarn/plugins 67 | !.yarn/releases 68 | !.yarn/sdks 69 | !.yarn/versions 70 | 71 | # Expo 72 | .expo/ 73 | 74 | # Turborepo 75 | .turbo/ 76 | 77 | # generated by bob 78 | lib/ 79 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /example80/android/app/src/main/java/com/example2/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example2 2 | 3 | import com.facebook.react.ReactActivity 4 | import com.facebook.react.ReactActivityDelegate 5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled 6 | import com.facebook.react.defaults.DefaultReactActivityDelegate 7 | import android.os.Bundle; 8 | 9 | class MainActivity : ReactActivity() { 10 | override fun onCreate(savedInstanceState: Bundle?) { 11 | super.onCreate(null) 12 | } 13 | 14 | /** 15 | * Returns the name of the main component registered from JavaScript. This is used to schedule 16 | * rendering of the component. 17 | */ 18 | override fun getMainComponentName(): String = "example2" 19 | 20 | /** 21 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] 22 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] 23 | */ 24 | override fun createReactActivityDelegate(): ReactActivityDelegate = 25 | DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 kusstar 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /react-native-fast-url.podspec: -------------------------------------------------------------------------------- 1 | require "json" 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, "package.json"))) 4 | folly_version = '2021.06.28.00-v2' 5 | folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' 6 | 7 | 8 | Pod::Spec.new do |s| 9 | s.name = "react-native-fast-url" 10 | s.version = package["version"] 11 | s.summary = package["description"] 12 | s.homepage = package["homepage"] 13 | s.license = package["license"] 14 | s.authors = package["author"] 15 | s.platforms = { :ios => "13.4" } 16 | s.source = { :git => "https://github.com/KusStar/react-native-fast-url.git", :tag => "#{s.version}" } 17 | 18 | s.source_files = "ios/**/*.{h,m,mm}", "cpp/**/*.{h,cpp}" 19 | s.requires_arc = true 20 | 21 | s.dependency "React-Core" 22 | s.dependency "React-jsi" 23 | 24 | s.compiler_flags = folly_compiler_flags 25 | s.pod_target_xcconfig = { 26 | "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/Headers/Private/React-Core\"", 27 | "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" 28 | } 29 | end 30 | -------------------------------------------------------------------------------- /example80/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example80/ios/example2/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "scale" : "1x", 46 | "size" : "1024x1024" 47 | } 48 | ], 49 | "info" : { 50 | "author" : "xcode", 51 | "version" : 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /example/ios/FastUrlExample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "scale" : "1x", 46 | "size" : "1024x1024" 47 | } 48 | ], 49 | "info" : { 50 | "author" : "xcode", 51 | "version" : 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /example80/ios/example2/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryFileTimestamp 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | C617.1 13 | 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryUserDefaults 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | CA92.1 21 | 22 | 23 | 24 | NSPrivacyAccessedAPIType 25 | NSPrivacyAccessedAPICategorySystemBootTime 26 | NSPrivacyAccessedAPITypeReasons 27 | 28 | 35F9.1 29 | 30 | 31 | 32 | NSPrivacyCollectedDataTypes 33 | 34 | NSPrivacyTracking 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/FastUrlExample/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryFileTimestamp 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | C617.1 13 | 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryUserDefaults 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | CA92.1 21 | 22 | 23 | 24 | NSPrivacyAccessedAPIType 25 | NSPrivacyAccessedAPICategorySystemBootTime 26 | NSPrivacyAccessedAPITypeReasons 27 | 28 | 35F9.1 29 | 30 | 31 | 32 | NSPrivacyCollectedDataTypes 33 | 34 | NSPrivacyTracking 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example80/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Resolve react_native_pods.rb with node to allow for hoisting 2 | require Pod::Executable.execute_command('node', ['-p', 3 | 'require.resolve( 4 | "react-native/scripts/react_native_pods.rb", 5 | {paths: [process.argv[1]]}, 6 | )', __dir__]).strip 7 | 8 | platform :ios, min_ios_version_supported 9 | prepare_react_native_project! 10 | 11 | linkage = ENV['USE_FRAMEWORKS'] 12 | if linkage != nil 13 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 14 | use_frameworks! :linkage => linkage.to_sym 15 | end 16 | 17 | target 'example2' do 18 | config = use_native_modules! 19 | 20 | use_react_native!( 21 | :path => config[:reactNativePath], 22 | # An absolute path to your application root. 23 | :app_path => "#{Pod::Config.instance.installation_root}/.." 24 | ) 25 | 26 | post_install do |installer| 27 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 28 | react_native_post_install( 29 | installer, 30 | config[:reactNativePath], 31 | :mac_catalyst_enabled => false, 32 | # :ccache_enabled => true 33 | ) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /android/src/main/java/com/fasturl/FastUrlModule.java: -------------------------------------------------------------------------------- 1 | package com.fasturl; 2 | 3 | import androidx.annotation.NonNull; 4 | import android.util.Log; 5 | 6 | import com.facebook.react.bridge.Promise; 7 | import com.facebook.react.bridge.ReactApplicationContext; 8 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 9 | import com.facebook.react.bridge.ReactMethod; 10 | import com.facebook.react.module.annotations.ReactModule; 11 | 12 | @ReactModule(name = FastUrlModule.NAME) 13 | public class FastUrlModule extends ReactContextBaseJavaModule { 14 | public static final String NAME = "FastUrl"; 15 | 16 | public FastUrlModule(ReactApplicationContext reactContext) { 17 | super(reactContext); 18 | } 19 | 20 | @Override 21 | @NonNull 22 | public String getName() { 23 | return NAME; 24 | } 25 | 26 | @ReactMethod(isBlockingSynchronousMethod = true) 27 | public boolean install() { 28 | try { 29 | System.loadLibrary("fast-url"); 30 | FastUrlBridge.instance.install(getReactApplicationContext()); 31 | return true; 32 | } catch (Exception exception) { 33 | Log.e(NAME, "Failed to install JSI Bindings!", exception); 34 | return false; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /example/src/screens/Benchmarks/bench.ts: -------------------------------------------------------------------------------- 1 | import performance from 'react-native-performance'; 2 | import { URL as fastURL } from 'react-native-fast-url'; 3 | import { URL as polyFillURL } from 'react-native-url-polyfill'; 4 | 5 | const bench = (tag: string, fn: () => void) => { 6 | performance.mark('start_' + tag); 7 | fn(); 8 | performance.mark('end_' + tag); 9 | performance.measure(tag, 'start_' + tag, 'end_' + tag); 10 | console.log(tag, performance.getEntriesByName(tag)); 11 | return performance.getEntriesByName(tag); 12 | }; 13 | 14 | export const startBench = () => { 15 | const result = []; 16 | const url = 'https://example.com?a=1&b=2&c=3'; 17 | for (const loop of [100, 1000, 10000, 100000]) { 18 | global.gc?.(); 19 | 20 | const b2 = bench('fast URL x' + loop, () => { 21 | for (let i = 0; i < loop; i++) { 22 | new fastURL(url); 23 | } 24 | }); 25 | 26 | global.gc?.(); 27 | 28 | const b1 = bench('polyfill URL x' + loop, () => { 29 | for (let i = 0; i < loop; i++) { 30 | new polyFillURL(url); 31 | } 32 | }); 33 | 34 | result.push({ 35 | loop, 36 | b1: b1[0]?.duration!, 37 | b2: b2[0]?.duration!, 38 | }); 39 | } 40 | 41 | return result; 42 | }; 43 | -------------------------------------------------------------------------------- /example80/src/screens/Benchmarks/bench.ts: -------------------------------------------------------------------------------- 1 | import performance from 'react-native-performance'; 2 | import { URL as fastURL } from 'react-native-fast-url'; 3 | import { URL as polyFillURL } from 'react-native-url-polyfill'; 4 | 5 | const bench = (tag: string, fn: () => void) => { 6 | performance.mark('start_' + tag); 7 | fn(); 8 | performance.mark('end_' + tag); 9 | performance.measure(tag, 'start_' + tag, 'end_' + tag); 10 | console.log(tag, performance.getEntriesByName(tag)); 11 | return performance.getEntriesByName(tag); 12 | }; 13 | 14 | export const startBench = () => { 15 | const result = []; 16 | const url = 'https://example.com?a=1&b=2&c=3'; 17 | for (const loop of [100, 1000, 10000, 100000]) { 18 | global.gc?.(); 19 | 20 | const b2 = bench('fast URL x' + loop, () => { 21 | for (let i = 0; i < loop; i++) { 22 | new fastURL(url); 23 | } 24 | }); 25 | 26 | global.gc?.(); 27 | 28 | const b1 = bench('polyfill URL x' + loop, () => { 29 | for (let i = 0; i < loop; i++) { 30 | new polyFillURL(url); 31 | } 32 | }); 33 | 34 | result.push({ 35 | loop, 36 | b1: b1[0]?.duration!, 37 | b2: b2[0]?.duration!, 38 | }); 39 | } 40 | 41 | return result; 42 | }; 43 | -------------------------------------------------------------------------------- /example/src/components/TestItem.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, StyleSheet } from 'react-native'; 3 | import Checkbox from '@react-native-community/checkbox'; 4 | import { Text } from './Text'; 5 | import { useColorTheme } from './useColorTheme'; 6 | 7 | type TestItemProps = { 8 | description: string; 9 | value: boolean; 10 | index: number; 11 | onToggle: (index: number) => void; 12 | }; 13 | 14 | export const TestItem: React.FC = ({ 15 | description, 16 | value, 17 | index, 18 | onToggle, 19 | }: TestItemProps) => { 20 | const theme = useColorTheme(); 21 | return ( 22 | 23 | {description} 24 | { 30 | onToggle(index); 31 | }} 32 | /> 33 | 34 | ); 35 | }; 36 | 37 | const styles = StyleSheet.create({ 38 | container: { 39 | borderRadius: 6, 40 | width: '100%', 41 | padding: 10, 42 | paddingHorizontal: 25, 43 | flexDirection: 'row', 44 | alignContent: 'center', 45 | alignItems: 'center', 46 | justifyContent: 'space-between', 47 | backgroundColor: '#d1e8ff', 48 | marginTop: 10, 49 | }, 50 | }); 51 | -------------------------------------------------------------------------------- /example80/src/components/TestItem.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, StyleSheet } from 'react-native'; 3 | import Checkbox from '@react-native-community/checkbox'; 4 | import { Text } from './Text'; 5 | import { useColorTheme } from './useColorTheme'; 6 | 7 | type TestItemProps = { 8 | description: string; 9 | value: boolean; 10 | index: number; 11 | onToggle: (index: number) => void; 12 | }; 13 | 14 | export const TestItem: React.FC = ({ 15 | description, 16 | value, 17 | index, 18 | onToggle, 19 | }: TestItemProps) => { 20 | const theme = useColorTheme(); 21 | return ( 22 | 23 | {description} 24 | { 30 | onToggle(index); 31 | }} 32 | /> 33 | 34 | ); 35 | }; 36 | 37 | const styles = StyleSheet.create({ 38 | container: { 39 | borderRadius: 6, 40 | width: '100%', 41 | padding: 10, 42 | paddingHorizontal: 25, 43 | flexDirection: 'row', 44 | alignContent: 'center', 45 | alignItems: 'center', 46 | justifyContent: 'space-between', 47 | backgroundColor: '#d1e8ff', 48 | marginTop: 10, 49 | }, 50 | }); 51 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Resolve react_native_pods.rb with node to allow for hoisting 2 | require Pod::Executable.execute_command('node', ['-p', 3 | 'require.resolve( 4 | "react-native/scripts/react_native_pods.rb", 5 | {paths: [process.argv[1]]}, 6 | )', __dir__]).strip 7 | 8 | platform :ios, min_ios_version_supported 9 | prepare_react_native_project! 10 | 11 | ENV['RCT_NEW_ARCH_ENABLED'] = '1' 12 | 13 | linkage = ENV['USE_FRAMEWORKS'] 14 | if linkage != nil 15 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 16 | use_frameworks! :linkage => linkage.to_sym 17 | end 18 | 19 | target 'FastUrlExample' do 20 | config = use_native_modules! 21 | 22 | use_react_native!( 23 | :path => config[:reactNativePath], 24 | # An absolute path to your application root. 25 | :app_path => "#{Pod::Config.instance.installation_root}/.." 26 | ) 27 | 28 | target 'FastUrlExampleTests' do 29 | inherit! :complete 30 | # Pods for testing 31 | end 32 | 33 | post_install do |installer| 34 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 35 | react_native_post_install( 36 | installer, 37 | config[:reactNativePath], 38 | :mac_catalyst_enabled => false, 39 | # :ccache_enabled => true 40 | ) 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /cpp/URLHostObjects.h: -------------------------------------------------------------------------------- 1 | #ifndef FASTURL_HOSTOBJECTS_H 2 | #define FASTURL_HOSTOBJECTS_H 3 | 4 | #include "utils.h" 5 | 6 | namespace fasturl { 7 | namespace jsi = facebook::jsi; 8 | 9 | class JSI_EXPORT URLSearchParamsHostObject : public jsi::HostObject { 10 | public: 11 | URLSearchParamsHostObject(){}; 12 | 13 | URLSearchParamsHostObject(ada::url_search_params params) 14 | : _params(params){}; 15 | 16 | std::vector getPropertyNames( 17 | jsi::Runtime &rt) override; 18 | 19 | jsi::Value get(jsi::Runtime &rt, 20 | const jsi::PropNameID &propNameID) override; 21 | 22 | private: 23 | ada::url_search_params _params; 24 | }; 25 | 26 | class JSI_EXPORT URLHostObject : public jsi::HostObject { 27 | public: 28 | URLHostObject(){}; 29 | 30 | URLHostObject(ada::url_aggregator url) : _url(url){}; 31 | 32 | std::vector getPropertyNames( 33 | jsi::Runtime &rt) override; 34 | 35 | jsi::Value get(jsi::Runtime &rt, 36 | const jsi::PropNameID &propNameID) override; 37 | void set(jsi::Runtime &, const jsi::PropNameID &name, 38 | const jsi::Value &value) override; 39 | 40 | private: 41 | ada::url_aggregator _url; 42 | }; 43 | 44 | } // namespace fasturl 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /example80/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | **/.xcode.env.local 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | *.hprof 33 | .cxx/ 34 | *.keystore 35 | !debug.keystore 36 | .kotlin/ 37 | 38 | # node.js 39 | # 40 | node_modules/ 41 | npm-debug.log 42 | yarn-error.log 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | **/fastlane/report.xml 52 | **/fastlane/Preview.html 53 | **/fastlane/screenshots 54 | **/fastlane/test_output 55 | 56 | # Bundle artifact 57 | *.jsbundle 58 | 59 | # Ruby / CocoaPods 60 | **/Pods/ 61 | /vendor/bundle/ 62 | 63 | # Temporary files created by Metro to check the health of the file watcher 64 | .metro-health-check* 65 | 66 | # testing 67 | /coverage 68 | 69 | # Yarn 70 | .yarn/* 71 | !.yarn/patches 72 | !.yarn/plugins 73 | !.yarn/releases 74 | !.yarn/sdks 75 | !.yarn/versions 76 | -------------------------------------------------------------------------------- /example80/ios/example2/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import React 3 | import React_RCTAppDelegate 4 | import ReactAppDependencyProvider 5 | 6 | @main 7 | class AppDelegate: UIResponder, UIApplicationDelegate { 8 | var window: UIWindow? 9 | 10 | var reactNativeDelegate: ReactNativeDelegate? 11 | var reactNativeFactory: RCTReactNativeFactory? 12 | 13 | func application( 14 | _ application: UIApplication, 15 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil 16 | ) -> Bool { 17 | let delegate = ReactNativeDelegate() 18 | let factory = RCTReactNativeFactory(delegate: delegate) 19 | delegate.dependencyProvider = RCTAppDependencyProvider() 20 | 21 | reactNativeDelegate = delegate 22 | reactNativeFactory = factory 23 | 24 | window = UIWindow(frame: UIScreen.main.bounds) 25 | 26 | factory.startReactNative( 27 | withModuleName: "example2", 28 | in: window, 29 | launchOptions: launchOptions 30 | ) 31 | 32 | return true 33 | } 34 | } 35 | 36 | class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate { 37 | override func sourceURL(for bridge: RCTBridge) -> URL? { 38 | self.bundleURL() 39 | } 40 | 41 | override func bundleURL() -> URL? { 42 | #if DEBUG 43 | RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") 44 | #else 45 | Bundle.main.url(forResource: "main", withExtension: "jsbundle") 46 | #endif 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example80/android/app/src/main/java/com/example2/MainApplication.kt: -------------------------------------------------------------------------------- 1 | package com.example2 2 | 3 | import android.app.Application 4 | import com.facebook.react.PackageList 5 | import com.facebook.react.ReactApplication 6 | import com.facebook.react.ReactHost 7 | import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative 8 | import com.facebook.react.ReactNativeHost 9 | import com.facebook.react.ReactPackage 10 | import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost 11 | import com.facebook.react.defaults.DefaultReactNativeHost 12 | 13 | class MainApplication : Application(), ReactApplication { 14 | 15 | override val reactNativeHost: ReactNativeHost = 16 | object : DefaultReactNativeHost(this) { 17 | override fun getPackages(): List = 18 | PackageList(this).packages.apply { 19 | // Packages that cannot be autolinked yet can be added manually here, for example: 20 | // add(MyReactNativePackage()) 21 | } 22 | 23 | override fun getJSMainModuleName(): String = "index" 24 | 25 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG 26 | 27 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED 28 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED 29 | } 30 | 31 | override val reactHost: ReactHost 32 | get() = getDefaultReactHost(applicationContext, reactNativeHost) 33 | 34 | override fun onCreate() { 35 | super.onCreate() 36 | loadReactNative(this) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /example/metro.config.js: -------------------------------------------------------------------------------- 1 | const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); 2 | const path = require('path'); 3 | const escape = require('escape-string-regexp'); 4 | const exclusionList = require('metro-config/src/defaults/exclusionList'); 5 | const pak = require('../package.json'); 6 | 7 | const root = path.resolve(__dirname, '..'); 8 | const modules = Object.keys({ ...pak.peerDependencies }); 9 | 10 | /** 11 | * Metro configuration 12 | * https://facebook.github.io/metro/docs/configuration 13 | * 14 | * @type {import('metro-config').MetroConfig} 15 | */ 16 | const config = { 17 | watchFolders: [root], 18 | 19 | // We need to make sure that only one version is loaded for peerDependencies 20 | // So we block them at the root, and alias them to the versions in example's node_modules 21 | resolver: { 22 | blacklistRE: exclusionList( 23 | modules.map( 24 | (m) => 25 | new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) 26 | ) 27 | ), 28 | 29 | extraNodeModules: modules.reduce((acc, name) => { 30 | acc[name] = path.join(__dirname, 'node_modules', name); 31 | acc.stream = path.join(__dirname, 'node_modules', 'stream-browserify'); 32 | acc.buffer = path.join( 33 | __dirname, 34 | 'node_modules', 35 | '@craftzdog', 36 | 'react-native-buffer' 37 | ); 38 | return acc; 39 | }, {}), 40 | }, 41 | 42 | transformer: { 43 | getTransformOptions: async () => ({ 44 | transform: { 45 | experimentalImportSupport: false, 46 | inlineRequires: true, 47 | }, 48 | }), 49 | }, 50 | }; 51 | 52 | module.exports = mergeConfig(getDefaultConfig(__dirname), config); 53 | -------------------------------------------------------------------------------- /example80/metro.config.js: -------------------------------------------------------------------------------- 1 | const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); 2 | const path = require('path'); 3 | const escape = require('escape-string-regexp'); 4 | const exclusionList = require('metro-config/src/defaults/exclusionList'); 5 | const pak = require('../package.json'); 6 | 7 | const root = path.resolve(__dirname, '..'); 8 | const modules = Object.keys({ ...pak.peerDependencies }); 9 | 10 | /** 11 | * Metro configuration 12 | * https://facebook.github.io/metro/docs/configuration 13 | * 14 | * @type {import('metro-config/src/index.js').MetroConfig} 15 | */ 16 | const config = { 17 | watchFolders: [root], 18 | 19 | // We need to make sure that only one version is loaded for peerDependencies 20 | // So we block them at the root, and alias them to the versions in example's node_modules 21 | resolver: { 22 | blacklistRE: exclusionList( 23 | modules.map( 24 | (m) => 25 | new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) 26 | ) 27 | ), 28 | 29 | extraNodeModules: modules.reduce((acc, name) => { 30 | acc[name] = path.join(__dirname, 'node_modules', name); 31 | acc.stream = path.join(__dirname, 'node_modules', 'stream-browserify'); 32 | acc.buffer = path.join( 33 | __dirname, 34 | 'node_modules', 35 | '@craftzdog', 36 | 'react-native-buffer' 37 | ); 38 | return acc; 39 | }, {}), 40 | }, 41 | 42 | transformer: { 43 | getTransformOptions: async () => ({ 44 | transform: { 45 | experimentalImportSupport: false, 46 | inlineRequires: true, 47 | }, 48 | }), 49 | }, 50 | }; 51 | 52 | module.exports = mergeConfig(getDefaultConfig(__dirname), config); 53 | -------------------------------------------------------------------------------- /example80/ios/example2/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | example2 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | NSAllowsLocalNetworking 32 | 33 | 34 | NSLocationWhenInUseUsageDescription 35 | 36 | RCTNewArchEnabled 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | arm64 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /example/ios/FastUrlExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | FastUrlExample 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | 30 | NSAllowsArbitraryLoads 31 | 32 | NSAllowsLocalNetworking 33 | 34 | 35 | NSLocationWhenInUseUsageDescription 36 | 37 | UILaunchStoryboardName 38 | LaunchScreen 39 | UIRequiredDeviceCapabilities 40 | 41 | arm64 42 | 43 | UISupportedInterfaceOrientations 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | UIViewControllerBasedStatusBarAppearance 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/fasturlexample/MainApplication.kt: -------------------------------------------------------------------------------- 1 | package com.fasturlexample 2 | 3 | import android.app.Application 4 | import com.facebook.react.PackageList 5 | import com.facebook.react.ReactApplication 6 | import com.facebook.react.ReactHost 7 | import com.facebook.react.ReactNativeHost 8 | import com.facebook.react.ReactPackage 9 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load 10 | import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost 11 | import com.facebook.react.defaults.DefaultReactNativeHost 12 | import com.facebook.react.soloader.OpenSourceMergedSoMapping 13 | import com.facebook.soloader.SoLoader 14 | 15 | class MainApplication : Application(), ReactApplication { 16 | 17 | override val reactNativeHost: ReactNativeHost = 18 | object : DefaultReactNativeHost(this) { 19 | override fun getPackages(): List = 20 | PackageList(this).packages.apply { 21 | // Packages that cannot be autolinked yet can be added manually here, for example: 22 | // add(MyReactNativePackage()) 23 | } 24 | 25 | override fun getJSMainModuleName(): String = "index" 26 | 27 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG 28 | 29 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED 30 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED 31 | } 32 | 33 | override val reactHost: ReactHost 34 | get() = getDefaultReactHost(applicationContext, reactNativeHost) 35 | 36 | override fun onCreate() { 37 | super.onCreate() 38 | SoLoader.init(this, OpenSourceMergedSoMapping) 39 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { 40 | // If you opted-in for the New Architecture, we load the native entry point for this app. 41 | load() 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /example80/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m 13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | 25 | # Use this property to specify which architecture you want to build. 26 | # You can also override it from the CLI using 27 | # ./gradlew -PreactNativeArchitectures=x86_64 28 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 29 | 30 | # Use this property to enable support to the new architecture. 31 | # This will allow you to use TurboModules and the Fabric render in 32 | # your application. You should enable this flag either if you want 33 | # to write custom TurboModules/Fabric components OR use libraries that 34 | # are providing them. 35 | newArchEnabled=true 36 | 37 | # Use this property to enable or disable the Hermes JS engine. 38 | # If set to false, you will be using JSC instead. 39 | hermesEnabled=true 40 | -------------------------------------------------------------------------------- /example80/src/screens/Benchmarks/Benchmarks.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { StyleSheet, View, Text, ActivityIndicator, ScrollView } from 'react-native'; 4 | import { startBench } from './bench'; 5 | import { useColorTheme } from '../../components/useColorTheme'; 6 | 7 | export function Benchmarks() { 8 | const [result, setResult] = React.useState<{ 9 | b1: number; 10 | b2: number; 11 | loop: number; 12 | }[]>(); 13 | React.useEffect(() => { 14 | setTimeout(() => { 15 | setResult(startBench()); 16 | }, 100) 17 | }, []); 18 | 19 | const theme = useColorTheme(); 20 | 21 | const textStyle = { 22 | color: theme.colors.text, 23 | } 24 | 25 | return ( 26 | 27 | 28 | 29 | { 30 | result ? 31 | 38 | {result.map((it, index) => 39 | 40 | 41 | LOOP: {it.loop} 42 | polyfill URL: {it.b1.toFixed(2)}ms 43 | FastUrl: {it.b2.toFixed(2)}ms 44 | FastUrl is {(it.b1 / it.b2).toFixed(2)}x faster 45 | 46 | 47 | )} 48 | 49 | 50 | : 51 | 52 | 53 | Running benchmark... 54 | 55 | } 56 | 57 | ); 58 | } 59 | 60 | const styles = StyleSheet.create({ 61 | container: { 62 | flex: 1, 63 | alignItems: 'center', 64 | justifyContent: 'center', 65 | }, 66 | box: { 67 | width: 60, 68 | height: 60, 69 | marginVertical: 20, 70 | }, 71 | }); 72 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-fast-url-example", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "ios": "react-native run-ios", 8 | "start": "react-native start", 9 | "build:android": "cd android && ./gradlew assembleDebug --no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a", 10 | "build:ios": "cd ios && xcodebuild -workspace FastUrlExample.xcworkspace -scheme FastUrlExample -configuration Debug -sdk iphonesimulator CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ GCC_OPTIMIZATION_LEVEL=0 GCC_PRECOMPILE_PREFIX_HEADER=YES ASSETCATALOG_COMPILER_OPTIMIZATION=time DEBUG_INFORMATION_FORMAT=dwarf COMPILER_INDEX_STORE_ENABLE=NO" 11 | }, 12 | "dependencies": { 13 | "@craftzdog/react-native-buffer": "^6.0.5", 14 | "@react-native-community/checkbox": "^0.5.17", 15 | "@react-navigation/native": "^6.1.9", 16 | "@react-navigation/native-stack": "^6.9.17", 17 | "binary-search-bounds": "^2.0.5", 18 | "chai": "^5.0.0", 19 | "events": "^3.3.0", 20 | "long": "^5.2.3", 21 | "mocha": "^10.2.0", 22 | "react": "18.3.1", 23 | "react-native": "0.76.9", 24 | "react-native-performance": "^5.1.0", 25 | "react-native-safe-area-context": "^5.0.0", 26 | "react-native-screens": "3.37.0", 27 | "react-native-url-polyfill": "^2.0.0", 28 | "stream-browserify": "^3.0.0", 29 | "trie-typed": "^1.51.7", 30 | "util": "^0.12.5" 31 | }, 32 | "devDependencies": { 33 | "@babel/core": "^7.25.2", 34 | "@babel/plugin-transform-class-static-block": "^7.23.4", 35 | "@babel/preset-env": "^7.20.0", 36 | "@babel/runtime": "^7.20.0", 37 | "@react-native/metro-config": "^0.72.11", 38 | "@types/chai": "^4.3.11", 39 | "@types/mocha": "^10.0.6", 40 | "babel-plugin-module-resolver": "^5.0.0", 41 | "metro-react-native-babel-preset": "0.76.8", 42 | "pod-install": "^0.1.0" 43 | }, 44 | "engines": { 45 | "node": ">=16" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /example/src/screens/Benchmarks/Benchmarks.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | import * as React from 'react'; 3 | 4 | import { StyleSheet, View, Text, ActivityIndicator, ScrollView } from 'react-native'; 5 | import { startBench } from './bench'; 6 | import { useColorTheme } from '../../components/useColorTheme'; 7 | 8 | export function Benchmarks() { 9 | const [result, setResult] = React.useState<{ 10 | b1: number; 11 | b2: number; 12 | loop: number; 13 | }[]>(); 14 | React.useEffect(() => { 15 | setTimeout(() => { 16 | setResult(startBench()); 17 | }, 100) 18 | }, []); 19 | 20 | const theme = useColorTheme(); 21 | 22 | const textStyle = { 23 | color: theme.colors.text, 24 | } 25 | 26 | return ( 27 | 28 | 29 | 30 | { 31 | result ? 32 | 39 | {result.map((it, index) => 40 | 41 | 42 | LOOP: {it.loop} 43 | polyfill URL: {it.b1.toFixed(2)}ms 44 | FastUrl: {it.b2.toFixed(2)}ms 45 | FastUrl is {(it.b1 / it.b2).toFixed(2)}x faster 46 | 47 | 48 | )} 49 | 50 | 51 | : 52 | 53 | 54 | Running benchmark... 55 | 56 | } 57 | 58 | ); 59 | } 60 | 61 | const styles = StyleSheet.create({ 62 | container: { 63 | flex: 1, 64 | alignItems: 'center', 65 | justifyContent: 'center', 66 | }, 67 | box: { 68 | width: 60, 69 | height: 60, 70 | marginVertical: 20, 71 | }, 72 | }); 73 | -------------------------------------------------------------------------------- /example80/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example2", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "pod": "pod-install", 7 | "android": "react-native run-android", 8 | "ios": "react-native run-ios", 9 | "lint": "eslint .", 10 | "start": "react-native start", 11 | "test": "jest" 12 | }, 13 | "dependencies": { 14 | "@craftzdog/react-native-buffer": "^6.1.0", 15 | "@react-native-community/checkbox": "^0.5.20", 16 | "@react-native/new-app-screen": "0.80.2", 17 | "@react-navigation/native": "^7.1.15", 18 | "@react-navigation/native-stack": "^7.3.22", 19 | "chai": "^5.2.1", 20 | "events": "^3.3.0", 21 | "long": "^5.3.2", 22 | "mocha": "^10.2.0", 23 | "react": "19.1.0", 24 | "react-native": "0.80.2", 25 | "react-native-performance": "^5.1.4", 26 | "react-native-safe-area-context": "^5.5.2", 27 | "react-native-screens": "^4.13.1", 28 | "react-native-url-polyfill": "^2.0.0", 29 | "stream-browserify": "^3.0.0", 30 | "util": "^0.12.5" 31 | }, 32 | "devDependencies": { 33 | "@babel/core": "^7.25.2", 34 | "@babel/plugin-transform-class-static-block": "^7.27.1", 35 | "@babel/preset-env": "^7.25.3", 36 | "@babel/runtime": "^7.25.0", 37 | "@react-native-community/cli": "19.1.1", 38 | "@react-native-community/cli-platform-android": "19.1.1", 39 | "@react-native-community/cli-platform-ios": "19.1.1", 40 | "@react-native/babel-preset": "0.80.2", 41 | "@react-native/eslint-config": "0.80.2", 42 | "@react-native/metro-config": "0.80.2", 43 | "@react-native/typescript-config": "0.80.2", 44 | "@types/chai": "^5.2.2", 45 | "@types/jest": "^29.5.13", 46 | "@types/mocha": "^10.0.10", 47 | "@types/react": "^19.1.0", 48 | "@types/react-test-renderer": "^19.1.0", 49 | "babel-plugin-module-resolver": "^5.0.2", 50 | "eslint": "^8.19.0", 51 | "jest": "^29.6.3", 52 | "prettier": "2.8.8", 53 | "react-test-renderer": "19.1.0", 54 | "typescript": "5.0.4" 55 | }, 56 | "engines": { 57 | "node": ">=18" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/rn_edit_text_material.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 21 | 22 | 23 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m 13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | # Automatically convert third-party libraries to use AndroidX 25 | android.enableJetifier=true 26 | 27 | # Version of flipper SDK to use with React Native 28 | FLIPPER_VERSION=0.182.0 29 | 30 | # Use this property to specify which architecture you want to build. 31 | # You can also override it from the CLI using 32 | # ./gradlew -PreactNativeArchitectures=x86_64 33 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 34 | 35 | # Use this property to enable support to the new architecture. 36 | # This will allow you to use TurboModules and the Fabric render in 37 | # your application. You should enable this flag either if you want 38 | # to write custom TurboModules/Fabric components OR use libraries that 39 | # are providing them. 40 | newArchEnabled=false 41 | 42 | # Use this property to enable or disable the Hermes JS engine. 43 | # If set to false, you will be using JSC instead. 44 | hermesEnabled=true 45 | -------------------------------------------------------------------------------- /example80/android/app/src/main/res/drawable/rn_edit_text_material.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 22 | 23 | 24 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/src/testing/MochaSetup.ts: -------------------------------------------------------------------------------- 1 | import type { RowItemType } from '../screens/Tests/types'; 2 | import { rootSuite, clearTests } from './MochaRnAdapter'; 3 | import 'mocha'; 4 | import type * as MochaTypes from 'mocha'; 5 | 6 | export function testLib( 7 | addTestResult: (testResult: RowItemType) => void, 8 | testRegistrators: Array<() => void> = [] 9 | ) { 10 | console.log('setting up mocha'); 11 | 12 | const { 13 | EVENT_RUN_BEGIN, 14 | EVENT_RUN_END, 15 | EVENT_TEST_FAIL, 16 | EVENT_TEST_PASS, 17 | EVENT_SUITE_BEGIN, 18 | EVENT_SUITE_END, 19 | } = Mocha.Runner.constants; 20 | 21 | clearTests(); 22 | var runner = new Mocha.Runner(rootSuite) as MochaTypes.Runner; 23 | 24 | let indents = -1; 25 | const indent = () => Array(indents).join(' '); 26 | runner 27 | .once(EVENT_RUN_BEGIN, () => {}) 28 | .on(EVENT_SUITE_BEGIN, (suite: MochaTypes.Suite) => { 29 | const name = suite.fullTitle(); 30 | if (name !== '') { 31 | addTestResult({ 32 | indentation: indents, 33 | description: name, 34 | key: Math.random().toString(), 35 | type: 'grouping', 36 | }); 37 | } 38 | indents++; 39 | }) 40 | .on(EVENT_SUITE_END, () => { 41 | indents--; 42 | }) 43 | .on(EVENT_TEST_PASS, (test: MochaTypes.Runnable) => { 44 | addTestResult({ 45 | indentation: indents, 46 | description: test.fullTitle(), 47 | key: Math.random().toString(), 48 | type: 'correct', 49 | }); 50 | console.log(`${indent()}pass: ${test.fullTitle()}`); 51 | }) 52 | .on(EVENT_TEST_FAIL, (test: MochaTypes.Runnable, err: Error) => { 53 | addTestResult({ 54 | indentation: indents, 55 | description: test.fullTitle(), 56 | key: Math.random().toString(), 57 | type: 'incorrect', 58 | errorMsg: err.message, 59 | }); 60 | console.log( 61 | `${indent()}fail: ${test.fullTitle()} - error: ${err.message}` 62 | ); 63 | }) 64 | .once(EVENT_RUN_END, () => {}); 65 | 66 | testRegistrators.forEach((register) => { 67 | register(); 68 | }); 69 | 70 | runner.run(); 71 | 72 | return () => { 73 | console.log('aborting'); 74 | runner.abort(); 75 | }; 76 | } 77 | -------------------------------------------------------------------------------- /example80/src/testing/MochaSetup.ts: -------------------------------------------------------------------------------- 1 | import type { RowItemType } from '../screens/Tests/types'; 2 | import { rootSuite, clearTests } from './MochaRnAdapter'; 3 | import 'mocha'; 4 | import type * as MochaTypes from 'mocha'; 5 | 6 | export function testLib( 7 | addTestResult: (testResult: RowItemType) => void, 8 | testRegistrators: Array<() => void> = [] 9 | ) { 10 | console.log('setting up mocha'); 11 | 12 | const { 13 | EVENT_RUN_BEGIN, 14 | EVENT_RUN_END, 15 | EVENT_TEST_FAIL, 16 | EVENT_TEST_PASS, 17 | EVENT_SUITE_BEGIN, 18 | EVENT_SUITE_END, 19 | } = Mocha.Runner.constants; 20 | 21 | clearTests(); 22 | var runner = new Mocha.Runner(rootSuite) as MochaTypes.Runner; 23 | 24 | let indents = -1; 25 | const indent = () => Array(indents).join(' '); 26 | runner 27 | .once(EVENT_RUN_BEGIN, () => {}) 28 | .on(EVENT_SUITE_BEGIN, (suite: MochaTypes.Suite) => { 29 | const name = suite.fullTitle(); 30 | if (name !== '') { 31 | addTestResult({ 32 | indentation: indents, 33 | description: name, 34 | key: Math.random().toString(), 35 | type: 'grouping', 36 | }); 37 | } 38 | indents++; 39 | }) 40 | .on(EVENT_SUITE_END, () => { 41 | indents--; 42 | }) 43 | .on(EVENT_TEST_PASS, (test: MochaTypes.Runnable) => { 44 | addTestResult({ 45 | indentation: indents, 46 | description: test.fullTitle(), 47 | key: Math.random().toString(), 48 | type: 'correct', 49 | }); 50 | console.log(`${indent()}pass: ${test.fullTitle()}`); 51 | }) 52 | .on(EVENT_TEST_FAIL, (test: MochaTypes.Runnable, err: Error) => { 53 | addTestResult({ 54 | indentation: indents, 55 | description: test.fullTitle(), 56 | key: Math.random().toString(), 57 | type: 'incorrect', 58 | errorMsg: err.message, 59 | }); 60 | console.log( 61 | `${indent()}fail: ${test.fullTitle()} - error: ${err.message}` 62 | ); 63 | }) 64 | .once(EVENT_RUN_END, () => {}); 65 | 66 | testRegistrators.forEach((register) => { 67 | register(); 68 | }); 69 | 70 | runner.run(); 71 | 72 | return () => { 73 | console.log('aborting'); 74 | runner.abort(); 75 | }; 76 | } 77 | -------------------------------------------------------------------------------- /example/ios/FastUrlExampleTests/FastUrlExampleTests.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import 5 | #import 6 | 7 | #define TIMEOUT_SECONDS 600 8 | #define TEXT_TO_LOOK_FOR @"Welcome to React" 9 | 10 | @interface FastUrlExampleTests : XCTestCase 11 | 12 | @end 13 | 14 | @implementation FastUrlExampleTests 15 | 16 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test 17 | { 18 | if (test(view)) { 19 | return YES; 20 | } 21 | for (UIView *subview in [view subviews]) { 22 | if ([self findSubviewInView:subview matching:test]) { 23 | return YES; 24 | } 25 | } 26 | return NO; 27 | } 28 | 29 | - (void)testRendersWelcomeScreen 30 | { 31 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 32 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 33 | BOOL foundElement = NO; 34 | 35 | __block NSString *redboxError = nil; 36 | #ifdef DEBUG 37 | RCTSetLogFunction( 38 | ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 39 | if (level >= RCTLogLevelError) { 40 | redboxError = message; 41 | } 42 | }); 43 | #endif 44 | 45 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 46 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 47 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 48 | 49 | foundElement = [self findSubviewInView:vc.view 50 | matching:^BOOL(UIView *view) { 51 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 52 | return YES; 53 | } 54 | return NO; 55 | }]; 56 | } 57 | 58 | #ifdef DEBUG 59 | RCTSetLogFunction(RCTDefaultLogFunction); 60 | #endif 61 | 62 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 63 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-fast-url 2 | 3 | A Fast URL and URLSearchParams Polyfills for React Native. 4 | 5 | Built in JSI and [ada](https://github.com/ada-url/ada), a WHATWG-compliant and fast URL parser adopted in Node.js since v18.16 for the best performance. 6 | 7 | Tested on RN [0.76](https://github.com/KusStar/react-native-fast-url/tree/main/example), [0.80](https://github.com/KusStar/react-native-fast-url/tree/main/example80), **new architecture** supported(https://github.com/KusStar/react-native-fast-url/pull/9). Thanks to [https://github.com/Doublemme](https://github.com/Doublemme) for the contribution. 8 | 9 | The legecy branch is still available in the [legacy](https://github.com/KusStar/react-native-fast-url/tree/legacy) branch. 10 | 11 | ## Installation 12 | 13 | ```sh 14 | npm install react-native-fast-url 15 | yarn add react-native-fast-url 16 | ``` 17 | 18 | ## Benchmarks 19 | 20 | Compared to [react-native-url-polyfill](https://github.com/charpeni/react-native-url-polyfill/tree/main). 21 | 22 | Run on M1 Pro Mac Catalyst, React Native v0.72.7. 23 | 24 | | | loop 100 | loop 1,000 | loop 10,000 | loop 100,000 | 25 | |---------------------------|------------|------------|------------|------------| 26 | | react-native-url-polyfill | 22ms | 125ms | 1225ms | 12438ms | 27 | | react-native-fast-url | 2ms | 4ms | 35ms | 361ms | 28 | | fast-url is | 12x faster | 35x faster | 36x faster | 34x faster | 29 | 30 | Benchmark code in example: [bench.ts](./example/src/bench.ts) 31 | 32 | This library(Ada) significantly outperforms `react-native-url-polyfill` in terms of speed, fully embracing the WHATWG URL standard and Unicode Standards. However, it's essential to note that Ada's bundle size is larger compared to `react-native-url-polyfill`. The binary size of the Ada C++ library is approximately **500KB**, while `react-native-url-polyfill` is a more compact **73.67KB**. The choice between the two should be based on your specific requirements and preferences. 33 | 34 | ## Usage 35 | 36 | Import the polyfill in your entry file: 37 | 38 | ```js 39 | // index.js 40 | import 'react-native-fast-url/polyfill'; 41 | ``` 42 | 43 | Or if you want to use it only in some files: 44 | 45 | ```js 46 | import { URL, URLSearchParams } from 'react-native-fast-url'; 47 | ``` 48 | 49 | ## Contributing 50 | 51 | See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow. 52 | 53 | ## License 54 | 55 | MIT 56 | 57 | --- 58 | 59 | Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob) 60 | -------------------------------------------------------------------------------- /cpp/fast-url.cpp: -------------------------------------------------------------------------------- 1 | #include "fast-url.h" 2 | 3 | #include "URLHostObjects.h" 4 | 5 | namespace fasturl { 6 | namespace jsi = facebook::jsi; 7 | 8 | void install(jsi::Runtime& rt) { 9 | auto URLSearchParams = HOST_FN(rt, "URLSearchParams", 1, { 10 | if (count != 1) { 11 | return jsi::Value::undefined(); 12 | } 13 | if (!args[0].isString()) { 14 | return jsi::Value::undefined(); 15 | } 16 | std::string params_raw = args[0].asString(rt).utf8(rt); 17 | ada::url_search_params params(params_raw); 18 | 19 | return jsi::Object::createFromHostObject( 20 | rt, std::make_shared( 21 | URLSearchParamsHostObject(params))); 22 | }); 23 | 24 | // URL accepts 1 or 2 arguments, with the second argument being an 25 | // optional "base" string which we need to resolve the url against 26 | auto URL = HOST_FN(rt, "URL", 2, { 27 | if (count < 1 || count > 2) { 28 | return jsi::Value::undefined(); 29 | } 30 | if (!args[0].isString()) { 31 | throw jsi::JSError(rt, 32 | "Failed to construct 'URL': First argument " 33 | "must be a string"); 34 | } 35 | std::string url_raw = args[0].asString(rt).utf8(rt); 36 | 37 | ada::url_aggregator* base_url_ptr = nullptr; 38 | ada::url_aggregator base_url; 39 | 40 | if (count == 2 && !args[1].isUndefined() && args[1].isString()) { 41 | std::string base_raw = args[1].asString(rt).utf8(rt); 42 | auto base_parse_result = 43 | ada::parse(base_raw); 44 | 45 | if (!base_parse_result) { 46 | throw jsi::JSError( 47 | rt, "Failed to construct 'URL': Invalid base URL"); 48 | } 49 | 50 | base_url = base_parse_result.value(); 51 | base_url_ptr = &base_url; 52 | } 53 | 54 | auto url_parse_result = 55 | ada::parse(url_raw, base_url_ptr); 56 | 57 | if (url_parse_result) { 58 | return jsi::Object::createFromHostObject( 59 | rt, std::make_shared( 60 | URLHostObject(url_parse_result.value()))); 61 | } else { 62 | throw jsi::JSError(rt, 63 | "Failed to construct 'URL': Invalid URL"); 64 | } 65 | 66 | return jsi::Value::undefined(); 67 | }); 68 | 69 | jsi::Object module = jsi::Object(rt); 70 | 71 | module.setProperty(rt, "URLSearchParams", std::move(URLSearchParams)); 72 | module.setProperty(rt, "URL", std::move(URL)); 73 | 74 | rt.global().setProperty(rt, "__FastUrl", std::move(module)); 75 | } 76 | } // namespace fasturl 77 | -------------------------------------------------------------------------------- /example/src/screens/Tests/Tests.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useCallback, useRef, useEffect } from 'react'; 2 | import type { NativeStackScreenProps } from '@react-navigation/native-stack'; 3 | import { View, ScrollView, StyleSheet } from 'react-native'; 4 | import { testLib } from '../../testing/MochaSetup'; 5 | import { CorrectResultItem } from '../../components/CorrectResultItem'; 6 | import { IncorrectResultItem } from '../../components/IncorrectResultItem'; 7 | import { Suite } from '../../components/Suite'; 8 | import { Indentator } from '../../components/Indentator'; 9 | import type { RowItemType } from './types'; 10 | import type { RootStackParamList } from '../params'; 11 | 12 | function useTestRows(): [RowItemType[], (newResult: RowItemType) => void] { 13 | const [rows, setRows] = useState([]); 14 | 15 | let viewIsMounted = useRef(true); 16 | 17 | useEffect(() => { 18 | return () => { 19 | viewIsMounted.current = false; 20 | }; 21 | }, []); 22 | 23 | const addResult = useCallback( 24 | (newResult: RowItemType) => { 25 | if (!viewIsMounted.current) { 26 | return; 27 | } 28 | setRows((prevRows) => { 29 | prevRows.push(newResult); 30 | return [...prevRows]; // had to copy to trigger rerender 31 | }); 32 | }, 33 | [setRows] 34 | ); 35 | 36 | return [rows, addResult]; 37 | } 38 | 39 | type TestingScreenProps = NativeStackScreenProps; 40 | 41 | export function Tests({ route }: TestingScreenProps) { 42 | const { testRegistrators } = route.params; 43 | const [rows, addRow] = useTestRows(); 44 | 45 | useEffect(() => { 46 | const abort = testLib(addRow, testRegistrators); 47 | return () => { 48 | abort(); 49 | }; 50 | }, [addRow, testRegistrators]); 51 | 52 | return ( 53 | 54 | 55 | {rows.map((it) => { 56 | let InnerElement = ; 57 | if (it.type === 'correct') { 58 | InnerElement = ; 59 | } 60 | if (it.type === 'incorrect') { 61 | const errorMsg = it.errorMsg || ''; // Trick TS - How to do it as it should be? :) 62 | InnerElement = ( 63 | 67 | ); 68 | } 69 | if (it.type === 'grouping') { 70 | InnerElement = ; 71 | } 72 | return ( 73 | 74 | {InnerElement} 75 | 76 | ); 77 | })} 78 | 79 | 80 | ); 81 | } 82 | 83 | const styles = StyleSheet.create({ 84 | mainContainer: { 85 | flex: 1, 86 | backgroundColor: 'white', 87 | }, 88 | testList: { 89 | flex: 9, 90 | }, 91 | menu: { 92 | flex: 1, 93 | alignItems: 'center', 94 | alignContent: 'center', 95 | justifyContent: 'center', 96 | }, 97 | scroll: {}, 98 | }); 99 | -------------------------------------------------------------------------------- /example80/src/screens/Tests/Tests.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useCallback, useRef, useEffect } from 'react'; 2 | import type { NativeStackScreenProps } from '@react-navigation/native-stack'; 3 | import { View, ScrollView, StyleSheet } from 'react-native'; 4 | import { testLib } from '../../testing/MochaSetup'; 5 | import { CorrectResultItem } from '../../components/CorrectResultItem'; 6 | import { IncorrectResultItem } from '../../components/IncorrectResultItem'; 7 | import { Suite } from '../../components/Suite'; 8 | import { Indentator } from '../../components/Indentator'; 9 | import type { RowItemType } from './types'; 10 | import type { RootStackParamList } from '../params'; 11 | 12 | function useTestRows(): [RowItemType[], (newResult: RowItemType) => void] { 13 | const [rows, setRows] = useState([]); 14 | 15 | let viewIsMounted = useRef(true); 16 | 17 | useEffect(() => { 18 | return () => { 19 | viewIsMounted.current = false; 20 | }; 21 | }, []); 22 | 23 | const addResult = useCallback( 24 | (newResult: RowItemType) => { 25 | if (!viewIsMounted.current) { 26 | return; 27 | } 28 | setRows((prevRows) => { 29 | prevRows.push(newResult); 30 | return [...prevRows]; // had to copy to trigger rerender 31 | }); 32 | }, 33 | [setRows] 34 | ); 35 | 36 | return [rows, addResult]; 37 | } 38 | 39 | type TestingScreenProps = NativeStackScreenProps; 40 | 41 | export function Tests({ route }: TestingScreenProps) { 42 | const { testRegistrators } = route.params; 43 | const [rows, addRow] = useTestRows(); 44 | 45 | useEffect(() => { 46 | const abort = testLib(addRow, testRegistrators); 47 | return () => { 48 | abort(); 49 | }; 50 | }, [addRow, testRegistrators]); 51 | 52 | return ( 53 | 54 | 55 | {rows.map((it) => { 56 | let InnerElement = ; 57 | if (it.type === 'correct') { 58 | InnerElement = ; 59 | } 60 | if (it.type === 'incorrect') { 61 | const errorMsg = it.errorMsg || ''; // Trick TS - How to do it as it should be? :) 62 | InnerElement = ( 63 | 67 | ); 68 | } 69 | if (it.type === 'grouping') { 70 | InnerElement = ; 71 | } 72 | return ( 73 | 74 | {InnerElement} 75 | 76 | ); 77 | })} 78 | 79 | 80 | ); 81 | } 82 | 83 | const styles = StyleSheet.create({ 84 | mainContainer: { 85 | flex: 1, 86 | backgroundColor: 'white', 87 | }, 88 | testList: { 89 | flex: 9, 90 | }, 91 | menu: { 92 | flex: 1, 93 | alignItems: 'center', 94 | alignContent: 'center', 95 | justifyContent: 'center', 96 | }, 97 | scroll: {}, 98 | }); 99 | -------------------------------------------------------------------------------- /example/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli). 2 | 3 | # Getting Started 4 | 5 | >**Note**: Make sure you have completed the [React Native - Environment Setup](https://reactnative.dev/docs/environment-setup) instructions till "Creating a new application" step, before proceeding. 6 | 7 | ## Step 1: Start the Metro Server 8 | 9 | First, you will need to start **Metro**, the JavaScript _bundler_ that ships _with_ React Native. 10 | 11 | To start Metro, run the following command from the _root_ of your React Native project: 12 | 13 | ```bash 14 | export RCT_NEW_ARCH_ENABLED=0 15 | # using npm 16 | npm start 17 | 18 | # OR using Yarn 19 | yarn start 20 | ``` 21 | 22 | ## Step 2: Start your Application 23 | 24 | Let Metro Bundler run in its _own_ terminal. Open a _new_ terminal from the _root_ of your React Native project. Run the following command to start your _Android_ or _iOS_ app: 25 | 26 | ### For Android 27 | 28 | ```bash 29 | # using npm 30 | npm run android 31 | 32 | # OR using Yarn 33 | yarn android 34 | ``` 35 | 36 | ### For iOS 37 | 38 | ```bash 39 | # using npm 40 | npm run ios 41 | 42 | # OR using Yarn 43 | yarn ios 44 | ``` 45 | 46 | If everything is set up _correctly_, you should see your new app running in your _Android Emulator_ or _iOS Simulator_ shortly provided you have set up your emulator/simulator correctly. 47 | 48 | This is one way to run your app — you can also run it directly from within Android Studio and Xcode respectively. 49 | 50 | ## Step 3: Modifying your App 51 | 52 | Now that you have successfully run the app, let's modify it. 53 | 54 | 1. Open `App.tsx` in your text editor of choice and edit some lines. 55 | 2. For **Android**: Press the R key twice or select **"Reload"** from the **Developer Menu** (Ctrl + M (on Window and Linux) or Cmd ⌘ + M (on macOS)) to see your changes! 56 | 57 | For **iOS**: Hit Cmd ⌘ + R in your iOS Simulator to reload the app and see your changes! 58 | 59 | ## Congratulations! :tada: 60 | 61 | You've successfully run and modified your React Native App. :partying_face: 62 | 63 | ### Now what? 64 | 65 | - If you want to add this new React Native code to an existing application, check out the [Integration guide](https://reactnative.dev/docs/integration-with-existing-apps). 66 | - If you're curious to learn more about React Native, check out the [Introduction to React Native](https://reactnative.dev/docs/getting-started). 67 | 68 | # Troubleshooting 69 | 70 | If you can't get this to work, see the [Troubleshooting](https://reactnative.dev/docs/troubleshooting) page. 71 | 72 | # Learn More 73 | 74 | To learn more about React Native, take a look at the following resources: 75 | 76 | - [React Native Website](https://reactnative.dev) - learn more about React Native. 77 | - [Getting Started](https://reactnative.dev/docs/environment-setup) - an **overview** of React Native and how setup your environment. 78 | - [Learn the Basics](https://reactnative.dev/docs/getting-started) - a **guided tour** of the React Native **basics**. 79 | - [Blog](https://reactnative.dev/blog) - read the latest official React Native **Blog** posts. 80 | - [`@facebook/react-native`](https://github.com/facebook/react-native) - the Open Source; GitHub **repository** for React Native. 81 | -------------------------------------------------------------------------------- /example/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.7) 5 | base64 6 | nkf 7 | rexml 8 | activesupport (7.1.5.1) 9 | base64 10 | benchmark (>= 0.3) 11 | bigdecimal 12 | concurrent-ruby (~> 1.0, >= 1.0.2) 13 | connection_pool (>= 2.2.5) 14 | drb 15 | i18n (>= 1.6, < 2) 16 | logger (>= 1.4.2) 17 | minitest (>= 5.1) 18 | mutex_m 19 | securerandom (>= 0.3) 20 | tzinfo (~> 2.0) 21 | addressable (2.8.7) 22 | public_suffix (>= 2.0.2, < 7.0) 23 | algoliasearch (1.27.5) 24 | httpclient (~> 2.8, >= 2.8.3) 25 | json (>= 1.5.1) 26 | atomos (0.1.3) 27 | base64 (0.3.0) 28 | benchmark (0.4.1) 29 | bigdecimal (3.2.2) 30 | claide (1.1.0) 31 | cocoapods (1.15.2) 32 | addressable (~> 2.8) 33 | claide (>= 1.0.2, < 2.0) 34 | cocoapods-core (= 1.15.2) 35 | cocoapods-deintegrate (>= 1.0.3, < 2.0) 36 | cocoapods-downloader (>= 2.1, < 3.0) 37 | cocoapods-plugins (>= 1.0.0, < 2.0) 38 | cocoapods-search (>= 1.0.0, < 2.0) 39 | cocoapods-trunk (>= 1.6.0, < 2.0) 40 | cocoapods-try (>= 1.1.0, < 2.0) 41 | colored2 (~> 3.1) 42 | escape (~> 0.0.4) 43 | fourflusher (>= 2.3.0, < 3.0) 44 | gh_inspector (~> 1.0) 45 | molinillo (~> 0.8.0) 46 | nap (~> 1.0) 47 | ruby-macho (>= 2.3.0, < 3.0) 48 | xcodeproj (>= 1.23.0, < 2.0) 49 | cocoapods-core (1.15.2) 50 | activesupport (>= 5.0, < 8) 51 | addressable (~> 2.8) 52 | algoliasearch (~> 1.0) 53 | concurrent-ruby (~> 1.1) 54 | fuzzy_match (~> 2.0.4) 55 | nap (~> 1.0) 56 | netrc (~> 0.11) 57 | public_suffix (~> 4.0) 58 | typhoeus (~> 1.0) 59 | cocoapods-deintegrate (1.0.5) 60 | cocoapods-downloader (2.1) 61 | cocoapods-plugins (1.0.0) 62 | nap 63 | cocoapods-search (1.0.1) 64 | cocoapods-trunk (1.6.0) 65 | nap (>= 0.8, < 2.0) 66 | netrc (~> 0.11) 67 | cocoapods-try (1.2.0) 68 | colored2 (3.1.2) 69 | concurrent-ruby (1.3.3) 70 | connection_pool (2.5.3) 71 | drb (2.2.3) 72 | escape (0.0.4) 73 | ethon (0.16.0) 74 | ffi (>= 1.15.0) 75 | ffi (1.17.2) 76 | fourflusher (2.3.1) 77 | fuzzy_match (2.0.4) 78 | gh_inspector (1.1.3) 79 | httpclient (2.9.0) 80 | mutex_m 81 | i18n (1.14.7) 82 | concurrent-ruby (~> 1.0) 83 | json (2.13.1) 84 | logger (1.7.0) 85 | minitest (5.25.5) 86 | molinillo (0.8.0) 87 | mutex_m (0.3.0) 88 | nanaimo (0.3.0) 89 | nap (1.1.0) 90 | netrc (0.11.0) 91 | nkf (0.2.0) 92 | public_suffix (4.0.7) 93 | rexml (3.4.1) 94 | ruby-macho (2.5.1) 95 | securerandom (0.3.2) 96 | typhoeus (1.4.1) 97 | ethon (>= 0.9.0) 98 | tzinfo (2.0.6) 99 | concurrent-ruby (~> 1.0) 100 | xcodeproj (1.25.1) 101 | CFPropertyList (>= 2.3.3, < 4.0) 102 | atomos (~> 0.1.3) 103 | claide (>= 1.0.2, < 2.0) 104 | colored2 (~> 3.1) 105 | nanaimo (~> 0.3.0) 106 | rexml (>= 3.3.6, < 4.0) 107 | 108 | PLATFORMS 109 | ruby 110 | 111 | DEPENDENCIES 112 | activesupport (>= 6.1.7.5, != 7.1.0) 113 | cocoapods (>= 1.13, != 1.15.1, != 1.15.0) 114 | concurrent-ruby (< 1.3.4) 115 | xcodeproj (< 1.26.0) 116 | 117 | RUBY VERSION 118 | ruby 2.7.5p203 119 | 120 | BUNDLED WITH 121 | 2.4.22 122 | -------------------------------------------------------------------------------- /example80/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @REM Copyright (c) Meta Platforms, Inc. and affiliates. 2 | @REM 3 | @REM This source code is licensed under the MIT license found in the 4 | @REM LICENSE file in the root directory of this source tree. 5 | 6 | @rem 7 | @rem Copyright 2015 the original author or authors. 8 | @rem 9 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 10 | @rem you may not use this file except in compliance with the License. 11 | @rem You may obtain a copy of the License at 12 | @rem 13 | @rem https://www.apache.org/licenses/LICENSE-2.0 14 | @rem 15 | @rem Unless required by applicable law or agreed to in writing, software 16 | @rem distributed under the License is distributed on an "AS IS" BASIS, 17 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | @rem See the License for the specific language governing permissions and 19 | @rem limitations under the License. 20 | @rem 21 | @rem SPDX-License-Identifier: Apache-2.0 22 | @rem 23 | 24 | @if "%DEBUG%"=="" @echo off 25 | @rem ########################################################################## 26 | @rem 27 | @rem Gradle startup script for Windows 28 | @rem 29 | @rem ########################################################################## 30 | 31 | @rem Set local scope for the variables with windows NT shell 32 | if "%OS%"=="Windows_NT" setlocal 33 | 34 | set DIRNAME=%~dp0 35 | if "%DIRNAME%"=="" set DIRNAME=. 36 | @rem This is normally unused 37 | set APP_BASE_NAME=%~n0 38 | set APP_HOME=%DIRNAME% 39 | 40 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 41 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 42 | 43 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 44 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 45 | 46 | @rem Find java.exe 47 | if defined JAVA_HOME goto findJavaFromJavaHome 48 | 49 | set JAVA_EXE=java.exe 50 | %JAVA_EXE% -version >NUL 2>&1 51 | if %ERRORLEVEL% equ 0 goto execute 52 | 53 | echo. 1>&2 54 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 55 | echo. 1>&2 56 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 57 | echo location of your Java installation. 1>&2 58 | 59 | goto fail 60 | 61 | :findJavaFromJavaHome 62 | set JAVA_HOME=%JAVA_HOME:"=% 63 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 64 | 65 | if exist "%JAVA_EXE%" goto execute 66 | 67 | echo. 1>&2 68 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 69 | echo. 1>&2 70 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 71 | echo location of your Java installation. 1>&2 72 | 73 | goto fail 74 | 75 | :execute 76 | @rem Setup the command line 77 | 78 | set CLASSPATH= 79 | 80 | 81 | @rem Execute Gradle 82 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 83 | 84 | :end 85 | @rem End local scope for the variables with windows NT shell 86 | if %ERRORLEVEL% equ 0 goto mainEnd 87 | 88 | :fail 89 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 90 | rem the _cmd.exe /c_ return code! 91 | set EXIT_CODE=%ERRORLEVEL% 92 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 93 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 94 | exit /b %EXIT_CODE% 95 | 96 | :mainEnd 97 | if "%OS%"=="Windows_NT" endlocal 98 | 99 | :omega 100 | -------------------------------------------------------------------------------- /example80/ios/example2.xcodeproj/xcshareddata/xcschemes/example2.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 55 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /example/src/screens/Home.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useCallback } from 'react'; 2 | import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; 3 | import { View, ScrollView, StyleSheet } from 'react-native'; 4 | import { useNavigation } from '@react-navigation/native'; 5 | import type { TestItemType } from './Tests/types'; 6 | import { TEST_LIST } from './Tests/testList'; 7 | import { TestItem } from '../components/TestItem'; 8 | import { Button } from '../components/Button'; 9 | import type { RootStackParamList } from './params'; 10 | import { useColorTheme } from '../components/useColorTheme'; 11 | 12 | const useTests = (): [ 13 | Array, 14 | (index: number) => void, 15 | () => void, 16 | () => void 17 | ] => { 18 | const [tests, setTests] = useState>(TEST_LIST); 19 | 20 | const toggle = useCallback( 21 | (index: number) => { 22 | setTests((tests) => { 23 | // @ts-expect-error 24 | tests[index].value = !tests[index].value; 25 | return [...tests]; 26 | }); 27 | }, 28 | [setTests] 29 | ); 30 | 31 | const clearAll = useCallback(() => { 32 | setTests((tests) => { 33 | return tests.map((it) => { 34 | it.value = false; 35 | return it; 36 | }); 37 | }); 38 | }, [setTests]); 39 | 40 | const checkAll = useCallback(() => { 41 | setTests((tests) => { 42 | return tests.map((it) => { 43 | it.value = true; 44 | return it; 45 | }); 46 | }); 47 | }, [setTests]); 48 | 49 | return [tests, toggle, clearAll, checkAll]; 50 | }; 51 | 52 | export function Home() { 53 | const theme = useColorTheme(); 54 | const [tests, toggle, clearAll, checkAll] = useTests(); 55 | const navigation = 56 | useNavigation>(); 57 | 58 | return ( 59 | 67 | 68 | 69 | {tests.map((test, index: number) => ( 70 | 77 | ))} 78 | 79 | 80 | 81 |