react-native-fast-html-parser 0.1.0

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.
Files changed (69) hide show
  1. package/FastHtmlParser.podspec +36 -0
  2. package/LICENSE +20 -0
  3. package/README.md +435 -0
  4. package/android/CMakeLists.txt +31 -0
  5. package/android/build.gradle +121 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/cpp/cpp-adapter.cpp +11 -0
  8. package/android/src/main/java/com/margelo/nitro/fasthtmlparser/FastHtmlParserPackage.kt +22 -0
  9. package/android/src/main/jniLibs/arm64-v8a/libhtml_2_json.so +0 -0
  10. package/android/src/main/jniLibs/armeabi-v7a/libhtml_2_json.so +0 -0
  11. package/android/src/main/jniLibs/x86/libhtml_2_json.so +0 -0
  12. package/android/src/main/jniLibs/x86_64/libhtml_2_json.so +0 -0
  13. package/cpp/HybridFastHtmlParser.cpp +178 -0
  14. package/cpp/HybridFastHtmlParser.hpp +224 -0
  15. package/ios/libs/libhtml_2_json.xcframework/Info.plist +44 -0
  16. package/ios/libs/libhtml_2_json.xcframework/ios-arm64/libhtml_2_json.a +0 -0
  17. package/ios/libs/libhtml_2_json.xcframework/ios-arm64_x86_64-simulator/libhtml_2_json.a +0 -0
  18. package/lib/module/FastHtmlParser.nitro.js +4 -0
  19. package/lib/module/FastHtmlParser.nitro.js.map +1 -0
  20. package/lib/module/index.js +4 -0
  21. package/lib/module/index.js.map +1 -0
  22. package/lib/module/package.json +1 -0
  23. package/lib/module/parser.js +6 -0
  24. package/lib/module/parser.js.map +1 -0
  25. package/lib/module/parser.native.js +8 -0
  26. package/lib/module/parser.native.js.map +1 -0
  27. package/lib/typescript/package.json +1 -0
  28. package/lib/typescript/src/FastHtmlParser.nitro.d.ts +81 -0
  29. package/lib/typescript/src/FastHtmlParser.nitro.d.ts.map +1 -0
  30. package/lib/typescript/src/index.d.ts +3 -0
  31. package/lib/typescript/src/index.d.ts.map +1 -0
  32. package/lib/typescript/src/parser.d.ts +3 -0
  33. package/lib/typescript/src/parser.d.ts.map +1 -0
  34. package/lib/typescript/src/parser.native.d.ts +3 -0
  35. package/lib/typescript/src/parser.native.d.ts.map +1 -0
  36. package/nitro.json +23 -0
  37. package/nitrogen/generated/android/fasthtmlparser+autolinking.cmake +88 -0
  38. package/nitrogen/generated/android/fasthtmlparser+autolinking.gradle +27 -0
  39. package/nitrogen/generated/android/fasthtmlparserOnLoad.cpp +49 -0
  40. package/nitrogen/generated/android/fasthtmlparserOnLoad.hpp +34 -0
  41. package/nitrogen/generated/android/kotlin/com/margelo/nitro/fasthtmlparser/fasthtmlparserOnLoad.kt +35 -0
  42. package/nitrogen/generated/ios/FastHtmlParser+autolinking.rb +62 -0
  43. package/nitrogen/generated/ios/FastHtmlParser-Swift-Cxx-Bridge.cpp +17 -0
  44. package/nitrogen/generated/ios/FastHtmlParser-Swift-Cxx-Bridge.hpp +27 -0
  45. package/nitrogen/generated/ios/FastHtmlParser-Swift-Cxx-Umbrella.hpp +38 -0
  46. package/nitrogen/generated/ios/FastHtmlParserAutolinking.mm +35 -0
  47. package/nitrogen/generated/ios/FastHtmlParserAutolinking.swift +16 -0
  48. package/nitrogen/generated/shared/c++/HybridContentBlockSpec.cpp +39 -0
  49. package/nitrogen/generated/shared/c++/HybridContentBlockSpec.hpp +96 -0
  50. package/nitrogen/generated/shared/c++/HybridDefinitionItemSpec.cpp +24 -0
  51. package/nitrogen/generated/shared/c++/HybridDefinitionItemSpec.hpp +68 -0
  52. package/nitrogen/generated/shared/c++/HybridFastHtmlParserSpec.cpp +21 -0
  53. package/nitrogen/generated/shared/c++/HybridFastHtmlParserSpec.hpp +67 -0
  54. package/nitrogen/generated/shared/c++/HybridInlineNodeSpec.cpp +25 -0
  55. package/nitrogen/generated/shared/c++/HybridInlineNodeSpec.hpp +70 -0
  56. package/nitrogen/generated/shared/c++/HybridListItemSpec.cpp +24 -0
  57. package/nitrogen/generated/shared/c++/HybridListItemSpec.hpp +71 -0
  58. package/nitrogen/generated/shared/c++/HybridParsedArticleSpec.cpp +22 -0
  59. package/nitrogen/generated/shared/c++/HybridParsedArticleSpec.hpp +66 -0
  60. package/nitrogen/generated/shared/c++/HybridTableCellSpec.cpp +22 -0
  61. package/nitrogen/generated/shared/c++/HybridTableCellSpec.hpp +66 -0
  62. package/nitrogen/generated/shared/c++/HybridTableRowSpec.cpp +22 -0
  63. package/nitrogen/generated/shared/c++/HybridTableRowSpec.hpp +66 -0
  64. package/package.json +153 -0
  65. package/scripts/postinstall.js +234 -0
  66. package/src/FastHtmlParser.nitro.ts +86 -0
  67. package/src/index.tsx +12 -0
  68. package/src/parser.native.tsx +9 -0
  69. package/src/parser.tsx +7 -0
