react-native-ariel 0.1.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Ariel.podspec +44 -0
- package/LICENSE +20 -0
- package/README.md +349 -0
- package/android/CMakeLists.txt +79 -0
- package/android/build.gradle +144 -0
- package/android/cpp-adapter.cpp +43 -0
- package/android/generated/android/app/build/generated/source/codegen/java/com/facebook/fbreact/specs/NativeArielSpec.java +41 -0
- package/android/generated/android/app/build/generated/source/codegen/jni/ArielSpec-generated.cpp +38 -0
- package/android/generated/android/app/build/generated/source/codegen/jni/ArielSpec.h +31 -0
- package/android/generated/android/app/build/generated/source/codegen/jni/CMakeLists.txt +28 -0
- package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/ArielSpec/ArielSpecJSI.h +45 -0
- package/android/src/main/AndroidManifest.xml +5 -0
- package/android/src/main/java/com/ariel/ArielModule.kt +43 -0
- package/android/src/main/java/com/ariel/ArielPackage.kt +34 -0
- package/android/src/main/jniLibs/arm64-v8a/libmermaid_wrapper.a +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libmermaid_wrapper.a +0 -0
- package/android/src/main/jniLibs/x86/libmermaid_wrapper.a +0 -0
- package/android/src/main/jniLibs/x86_64/libmermaid_wrapper.a +0 -0
- package/cpp/mermaid_wrapper.cpp +2368 -0
- package/cpp/mermaid_wrapper.hpp +77 -0
- package/cpp/react-native-ariel.cpp +16 -0
- package/cpp/react-native-ariel.h +15 -0
- package/ios/Ariel.h +16 -0
- package/ios/Ariel.mm +66 -0
- package/ios/generated/build/generated/ios/ReactCodegen/ArielSpec/ArielSpec-generated.mm +46 -0
- package/ios/generated/build/generated/ios/ReactCodegen/ArielSpec/ArielSpec.h +63 -0
- package/ios/generated/build/generated/ios/ReactCodegen/ArielSpecJSI.h +45 -0
- package/lib/module/NativeAriel.js +7 -0
- package/lib/module/NativeAriel.js.map +1 -0
- package/lib/module/generated/rn/mermaid_wrapper-ffi.js +47 -0
- package/lib/module/generated/rn/mermaid_wrapper-ffi.js.map +1 -0
- package/lib/module/generated/rn/mermaid_wrapper.js +487 -0
- package/lib/module/generated/rn/mermaid_wrapper.js.map +1 -0
- package/lib/module/generated/web/mermaid_wrapper.js +532 -0
- package/lib/module/generated/web/mermaid_wrapper.js.map +1 -0
- package/lib/module/index.js +43 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/index.web.js +28 -0
- package/lib/module/index.web.js.map +2 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeAriel.d.ts +8 -0
- package/lib/typescript/src/NativeAriel.d.ts.map +1 -0
- package/lib/typescript/src/generated/rn/mermaid_wrapper-ffi.d.ts +102 -0
- package/lib/typescript/src/generated/rn/mermaid_wrapper-ffi.d.ts.map +1 -0
- package/lib/typescript/src/generated/rn/mermaid_wrapper.d.ts +291 -0
- package/lib/typescript/src/generated/rn/mermaid_wrapper.d.ts.map +1 -0
- package/lib/typescript/src/generated/web/mermaid_wrapper.d.ts +291 -0
- package/lib/typescript/src/generated/web/mermaid_wrapper.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +8 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/index.web.d.ts +8 -0
- package/lib/typescript/src/index.web.d.ts.map +1 -0
- package/package.json +146 -0
- package/react-native.config.js +15 -0
- package/src/NativeAriel.ts +10 -0
- package/src/generated/rn/mermaid_wrapper-ffi.ts +161 -0
- package/src/generated/rn/mermaid_wrapper.ts +765 -0
- package/src/generated/web/mermaid_wrapper.ts +771 -0
- package/src/index.tsx +41 -0
- package/src/index.web.ts +26 -0
- package/src/index.web.tsx +17 -0
package/Ariel.podspec
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Generated by uniffi-bindgen-react-native
|
|
2
|
+
require "json"
|
|
3
|
+
|
|
4
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
5
|
+
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
|
|
6
|
+
|
|
7
|
+
Pod::Spec.new do |s|
|
|
8
|
+
s.name = "Ariel"
|
|
9
|
+
s.version = package["version"]
|
|
10
|
+
s.summary = package["description"]
|
|
11
|
+
s.homepage = package["homepage"]
|
|
12
|
+
s.license = package["license"]
|
|
13
|
+
s.authors = package["author"]
|
|
14
|
+
|
|
15
|
+
s.platforms = { :ios => min_ios_version_supported }
|
|
16
|
+
s.source = { :git => "https://github.com/rinfi/ariel.git", :tag => "#{s.version}" }
|
|
17
|
+
|
|
18
|
+
s.source_files = "ios/**/*.{h,m,mm,swift}", "ios/generated/**/*.{h,m,mm}", "cpp/**/*.{hpp,cpp,c,h}", "cpp/generated/**/*.{hpp,cpp,c,h}"
|
|
19
|
+
s.vendored_frameworks = "ArielFramework.xcframework"
|
|
20
|
+
s.dependency "uniffi-bindgen-react-native", "0.31.0-2"
|
|
21
|
+
|
|
22
|
+
# Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
|
|
23
|
+
# See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
|
|
24
|
+
if respond_to?(:install_modules_dependencies, true)
|
|
25
|
+
install_modules_dependencies(s)
|
|
26
|
+
else
|
|
27
|
+
s.dependency "React-Core"
|
|
28
|
+
|
|
29
|
+
# Don't install the dependencies when we run `pod install` in the old architecture.
|
|
30
|
+
if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
|
|
31
|
+
s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
|
|
32
|
+
s.pod_target_xcconfig = {
|
|
33
|
+
"HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
|
|
34
|
+
"OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
|
|
35
|
+
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
|
|
36
|
+
}
|
|
37
|
+
s.dependency "React-Codegen"
|
|
38
|
+
s.dependency "RCT-Folly"
|
|
39
|
+
s.dependency "RCTRequired"
|
|
40
|
+
s.dependency "RCTTypeSafety"
|
|
41
|
+
s.dependency "ReactCommon/turbomodule/core"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rochanglien Infimate
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# Ariel
|
|
2
|
+
|
|
3
|
+
> **Mermaid diagrams for React Native and React Native Web. No DOM. No WebView. Pure Rust.**
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/react-native-ariel)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## Why Ariel?
|
|
10
|
+
|
|
11
|
+
Every other Mermaid solution for React Native requires a DOM, a WebView, or a headless browser. That means slow startup, heavy bundles, and broken native builds.
|
|
12
|
+
|
|
13
|
+
**Ariel** wraps [mermaid-rs-renderer](https://github.com/1jehuang/mermaid-rs-renderer) — a pure Rust Mermaid engine 500–2000× faster than mermaid-cli — as a React Native Turbo Module. The Rust code compiles natively for iOS and Android, and to WASM for the browser. No DOM. No WebView. Works fully offline.
|
|
14
|
+
|
|
15
|
+
| | Ariel | mermaid.js | mermaid-cli |
|
|
16
|
+
|---|:---:|:---:|:---:|
|
|
17
|
+
| iOS native | ✅ | ❌ | ❌ |
|
|
18
|
+
| Android native | ✅ | ❌ | ❌ |
|
|
19
|
+
| Web (WASM) | ✅ | ✅ | ❌ |
|
|
20
|
+
| No DOM | ✅ | ❌ | ❌ |
|
|
21
|
+
| No WebView | ✅ | ❌ | ❌ |
|
|
22
|
+
| Offline | ✅ | ⚠️ | ❌ |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
yarn add react-native-ariel react-native-svg
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
> **Note:** Ariel uses custom native code and requires [Expo Dev Client](https://docs.expo.dev/develop/development-builds/introduction/) — it does not work with Expo Go.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
### Simple render
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { renderMermaid } from 'react-native-ariel';
|
|
42
|
+
import { SvgXml } from 'react-native-svg';
|
|
43
|
+
|
|
44
|
+
const svg = renderMermaid('flowchart TD\n A[Hello] --> B[World]');
|
|
45
|
+
|
|
46
|
+
<SvgXml xml={svg} width="100%" />
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### With theme and layout control
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { renderMermaidWithOptions, ArielTheme } from 'react-native-ariel';
|
|
53
|
+
|
|
54
|
+
const theme = ArielTheme.modern(); // or ArielTheme.mermaidDefault()
|
|
55
|
+
const config = { nodeSpacing: 50, rankSpacing: 80, aspectRatioHint: null };
|
|
56
|
+
|
|
57
|
+
const svg = renderMermaidWithOptions(diagram, theme, config);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### With timing metrics
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { renderMermaidWithTiming, ArielTheme } from 'react-native-ariel';
|
|
64
|
+
|
|
65
|
+
const result = renderMermaidWithTiming(diagram, ArielTheme.modern(), config);
|
|
66
|
+
console.log(`Total: ${result.totalMs.toFixed(2)}ms`);
|
|
67
|
+
// Parse: 420µs Layout: 610µs Render: 200µs
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Full pipeline (parse once, render with multiple themes)
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import {
|
|
74
|
+
parseDiagram,
|
|
75
|
+
computeDiagramLayout,
|
|
76
|
+
renderSvgFromLayout,
|
|
77
|
+
ArielTheme,
|
|
78
|
+
} from 'react-native-ariel';
|
|
79
|
+
|
|
80
|
+
const parsed = parseDiagram('flowchart LR\n A --> B --> C');
|
|
81
|
+
const layout = computeDiagramLayout(parsed, ArielTheme.modern(), config);
|
|
82
|
+
const svg = renderSvgFromLayout(layout, ArielTheme.modern(), config);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Debug timing logs
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { setTimingLogs } from 'react-native-ariel';
|
|
89
|
+
|
|
90
|
+
setTimingLogs(true); // off by default
|
|
91
|
+
// → [Ariel] flowchart TD… | total 1.23ms parse 420µs layout 610µs render 200µs
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Logs are written to **Android Logcat**, the **Xcode console** on iOS, and the **browser DevTools console** on web (WASM timings are always zero).
|
|
95
|
+
|
|
96
|
+
> **Note:** When timing is on, every render call allocates a format string regardless of whether you can see the output. This is cheap but not free. The flag is intended for debugging — avoid shipping with `setTimingLogs(true)` hardcoded.
|
|
97
|
+
|
|
98
|
+
### Web (WASM) initialisation
|
|
99
|
+
|
|
100
|
+
On web, call `uniffiInitAsync` before any render calls:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { uniffiInitAsync } from 'react-native-ariel';
|
|
104
|
+
|
|
105
|
+
uniffiInitAsync().then(() => {
|
|
106
|
+
// safe to call renderMermaid here
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## API
|
|
113
|
+
|
|
114
|
+
| Function | Description |
|
|
115
|
+
|---|---|
|
|
116
|
+
| `renderMermaid(input)` | Render to SVG with default options |
|
|
117
|
+
| `renderMermaidWithOptions(input, theme, config)` | Render with theme and layout control |
|
|
118
|
+
| `renderMermaidWithTiming(input, theme, config)` | Render and return SVG + timing metrics |
|
|
119
|
+
| `parseDiagram(input)` | Parse only — returns opaque `ArielParsedDiagram` |
|
|
120
|
+
| `computeDiagramLayout(parsed, theme, config)` | Layout stage — returns opaque `ArielLayout` |
|
|
121
|
+
| `renderSvgFromLayout(layout, theme, config)` | SVG stage from pre-computed layout |
|
|
122
|
+
| `setTimingLogs(enabled)` | Toggle timing output to console (default: off) |
|
|
123
|
+
| `ArielTheme.modern()` | Modern theme — see below |
|
|
124
|
+
| `ArielTheme.mermaidDefault()` | Classic Mermaid theme — see below |
|
|
125
|
+
|
|
126
|
+
### Themes
|
|
127
|
+
|
|
128
|
+
Two built-in themes are available. Both are static constructors on `ArielTheme`:
|
|
129
|
+
|
|
130
|
+
**`ArielTheme.modern()`**
|
|
131
|
+
A clean, contemporary look with high-contrast shapes and softer typography. Good default for light-background UIs. Produces compact, well-spaced diagrams.
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const svg = renderMermaidWithOptions(diagram, ArielTheme.modern(), config);
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**`ArielTheme.mermaidDefault()`**
|
|
138
|
+
Reproduces the classic mermaid.js appearance — familiar to anyone who has used Mermaid in Markdown or documentation tools. Useful when you need visual parity with existing mermaid.js output.
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
const svg = renderMermaidWithOptions(diagram, ArielTheme.mermaidDefault(), config);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
> These are the only two themes currently exposed by [mermaid-rs-renderer](https://github.com/1jehuang/mermaid-rs-renderer). Custom theme colours are not yet supported.
|
|
145
|
+
|
|
146
|
+
### `ArielLayoutConfig`
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
{
|
|
150
|
+
nodeSpacing?: number | null;
|
|
151
|
+
rankSpacing?: number | null;
|
|
152
|
+
aspectRatioHint?: number | null;
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### `ArielRenderResult`
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
{
|
|
160
|
+
svg: string;
|
|
161
|
+
parseUs: number;
|
|
162
|
+
layoutUs: number;
|
|
163
|
+
renderUs: number;
|
|
164
|
+
totalMs: number;
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Dev Setup
|
|
171
|
+
|
|
172
|
+
### Prerequisites
|
|
173
|
+
|
|
174
|
+
| Tool | Purpose | Install |
|
|
175
|
+
|---|---|---|
|
|
176
|
+
| [Rust](https://rustup.rs) | Compile the Rust crate | `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \| sh` |
|
|
177
|
+
| [Node.js](https://nodejs.org) ≥ 20 | JS toolchain | nodejs.org |
|
|
178
|
+
| Yarn | Package manager | `npm i -g yarn` |
|
|
179
|
+
| [Android Studio](https://developer.android.com/studio) | Android SDK + NDK | See below |
|
|
180
|
+
| Xcode ≥ 15 | iOS builds (macOS only) | Mac App Store |
|
|
181
|
+
| [cargo-ndk](https://github.com/bbqsrc/cargo-ndk) | Android cross-compilation | `cargo install cargo-ndk` |
|
|
182
|
+
| [wasm-pack](https://rustwasm.github.io/wasm-pack/) | WASM builds | `cargo install wasm-pack` |
|
|
183
|
+
|
|
184
|
+
**Android NDK:** Open Android Studio → SDK Manager → SDK Tools tab → check **NDK (Side by side)** → Apply.
|
|
185
|
+
|
|
186
|
+
**Rust targets** — run once after installing Rust:
|
|
187
|
+
|
|
188
|
+
```sh
|
|
189
|
+
# Android
|
|
190
|
+
rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android i686-linux-android
|
|
191
|
+
|
|
192
|
+
# iOS
|
|
193
|
+
rustup target add aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim
|
|
194
|
+
|
|
195
|
+
# Web
|
|
196
|
+
rustup target add wasm32-unknown-unknown
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Clone and install
|
|
200
|
+
|
|
201
|
+
```sh
|
|
202
|
+
git clone https://github.com/rinfi/ariel.git
|
|
203
|
+
cd ariel
|
|
204
|
+
yarn
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Building
|
|
210
|
+
|
|
211
|
+
### Generate TypeScript bindings
|
|
212
|
+
|
|
213
|
+
Before building for any platform you need to generate the TypeScript and C++ bindings from the Rust source. This compiles the crate for your **host OS** (not a cross-compile target) so the code-generator can introspect it.
|
|
214
|
+
|
|
215
|
+
```sh
|
|
216
|
+
yarn ubrn:generate
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
This works on **Windows**, **macOS**, and **Linux** and writes to `src/generated/rn/` and `cpp/`. Re-run it whenever you change the Rust API.
|
|
220
|
+
|
|
221
|
+
> **Windows note:** `ubrn build android --and-generate` tries to invoke `prettier` as a bare executable, which fails on Windows (error 193 — the Unix shell script can't run as a Win32 app). `yarn ubrn:generate` bypasses this by building the host DLL directly and passing `--no-format`.
|
|
222
|
+
|
|
223
|
+
### Android
|
|
224
|
+
|
|
225
|
+
Compiles the Rust crate for all Android ABIs and places `.a` / `.so` files under `android/src/main/jniLibs/`. Run `yarn ubrn:generate` first if you haven't already.
|
|
226
|
+
|
|
227
|
+
```sh
|
|
228
|
+
yarn ubrn:generate # generates src/generated/rn/ and cpp/
|
|
229
|
+
yarn ubrn:android # compiles for arm64-v8a, armeabi-v7a, x86_64, x86
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### iOS (macOS only)
|
|
233
|
+
|
|
234
|
+
Compiles for device + simulator and runs `pod install`. Run `yarn ubrn:generate` first.
|
|
235
|
+
|
|
236
|
+
```sh
|
|
237
|
+
yarn ubrn:generate # generates src/generated/rn/ and cpp/
|
|
238
|
+
yarn ubrn:ios # compiles for aarch64-apple-ios, x86_64-apple-ios, aarch64-apple-ios-sim
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Web (WASM)
|
|
242
|
+
|
|
243
|
+
Compiles to `wasm32-unknown-unknown` and produces a `.wasm` bundle under `src/generated/web/`. Run `yarn ubrn:generate` first.
|
|
244
|
+
|
|
245
|
+
```sh
|
|
246
|
+
yarn ubrn:generate # generates src/generated/web/ (WASM TypeScript bindings)
|
|
247
|
+
yarn ubrn:web # compiles the WASM crate with wasm-pack
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Rust unit tests
|
|
251
|
+
|
|
252
|
+
```sh
|
|
253
|
+
cargo test --manifest-path rust/mermaid_wrapper/Cargo.toml
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### TypeScript tests
|
|
257
|
+
|
|
258
|
+
```sh
|
|
259
|
+
yarn test
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Clean generated files
|
|
263
|
+
|
|
264
|
+
Removes all `ubrn`-generated native code so you can rebuild from scratch.
|
|
265
|
+
|
|
266
|
+
```sh
|
|
267
|
+
yarn ubrn:clean
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Running the example app
|
|
273
|
+
|
|
274
|
+
The `example/` directory is an Expo app with a live Mermaid editor — type a diagram, see the SVG update in real time with timing stats.
|
|
275
|
+
|
|
276
|
+
### Step 1 — Generate bindings (all platforms, run once)
|
|
277
|
+
|
|
278
|
+
```sh
|
|
279
|
+
yarn ubrn:generate
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Step 2 — Build native libs for your target platform
|
|
283
|
+
|
|
284
|
+
```sh
|
|
285
|
+
# Android
|
|
286
|
+
yarn ubrn:android
|
|
287
|
+
|
|
288
|
+
# iOS (macOS only)
|
|
289
|
+
yarn ubrn:ios
|
|
290
|
+
|
|
291
|
+
# Web — compile WASM bundle
|
|
292
|
+
yarn ubrn:web
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Step 3 — Run the example
|
|
296
|
+
|
|
297
|
+
**Web** (no emulator needed — opens in your browser):
|
|
298
|
+
```sh
|
|
299
|
+
yarn example:web
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**Android** (emulator or USB device with debugging enabled):
|
|
303
|
+
```sh
|
|
304
|
+
yarn example:android
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**iOS** (macOS only):
|
|
308
|
+
```sh
|
|
309
|
+
yarn example:ios
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### With Expo Dev Client (install on device)
|
|
313
|
+
|
|
314
|
+
For a shareable installable build that includes the Ariel native module:
|
|
315
|
+
|
|
316
|
+
```sh
|
|
317
|
+
# Install EAS CLI
|
|
318
|
+
npm install -g eas-cli
|
|
319
|
+
|
|
320
|
+
# Build dev client (free for public repos)
|
|
321
|
+
eas build --profile development
|
|
322
|
+
|
|
323
|
+
# Install the .apk / .ipa on your device, then run:
|
|
324
|
+
yarn example:android # or example:ios
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## CI
|
|
330
|
+
|
|
331
|
+
Three GitHub Actions workflows run on every push to `main`:
|
|
332
|
+
|
|
333
|
+
| Workflow | Runner | What it does |
|
|
334
|
+
|---|---|---|
|
|
335
|
+
| `build-android.yml` | `ubuntu-latest` | Runs Rust unit tests, builds Android `.so` libs |
|
|
336
|
+
| `build-ios.yml` | `macos-latest` | Builds iOS `.xcframework` |
|
|
337
|
+
| `build-web.yml` | `ubuntu-latest` | Builds WASM bindings |
|
|
338
|
+
|
|
339
|
+
iOS uses GitHub's free `macos-latest` runner (unlimited minutes on public repos).
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## License
|
|
344
|
+
|
|
345
|
+
MIT © 2026 [Rochanglien Infimate](https://github.com/rinfi)
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
Built on [mermaid-rs-renderer](https://github.com/1jehuang/mermaid-rs-renderer) and [uniffi-bindgen-react-native](https://github.com/jhugman/uniffi-bindgen-react-native).
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Generated by uniffi-bindgen-react-native
|
|
2
|
+
cmake_minimum_required(VERSION 3.9.0)
|
|
3
|
+
project(Ariel)
|
|
4
|
+
|
|
5
|
+
set (CMAKE_VERBOSE_MAKEFILE ON)
|
|
6
|
+
set (CMAKE_CXX_STANDARD 17)
|
|
7
|
+
|
|
8
|
+
# Resolve the path to the uniffi-bindgen-react-native package
|
|
9
|
+
execute_process(
|
|
10
|
+
COMMAND node -p "require.resolve('uniffi-bindgen-react-native/package.json')"
|
|
11
|
+
OUTPUT_VARIABLE UNIFFI_BINDGEN_PATH
|
|
12
|
+
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
13
|
+
)
|
|
14
|
+
# Get the directory; get_filename_component and cmake_path will normalize
|
|
15
|
+
# paths with Windows path separators.
|
|
16
|
+
get_filename_component(UNIFFI_BINDGEN_PATH "${UNIFFI_BINDGEN_PATH}" DIRECTORY)
|
|
17
|
+
|
|
18
|
+
# Specifies a path to native header files.
|
|
19
|
+
include_directories(
|
|
20
|
+
../cpp
|
|
21
|
+
../cpp/generated
|
|
22
|
+
|
|
23
|
+
${UNIFFI_BINDGEN_PATH}/cpp/includes
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
add_library(react-native-ariel SHARED
|
|
27
|
+
../cpp/react-native-ariel.cpp
|
|
28
|
+
../cpp/generated/mermaid_wrapper.cpp
|
|
29
|
+
cpp-adapter.cpp
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# Set C++ compiler flags
|
|
33
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
|
|
34
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")
|
|
35
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -frtti")
|
|
36
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector-all")
|
|
37
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
|
38
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
|
39
|
+
|
|
40
|
+
# Set linker flags for 16KB page size alignment (required for Android 15+)
|
|
41
|
+
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
|
|
42
|
+
|
|
43
|
+
cmake_path(
|
|
44
|
+
SET MY_RUST_LIB
|
|
45
|
+
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libmermaid_wrapper.a
|
|
46
|
+
NORMALIZE
|
|
47
|
+
)
|
|
48
|
+
add_library(my_rust_lib STATIC IMPORTED)
|
|
49
|
+
set_target_properties(my_rust_lib PROPERTIES IMPORTED_LOCATION ${MY_RUST_LIB})
|
|
50
|
+
|
|
51
|
+
# Add ReactAndroid libraries, being careful to account for different versions.
|
|
52
|
+
find_package(ReactAndroid REQUIRED CONFIG)
|
|
53
|
+
find_library(LOGCAT log)
|
|
54
|
+
|
|
55
|
+
# REACTNATIVE_MERGED_SO seems to be only be set in a build.gradle.kt file,
|
|
56
|
+
# which we don't use. Thus falling back to version number sniffing.
|
|
57
|
+
if (ReactAndroid_VERSION_MINOR GREATER_EQUAL 76)
|
|
58
|
+
set(REACTNATIVE_MERGED_SO true)
|
|
59
|
+
endif()
|
|
60
|
+
|
|
61
|
+
# https://github.com/react-native-community/discussions-and-proposals/discussions/816
|
|
62
|
+
# This if-then-else can be removed once this library does not support version below 0.76
|
|
63
|
+
if (REACTNATIVE_MERGED_SO)
|
|
64
|
+
target_link_libraries(react-native-ariel ReactAndroid::reactnative)
|
|
65
|
+
else()
|
|
66
|
+
target_link_libraries(react-native-ariel
|
|
67
|
+
ReactAndroid::turbomodulejsijni
|
|
68
|
+
ReactAndroid::react_nativemodule_core
|
|
69
|
+
)
|
|
70
|
+
endif()
|
|
71
|
+
|
|
72
|
+
find_package(fbjni REQUIRED CONFIG)
|
|
73
|
+
target_link_libraries(
|
|
74
|
+
react-native-ariel
|
|
75
|
+
fbjni::fbjni
|
|
76
|
+
ReactAndroid::jsi
|
|
77
|
+
${LOGCAT}
|
|
78
|
+
my_rust_lib
|
|
79
|
+
)
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// Generated by uniffi-bindgen-react-native
|
|
2
|
+
|
|
3
|
+
buildscript {
|
|
4
|
+
// Buildscript is evaluated before everything else so we can't use getExtOrDefault
|
|
5
|
+
def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["DummyLibForAndroid_kotlinVersion"]
|
|
6
|
+
|
|
7
|
+
repositories {
|
|
8
|
+
google()
|
|
9
|
+
mavenCentral()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
dependencies {
|
|
13
|
+
classpath "com.android.tools.build:gradle:7.2.1"
|
|
14
|
+
// noinspection DifferentKotlinGradleVersion
|
|
15
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
def reactNativeArchitectures() {
|
|
20
|
+
def value = rootProject.getProperties().get("reactNativeArchitectures")
|
|
21
|
+
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
def isNewArchitectureEnabled() {
|
|
25
|
+
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
apply plugin: "com.android.library"
|
|
29
|
+
apply plugin: "kotlin-android"
|
|
30
|
+
|
|
31
|
+
if (isNewArchitectureEnabled()) {
|
|
32
|
+
apply plugin: "com.facebook.react"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
def getExtOrDefault(name) {
|
|
36
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["Ariel_" + name]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
def getExtOrIntegerDefault(name) {
|
|
40
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["Ariel_" + name]).toInteger()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
def supportsNamespace() {
|
|
44
|
+
def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')
|
|
45
|
+
def major = parsed[0].toInteger()
|
|
46
|
+
def minor = parsed[1].toInteger()
|
|
47
|
+
|
|
48
|
+
// Namespace support was added in 7.3.0
|
|
49
|
+
return (major == 7 && minor >= 3) || major >= 8
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
android {
|
|
53
|
+
if (supportsNamespace()) {
|
|
54
|
+
namespace "com.ariel"
|
|
55
|
+
|
|
56
|
+
sourceSets {
|
|
57
|
+
main {
|
|
58
|
+
manifest.srcFile "src/main/AndroidManifestNew.xml"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
ndkVersion getExtOrDefault("ndkVersion")
|
|
64
|
+
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
|
|
65
|
+
|
|
66
|
+
defaultConfig {
|
|
67
|
+
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
|
|
68
|
+
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
|
|
69
|
+
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
|
70
|
+
consumerProguardFiles 'proguard-rules.pro'
|
|
71
|
+
|
|
72
|
+
buildFeatures {
|
|
73
|
+
prefab true
|
|
74
|
+
}
|
|
75
|
+
externalNativeBuild {
|
|
76
|
+
cmake {
|
|
77
|
+
arguments '-DANDROID_STL=c++_shared'
|
|
78
|
+
abiFilters (*reactNativeArchitectures())
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
ndk {
|
|
82
|
+
abiFilters "arm64-v8a", "armeabi-v7a", "x86", "x86_64"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
externalNativeBuild {
|
|
87
|
+
cmake {
|
|
88
|
+
path "CMakeLists.txt"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
buildFeatures {
|
|
93
|
+
buildConfig true
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
buildTypes {
|
|
97
|
+
release {
|
|
98
|
+
minifyEnabled false
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
lintOptions {
|
|
103
|
+
disable "GradleCompatible"
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
compileOptions {
|
|
107
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
108
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
sourceSets {
|
|
112
|
+
main {
|
|
113
|
+
if (isNewArchitectureEnabled()) {
|
|
114
|
+
java.srcDirs += [
|
|
115
|
+
"generated/java",
|
|
116
|
+
"generated/jni"
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
repositories {
|
|
124
|
+
mavenCentral()
|
|
125
|
+
google()
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
def kotlin_version = getExtOrDefault("kotlinVersion")
|
|
129
|
+
|
|
130
|
+
dependencies {
|
|
131
|
+
// For < 0.71, this will be from the local maven repo
|
|
132
|
+
// For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
|
|
133
|
+
//noinspection GradleDynamicVersion
|
|
134
|
+
implementation "com.facebook.react:react-native:+"
|
|
135
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (isNewArchitectureEnabled()) {
|
|
139
|
+
react {
|
|
140
|
+
jsRootDir = file("../src/")
|
|
141
|
+
libraryName = "Ariel"
|
|
142
|
+
codegenJavaPackageName = "com.ariel"
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Generated by uniffi-bindgen-react-native
|
|
2
|
+
#include <jni.h>
|
|
3
|
+
#include <jsi/jsi.h>
|
|
4
|
+
#include <ReactCommon/CallInvokerHolder.h>
|
|
5
|
+
#include "react-native-ariel.h"
|
|
6
|
+
|
|
7
|
+
namespace jsi = facebook::jsi;
|
|
8
|
+
namespace react = facebook::react;
|
|
9
|
+
|
|
10
|
+
// Automated testing checks Java_com_ariel_ArielModule and ariel
|
|
11
|
+
// by comparing the whole line here.
|
|
12
|
+
/*
|
|
13
|
+
Java_com_ariel_ArielModule_nativeMultiply(JNIEnv *env, jclass type, jdouble a, jdouble b) {
|
|
14
|
+
return ariel::multiply(a, b);
|
|
15
|
+
}
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
// Installer coming from ArielModule
|
|
19
|
+
extern "C"
|
|
20
|
+
JNIEXPORT jboolean JNICALL
|
|
21
|
+
Java_com_ariel_ArielModule_nativeInstallRustCrate(
|
|
22
|
+
JNIEnv *env,
|
|
23
|
+
jclass type,
|
|
24
|
+
jlong rtPtr,
|
|
25
|
+
jobject callInvokerHolderJavaObj
|
|
26
|
+
) {
|
|
27
|
+
using JCallInvokerHolder = facebook::react::CallInvokerHolder;
|
|
28
|
+
|
|
29
|
+
auto holderLocal = facebook::jni::make_local(callInvokerHolderJavaObj);
|
|
30
|
+
auto holderRef = facebook::jni::static_ref_cast<JCallInvokerHolder::javaobject>(holderLocal);
|
|
31
|
+
auto* holderCxx = holderRef->cthis();
|
|
32
|
+
auto jsCallInvoker = holderCxx->getCallInvoker();
|
|
33
|
+
auto runtime = reinterpret_cast<jsi::Runtime *>(rtPtr);
|
|
34
|
+
|
|
35
|
+
return ariel::installRustCrate(*runtime, jsCallInvoker);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
extern "C"
|
|
39
|
+
JNIEXPORT jboolean JNICALL
|
|
40
|
+
Java_com_ariel_ArielModule_nativeCleanupRustCrate(JNIEnv *env, jclass type, jlong rtPtr) {
|
|
41
|
+
auto runtime = reinterpret_cast<jsi::Runtime *>(rtPtr);
|
|
42
|
+
return ariel::cleanupRustCrate(*runtime);
|
|
43
|
+
}
|