@@ -0,0 +1,36 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "FastHtmlParser"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["author"]
12
+
13
+ s.platforms = { :ios => min_ios_version_supported }
14
+ s.source = { :git => "https://github.com/abhishekce17/react-native-fast-html-parser.git", :tag => "#{s.version}" }
15
+
16
+ s.source_files = [
17
+ "ios/**/*.{m,mm}",
18
+ "cpp/**/*.{hpp,cpp}",
19
+ ]
20
+
21
+ s.vendored_frameworks = 'ios/libs/libhtml_2_json.xcframework'
22
+
23
+ s.dependency 'React-jsi'
24
+ s.dependency 'React-callinvoker'
25
+
26
+ load 'nitrogen/generated/ios/FastHtmlParser+autolinking.rb'
27
+ add_nitrogen_files(s)
28
+
29
+ install_modules_dependencies(s)
30
+
31
+ # Force C++17 standard to prevent Fabric compiler standard mismatches
32
+ s.attributes_hash["pod_target_xcconfig"] ||= {}
33
+ s.attributes_hash["pod_target_xcconfig"]["CLANG_CXX_LANGUAGE_STANDARD"] = "c++17"
34
+ s.attributes_hash["user_target_xcconfig"] ||= {}
35
+ s.attributes_hash["user_target_xcconfig"]["CLANG_CXX_LANGUAGE_STANDARD"] = "c++17"
36
+ end
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 abhishekce17
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,435 @@
1
+ # react-native-fast-html-parser
2
+
3
+ A high-performance, zero-copy HTML-to-structured-JSON parser library for React Native. Powered by a lightning-fast Rust core engine (`html_2_json`) and integrated via direct C++ JSI using Margelo Nitro Modules.
4
+
5
+ It achieves pure zero-copy shared-memory access on-device. This avoids standard string/JSON serialization overhead and Hermes garbage collection pauses during render loops.
6
+
7
+ ---
8
+
9
+ ## Features
10
+
11
+ - **Blazing Fast**: Directly parses HTML in CPU memory space using Rust's ecosystem.
12
+ - **Zero-Copy JSI Access**: Access elements recursively on-demand. Properties are retrieved directly from the native C++ pointer space without copying whole objects.
13
+ - **No JSON Intermediates**: Avoids standard CPU intensive parsing overhead of `JSON.parse` or bridge string serialization.
14
+ - **Type-safe AST**: Comprehensive typescript interfaces representing paragraph, headings, lists, tables, code blocks, figures, and rich media.
15
+
16
+ ---
17
+
18
+ ## Installation
19
+
20
+ Run this command inside your React Native application root directory:
21
+
22
+ ```bash
23
+ npm install react-native-fast-html-parser
24
+ ```
25
+ or if you use Yarn:
26
+ ```bash
27
+ yarn add react-native-fast-html-parser
28
+ ```
29
+
30
+ ### iOS Setup
31
+ Install pod dependencies:
32
+ ```bash
33
+ cd ios && pod install
34
+ ```
35
+
36
+ ### Build & Run
37
+ Since this package contains native C++ and precompiled Rust libraries, you must rebuild the application:
38
+ ```bash
39
+ npx react-native run-ios
40
+ # or
41
+ npx react-native run-android
42
+ ```
43
+
44
+ ---
45
+
46
+ ## Basic Usage
47
+
48
+ Import the `parseHTML` function to parse raw HTML and safely read properties by checking the `block.type` first:
49
+
50
+ ```typescript
51
+ import { parseHTML } from 'react-native-fast-html-parser';
52
+
53
+ const html = "<h1>Title</h1><p>This is a <b>bold</b> word.</p>";
54
+ const article = parseHTML(html);
55
+
56
+ if (article) {
57
+ console.log("Total Blocks parsed:", article.length); // 2
58
+
59
+ // Fetch block by index (calls C++ FFI directly)
60
+ const block = article.getBlock(0);
61
+
62
+ if (block) {
63
+ console.log("Block Type:", block.type); // "Heading"
64
+
65
+ // 1. Safe Property Querying via Block Type
66
+ if (block.type === 'Heading') {
67
+ console.log("Heading Level:", block.level); // 1 (Safe to read)
68
+ } else if (block.type === 'CodeBlock') {
69
+ console.log("Code language:", block.language); // Safe to read
70
+ }
71
+
72
+ // 2. Safe Default Fallbacks
73
+ // If you read a property that does not belong to the block type,
74
+ // it returns a safe default fallback instead of returning undefined or crashing:
75
+ console.log("Alt Text (non-applicable):", block.alt); // "" (empty string)
76
+
77
+ // 3. Read inline child nodes
78
+ const inline = block.getChild(0);
79
+ if (inline) {
80
+ console.log("Inline Type:", inline.type); // "Text"
81
+ console.log("Text Content:", inline.text); // "Title"
82
+ }
83
+ }
84
+ }
85
+ ```
86
+
87
+ ---
88
+
89
+ ## Block Type Mapping & Properties
90
+
91
+ Here is the quick reference of which properties/methods are valid for each `block.type`:
92
+
93
+ | `block.type` | Applicable Fields & Methods | Description |
94
+ | :--- | :--- | :--- |
95
+ | **`Paragraph`** | `childCount`, `getChild(index)` | Text block containing inline formatting nodes |
96
+ | **`Heading`** | `level` (1-6), `childCount`, `getChild(index)` | Section headers containing formatted inline text |
97
+ | **`Image`** / **`Figure`** | `url`, `alt`, `caption` | Images and figure elements with alt text and captions |
98
+ | **`CodeBlock`** | `code`, `language` | Syntax-highlighted code blocks |
99
+ | **`List`** | `ordered` (boolean), `itemCount`, `getItem(index)` | Ordered (`ol`) or Unordered (`ul`) list elements |
100
+ | **`Table`** | `rowCount`, `getRow(index)` | Tables containing rows and cells |
101
+ | **`Quote`** | `childCount`, `getQuoteChild(index)` | Blockquotes containing nested block elements |
102
+ | **`DefinitionList`** | `itemCount`, `getDefItem(index)` | List of term/definition pairs (`dl`/`dt`/`dd`) |
103
+ | **`Video`** | `src`, `poster`, `caption` | Native video components with source, cover, and captions |
104
+ | **`Audio`** | `src`, `caption` | Native audio players with captions |
105
+ | **`Embed`** | `src`, `title`, `caption` | Generic iframe or external embeds |
106
+ | **`Separator`** | *None* | A horizontal rule element (`<hr>`) |
107
+
108
+ ---
109
+
110
+ ## Handling Each Block Type (Code Examples)
111
+
112
+ Here is how you handle and query properties for each specific block type returned by `article.getBlock(index)`:
113
+
114
+ ### 1. Paragraph & Heading
115
+ Paragraphs and Headings contain child inline formatting nodes:
116
+ ```typescript
117
+ if (block.type === 'Paragraph') {
118
+ for (let i = 0; i < block.childCount; i++) {
119
+ const inline = block.getChild(i);
120
+ if (inline) {
121
+ console.log(`Text: ${inline.text}, Formatting: ${inline.type}`);
122
+ }
123
+ }
124
+ }
125
+
126
+ if (block.type === 'Heading') {
127
+ console.log("Heading Level:", block.level); // 1-6
128
+ const firstInlineChild = block.getChild(0);
129
+ }
130
+ ```
131
+
132
+ ### 2. Image, Figure & Media
133
+ ```typescript
134
+ if (block.type === 'Image' || block.type === 'Figure') {
135
+ console.log("URL:", block.url);
136
+ console.log("Alt Text:", block.alt);
137
+ console.log("Caption:", block.caption);
138
+ }
139
+
140
+ if (block.type === 'Video') {
141
+ console.log("Video source:", block.src);
142
+ console.log("Video cover poster:", block.poster);
143
+ console.log("Caption:", block.caption);
144
+ }
145
+
146
+ if (block.type === 'Audio') {
147
+ console.log("Audio source:", block.src);
148
+ }
149
+
150
+ if (block.type === 'Embed') {
151
+ console.log("Iframe source url:", block.src);
152
+ console.log("Iframe title:", block.title);
153
+ }
154
+ ```
155
+
156
+ ### 3. CodeBlock
157
+ ```typescript
158
+ if (block.type === 'CodeBlock') {
159
+ console.log("Raw Code:", block.code);
160
+ console.log("Language:", block.language); // e.g. "typescript", "rust"
161
+ }
162
+ ```
163
+
164
+ ### 4. List (Ordered / Unordered)
165
+ ```typescript
166
+ if (block.type === 'List') {
167
+ console.log("Is ordered list?", block.ordered);
168
+
169
+ for (let i = 0; i < block.itemCount; i++) {
170
+ const item = block.getItem(i);
171
+ if (item) {
172
+ // 1. Read inline children of list item
173
+ for (let j = 0; j < item.childCount; j++) {
174
+ const inline = item.getChild(j);
175
+ console.log(inline?.text);
176
+ }
177
+
178
+ // 2. Read nested lists (for multi-level nested lists)
179
+ for (let k = 0; k < item.nestedCount; k++) {
180
+ const nestedBlock = item.getNested(k);
181
+ console.log("Nested block type:", nestedBlock?.type); // "List"
182
+ }
183
+ }
184
+ }
185
+ }
186
+ ```
187
+
188
+ ### 5. Table
189
+ ```typescript
190
+ if (block.type === 'Table') {
191
+ for (let r = 0; r < block.rowCount; r++) {
192
+ const row = block.getRow(r);
193
+ if (row) {
194
+ for (let c = 0; c < row.cellCount; c++) {
195
+ const cell = row.getCell(c);
196
+ if (cell) {
197
+ // Read cell contents
198
+ const inlineChild = cell.getChild(0);
199
+ console.log(`Cell [${r}, ${c}]:`, inlineChild?.text);
200
+ }
201
+ }
202
+ }
203
+ }
204
+ }
205
+ ```
206
+
207
+ ### 6. Quote (Blockquote)
208
+ ```typescript
209
+ if (block.type === 'Quote') {
210
+ // Quote blocks contain sub-blocks (like nested Paragraphs)
211
+ for (let i = 0; i < block.childCount; i++) {
212
+ const quoteChildBlock = block.getQuoteChild(i);
213
+ if (quoteChildBlock) {
214
+ console.log("Nested quote block type:", quoteChildBlock.type); // e.g., "Paragraph"
215
+ }
216
+ }
217
+ }
218
+ ```
219
+
220
+ ### 7. DefinitionList
221
+ ```typescript
222
+ if (block.type === 'DefinitionList') {
223
+ for (let i = 0; i < block.itemCount; i++) {
224
+ const defItem = block.getDefItem(i);
225
+ if (defItem) {
226
+ // Read term inlines (<dt>)
227
+ const termInline = defItem.getTerm(0);
228
+
229
+ // Read definition inlines (<dd>)
230
+ const defInline = defItem.getDef(0);
231
+ }
232
+ }
233
+ }
234
+ ```
235
+
236
+ ### 8. Separator
237
+ ```typescript
238
+ if (block.type === 'Separator') {
239
+ console.log("Renders horizontal rule line (<hr>)");
240
+ }
241
+ ```
242
+
243
+ ---
244
+
245
+ ## Rendering Components (Traversing the AST)
246
+
247
+ Here is a complete, production-grade React Native component showing how to traverse the AST recursively to map HTML content to native layout blocks:
248
+
249
+ ```tsx
250
+ import React from 'react';
251
+ import { View, Text, StyleSheet, ScrollView } from 'react-native';
252
+ import { parseHTML, type ContentBlock, type InlineNode } from 'react-native-fast-html-parser';
253
+
254
+ // Helper to render formatting inlines (bold, italic, links)
255
+ function RenderInline({ node }: { node: InlineNode }): React.ReactElement {
256
+ if (node.type === 'Text') {
257
+ return <Text>{node.text}</Text>;
258
+ }
259
+ if (node.type === 'Bold') {
260
+ return <Text style={styles.bold}>{node.text}</Text>;
261
+ }
262
+ if (node.type === 'Italic') {
263
+ return <Text style={styles.italic}>{node.text}</Text>;
264
+ }
265
+ if (node.type === 'Link') {
266
+ return <Text style={styles.link} onPress={() => console.log('Open URL:', node.url)}>{node.text}</Text>;
267
+ }
268
+ return <Text>{node.text}</Text>;
269
+ }
270
+
271
+ // Helper to render block-level structures
272
+ function RenderBlock({ block }: { block: ContentBlock }): React.ReactElement | null {
273
+ switch (block.type) {
274
+ case 'Heading': {
275
+ const children = [];
276
+ for (let i = 0; i < block.childCount; i++) {
277
+ const child = block.getChild(i);
278
+ if (child) children.push(<RenderInline key={i} node={child} />);
279
+ }
280
+ const isH1 = block.level === 1;
281
+ return <Text style={isH1 ? styles.h1 : styles.h2}>{children}</Text>;
282
+ }
283
+
284
+ case 'Paragraph': {
285
+ const children = [];
286
+ for (let i = 0; i < block.childCount; i++) {
287
+ const child = block.getChild(i);
288
+ if (child) children.push(<RenderInline key={i} node={child} />);
289
+ }
290
+ return <Text style={styles.paragraph}>{children}</Text>;
291
+ }
292
+
293
+ case 'CodeBlock': {
294
+ return (
295
+ <View style={styles.codeContainer}>
296
+ <Text style={styles.codeLanguage}>{block.language || 'code'}</Text>
297
+ <Text style={styles.codeText}>{block.code}</Text>
298
+ </View>
299
+ );
300
+ }
301
+
302
+ case 'Quote': {
303
+ const quoteChildren = [];
304
+ for (let i = 0; i < block.childCount; i++) {
305
+ const quoteBlock = block.getQuoteChild(i);
306
+ if (quoteBlock) {
307
+ quoteChildren.push(<RenderBlock key={i} block={quoteBlock} />);
308
+ }
309
+ }
310
+ return <View style={styles.quoteBorder}>{quoteChildren}</View>;
311
+ }
312
+
313
+ default:
314
+ return null;
315
+ }
316
+ }
317
+
318
+ // Main Renderer Component
319
+ export default function HtmlContentRenderer({ html }: { html: string }) {
320
+ const article = React.useMemo(() => parseHTML(html), [html]);
321
+
322
+ if (!article) {
323
+ return <Text>Error parsing content</Text>;
324
+ }
325
+
326
+ const blocks = [];
327
+ for (let i = 0; i < article.length; i++) {
328
+ const block = article.getBlock(i);
329
+ if (block) {
330
+ blocks.push(<RenderBlock key={i} block={block} />);
331
+ }
332
+ }
333
+
334
+ return <ScrollView style={styles.container}>{blocks}</ScrollView>;
335
+ }
336
+
337
+ const styles = StyleSheet.create({
338
+ container: { flex: 1, padding: 16, backgroundColor: '#ffffff' },
339
+ paragraph: { fontSize: 16, lineHeight: 24, color: '#333333', marginVertical: 8 },
340
+ h1: { fontSize: 24, fontWeight: 'bold', marginVertical: 12, color: '#111111' },
341
+ h2: { fontSize: 20, fontWeight: 'bold', marginVertical: 10, color: '#222222' },
342
+ bold: { fontWeight: 'bold' },
343
+ italic: { fontStyle: 'italic' },
344
+ link: { color: '#0066cc', textDecorationLine: 'underline' },
345
+ codeContainer: { backgroundColor: '#f5f5f5', padding: 12, borderRadius: 8, marginVertical: 8 },
346
+ codeLanguage: { fontSize: 11, color: '#888888', textTransform: 'uppercase', marginBottom: 4 },
347
+ codeText: { fontFamily: 'Courier', fontSize: 14, color: '#333333' },
348
+ quoteBorder: { borderLeftWidth: 4, borderLeftColor: '#cccccc', paddingLeft: 12, marginVertical: 8, fontStyle: 'italic' }
349
+ });
350
+ ```
351
+
352
+ ---
353
+
354
+ ## AST Type Reference
355
+
356
+ All exposed interfaces are fully registered with JSI and typechecked:
357
+
358
+ ```typescript
359
+ export interface InlineNode {
360
+ readonly type: 'Text' | 'Bold' | 'Italic' | 'Link' | 'Strikethrough' | 'Underline' | 'Code';
361
+ readonly text: string;
362
+ readonly url: string;
363
+ readonly childCount: number;
364
+ getChild(index: number): InlineNode | null;
365
+ }
366
+
367
+ export interface ListItem {
368
+ readonly childCount: number;
369
+ getChild(index: number): InlineNode | null;
370
+ readonly nestedCount: number;
371
+ getNested(index: number): ContentBlock | null;
372
+ }
373
+
374
+ export interface TableCell {
375
+ readonly childCount: number;
376
+ getChild(index: number): InlineNode | null;
377
+ }
378
+
379
+ export interface TableRow {
380
+ readonly cellCount: number;
381
+ getCell(index: number): TableCell | null;
382
+ }
383
+
384
+ export interface DefinitionItem {
385
+ readonly termCount: number;
386
+ getTerm(index: number): InlineNode | null;
387
+ readonly defCount: number;
388
+ getDef(index: number): InlineNode | null;
389
+ }
390
+
391
+ export interface ContentBlock {
392
+ readonly type: 'Paragraph' | 'Heading' | 'List' | 'Table' | 'Quote' | 'CodeBlock' | 'Media' | 'DefinitionList' | 'Embed';
393
+ readonly level: number; // For Heading elements (1-6)
394
+ readonly url: string; // For Image/Media nodes
395
+ readonly alt: string; // For Image/Media nodes
396
+ readonly caption: string; // For Figures
397
+ readonly code: string; // For Code blocks
398
+ readonly language: string; // For Code blocks
399
+ readonly src: string; // For Video/Audio/Embed source url
400
+ readonly poster: string; // For Video poster url
401
+ readonly title: string; // For Embed elements
402
+
403
+ // Children elements
404
+ readonly childCount: number;
405
+ getChild(index: number): InlineNode | null;
406
+ getQuoteChild(index: number): ContentBlock | null;
407
+
408
+ // List properties
409
+ readonly ordered: boolean;
410
+ readonly itemCount: number;
411
+ getItem(index: number): ListItem | null;
412
+
413
+ // Table properties
414
+ readonly rowCount: number;
415
+ getRow(index: number): TableRow | null;
416
+
417
+ // DefinitionList properties
418
+ getDefItem(index: number): DefinitionItem | null;
419
+ }
420
+
421
+ export interface ParsedArticle {
422
+ readonly length: number;
423
+ getBlock(index: number): ContentBlock | null;
424
+ }
425
+
426
+ export interface FastHtmlParser {
427
+ parse(html: string): ParsedArticle | null;
428
+ }
429
+ ```
430
+
431
+ ---
432
+
433
+ ## License
434
+
435
+ MIT © [abhishekce17](https://github.com/abhishekce17)
@@ -0,0 +1,31 @@
1
+ project(fasthtmlparser)
2
+ cmake_minimum_required(VERSION 3.9.0)
3
+
4
+ set(PACKAGE_NAME fasthtmlparser)
5
+ set(CMAKE_VERBOSE_MAKEFILE ON)
6
+ set(CMAKE_CXX_STANDARD 20)
7
+
8
+ # Define C++ library and compile all sources
9
+ add_library(${PACKAGE_NAME} SHARED
10
+ src/main/cpp/cpp-adapter.cpp
11
+ ../cpp/HybridFastHtmlParser.cpp
12
+ )
13
+
14
+ # Add Nitrogen specs :)
15
+ include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/fasthtmlparser+autolinking.cmake)
16
+
17
+ # Set up local includes
18
+ include_directories("src/main/cpp" "../cpp")
19
+
20
+ # Tell the linker where to search for the precompiled Rust shared library for this target
21
+ target_link_directories(${PACKAGE_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})
22
+
23
+ find_library(LOG_LIB log)
24
+
25
+ # Link all libraries together
26
+ target_link_libraries(
27
+ ${PACKAGE_NAME}
28
+ ${LOG_LIB}
29
+ android # <-- Android core
30
+ html_2_json # <-- Link precompiled Rust library by name directly
31
+ )
@@ -0,0 +1,121 @@
1
+ buildscript {
2
+ ext.FastHtmlParser = [
3
+ kotlinVersion: "2.0.21",
4
+ minSdkVersion: 24,
5
+ compileSdkVersion: 36
6
+ ]
7
+
8
+ ext.getExtOrDefault = { prop ->
9
+ if (rootProject.ext.has(prop)) {
10
+ return rootProject.ext.get(prop)
11
+ }
12
+
13
+ return FastHtmlParser[prop]
14
+ }
15
+
16
+ repositories {
17
+ google()
18
+ mavenCentral()
19
+ }
20
+
21
+ dependencies {
22
+ classpath "com.android.tools.build:gradle:8.7.2"
23
+ // noinspection DifferentKotlinGradleVersion
24
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
25
+ }
26
+ }
27
+
28
+ def reactNativeArchitectures() {
29
+ def value = rootProject.getProperties().get("reactNativeArchitectures")
30
+ return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
31
+ }
32
+
33
+
34
+
35
+
36
+ apply plugin: "com.android.library"
37
+ apply plugin: "kotlin-android"
38
+ apply from: '../nitrogen/generated/android/fasthtmlparser+autolinking.gradle'
39
+
40
+ apply plugin: "com.facebook.react"
41
+
42
+ android {
43
+ namespace "com.margelo.nitro.fasthtmlparser"
44
+
45
+ compileSdkVersion getExtOrDefault("compileSdkVersion")
46
+
47
+ defaultConfig {
48
+ minSdkVersion getExtOrDefault("minSdkVersion")
49
+
50
+ externalNativeBuild {
51
+ cmake {
52
+ cppFlags "-frtti -fexceptions -Wall -fstack-protector-all"
53
+ arguments "-DANDROID_STL=c++_shared", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
54
+ abiFilters (*reactNativeArchitectures())
55
+
56
+ buildTypes {
57
+ debug {
58
+ cppFlags "-O1 -g"
59
+ }
60
+ release {
61
+ cppFlags "-O2"
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
67
+
68
+ externalNativeBuild {
69
+ cmake {
70
+ path "CMakeLists.txt"
71
+ }
72
+ }
73
+
74
+ packaging {
75
+ resources {
76
+ excludes += [
77
+ "META-INF",
78
+ "META-INF/**"
79
+ ]
80
+ }
81
+
82
+ jniLibs {
83
+ excludes += [
84
+ "**/libc++_shared.so",
85
+ "**/libfbjni.so",
86
+ "**/libjsi.so",
87
+ "**/libfolly_json.so",
88
+ "**/libfolly_runtime.so",
89
+ "**/libglog.so",
90
+ "**/libhermes.so",
91
+ "**/libhermes-executor-debug.so",
92
+ "**/libhermes_executor.so",
93
+ "**/libreactnative.so",
94
+ "**/libreactnativejni.so",
95
+ "**/libturbomodulejsijni.so",
96
+ "**/libreact_nativemodule_core.so",
97
+ "**/libjscexecutor.so"
98
+ ]
99
+ }
100
+ }
101
+
102
+ sourceSets {
103
+ main {
104
+ jniLibs.srcDirs = ["src/main/jniLibs"]
105
+ }
106
+ }
107
+
108
+ buildFeatures {
109
+ prefab true
110
+ }
111
+
112
+ compileOptions {
113
+ sourceCompatibility JavaVersion.VERSION_17
114
+ targetCompatibility JavaVersion.VERSION_17
115
+ }
116
+ }
117
+
118
+ dependencies {
119
+ implementation "com.facebook.react:react-android"
120
+ implementation project(":react-native-nitro-modules")
121
+ }
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,11 @@
1
+ #include <jni.h>
2
+ #include "fasthtmlparserOnLoad.hpp"
3
+
4
+ #include <fbjni/fbjni.h>
5
+
6
+
7
+ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
8
+ return facebook::jni::initialize(vm, []() {
9
+ margelo::nitro::fasthtmlparser::registerAllNatives();
10
+ });
11
+ }
@@ -0,0 +1,22 @@
1
+ package com.margelo.nitro.fasthtmlparser
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfoProvider
7
+
8
+ class FastHtmlParserPackage : BaseReactPackage() {
9
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
10
+ return null
11
+ }
12
+
13
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
14
+ return ReactModuleInfoProvider { HashMap() }
15
+ }
16
+
17
+ companion object {
18
+ init {
19
+ System.loadLibrary("fasthtmlparser")
20
+ }
21
+ }
22
+ }