nitro_generator 0.4.0 copy "nitro_generator: ^0.4.0" to clipboard
nitro_generator: ^0.4.0 copied to clipboard

Code generator for Nitro Modules (Nitrogen). Converts *.native.dart specs to Dart FFI, Kotlin, Swift, and C++ bindings.

0.4.0 #

  • New: Mixed Apple platform implementation targets — A single module can now use different implementation languages per Apple platform. For example, macos: NativeImpl.cpp with ios: NativeImpl.swift generates a single bridge with #if TARGET_OS_OSX / #else guards — no manual patching required. Supports all combinations: both Swift, both C++, or mixed.
  • Fixed: Swift @nitroNativeAsync protocol signature — Methods annotated with @nitroNativeAsync now correctly declare async throws in the generated HybridXxxProtocol.
  • SPM and CocoaPods support — Generated C++ bridges compile correctly under both Swift Package Manager (.mm forwarder via nitrogen link) and CocoaPods (ios/Classes/ and macos/Classes/ forwarders).
  • Ecosystem sync — Aligned with nitro, nitro_annotations, and nitrogen_cli 0.4.0.

0.3.3 #

  • Fixed: JNI crash (ART abort) with nested @HybridStruct fieldsGetFieldID was called with "Ljava/lang/Object;" for nested struct fields, posting a NoSuchFieldError that ART turned into a fatal runtime abort on the next JNI call. Fixed by generating the correct class descriptor (e.g. Lnitro/nitro_ar_module/Vector3;) in the constructor signature, GetFieldID calls, pack_*_from_jni, unpack_*_to_jni, and the release function. Both the already-generated file and the generator itself were fixed to prevent regression.
  • New: @HybridStruct types usable as @HybridRecord list fields@HybridRecord() class PackageBoxes { final List<BoundingBox> boxes; } now serializes correctly end-to-end.
    • spec_extractor.dart: _recordFieldKind now recognises @HybridStruct-annotated types, classifying List<BoundingBox> as listRecordObject (not listPrimitive).
    • struct_generator.dart generateKotlin: Every Kotlin data class for a struct now includes companion object { decodeFrom(buf) / decode(bytes) }, writeFieldsTo(out, buf), and encode(): ByteArray so structs can be embedded inline in record binary payloads.
    • record_generator.dart generateDartExtensions: Auto-generates RecordExt extensions (with fromNative, fromReader, writeFields, toNative) for every @HybridStruct type referenced in a record field, including transitive closure for nested struct types.
  • Fixed: Kotlin record list field wire format — The writeIndexedList helper (which discarded list items via { _ ->} and referenced an undefined it) has been replaced with a simple writeInt32(size) + forEach { e -> e.writeFieldsTo(out, buf) }. The corresponding Kotlin read no longer skips a phantom offset table; both sides now use the same count-then-items format as the Dart codec.
  • Tests: 50 new tests in struct_in_record_test.dart — Cover: Dart RecordExt for struct list items, Kotlin struct codec methods, Kotlin record using struct codecs, transitive nested-struct closure, recordObject (non-list) struct fields, all primitive field types, wire-format consistency, and negative cases (unreferenced structs produce no RecordExt).

0.3.2 #

  • Fixed: Nested struct fields generate typed pointers — Fields whose type is another @HybridStruct now use Pointer<NestedFfi> instead of Pointer<Void>. toDart(), toNative(), freeFields(), and proxy lazy getters all handle nested pointers correctly.
  • Fixed: Proxy super() for nested struct fields — Zero-value defaults are now generated recursively (e.g. Vector3(x: 0.0, y: 0.0, z: 0.0)) instead of null, which was invalid for non-nullable types.
  • New: Positional constructor param supportBridgeField gains isNamed and isRequired flags. The generator emits positional args before named args in toDart() and proxy super(), matching the struct's actual constructor signature. The spec extractor reads these flags automatically.
  • Fixed: TypedData length-field matching is case-sensitive — Only exact lowercase names (length, size, stride, bytelength, bytelen, len) match. A field named Stride (capital S) now correctly falls back to asTypedList(0).
  • Tests: 135 new tests across 3 filesnested_struct_test.dart, struct_constructor_params_test.dart, and struct_field_types_test.dart cover nested structs, all constructor styles, String/enum/TypedData fields, freeFields() combinations, zeroCopy, nullable stripping, and more.

0.3.1 #

  • New: macOS targeting in BridgeSpecBridgeSpec now accepts an optional macosImpl field (NativeImpl?) and exposes targetsMacos and targetsAppleCpp getters. targetsAppleCpp is true when either ios or macos (or both) use NativeImpl.cpp, enabling a single #ifdef __APPLE__ guard in the C++ bridge instead of separate iOS/macOS guards.
  • New: INVALID_MACOS_IMPL validator errorSpecValidator emits an error with code INVALID_MACOS_IMPL and severity error when macos: NativeImpl.kotlin is specified, since Kotlin is not a valid native language on macOS.
  • Improved: isCppImpl getter — Updated to account for macosImpl; a spec is considered cpp-only when all specified platforms use NativeImpl.cpp.
  • Improved: CppBridgeGenerator platform guard — The Apple-platform #ifdef block now uses __APPLE__ (covers both iOS and macOS) instead of __APPLE__ && TARGET_OS_IOS, so generated C++ bridges compile correctly in both iOS and macOS targets.
  • New: Edge-case tests in spec_validator_expansion_test.dart — 5 new cyclic struct detection edge cases: struct with no fields, struct with only primitive fields, two independent mutual cycles (each reported exactly once), four-struct transitive cycle, and a struct referencing a primitive type (not treated as cycle).
  • Fixed: stale DeleteLocalRef test assertionscpp_bridge_generator_test.dart and edge_cases_test.dart expected explicit env->DeleteLocalRef(j_param) calls that are no longer emitted; the generator now wraps every JNI call in PushLocalFrame(16) / PopLocalFrame(nullptr) which frees all local refs automatically. Tests updated to assert the PushLocalFrame/PopLocalFrame pattern and guard against regressing to manual DeleteLocalRef.
  • Fixed: record-return exception-ordering test snippet size — the 400-char substring was too small to contain GetByteArrayRegion after the extra PopLocalFrame error paths were added; extended to 700 chars and added presence guards for both substrings.
  • New: Zero-copy proxy streamingStructGenerator.generateDartProxies now emits final class ${Name}Proxy extends ${Name} implements Finalizable. Every getter is @override and reads lazily from a Pointer<${Name}Ffi>; super fields are zeroed and never read. Because Proxy <: ValueType, Stream<Proxy> satisfies Stream<Value> via Dart covariant generics — no .map() or API change required.
  • New: Generated C release symbolsCppBridgeGenerator emits a void ${lib}_release_${Struct}(void* ptr) function for every @HybridStruct inside extern "C" blocks on both the direct-C++ and JNI+Swift paths.
  • New: NativeFinalizer with generated release symbol — Each proxy's static NativeFinalizer? _finalizer is lazily bound to dylib.lookup('${lib}_release_${Struct}') via an idempotent static void _init(DynamicLibrary dylib). The impl constructor calls ${Name}Proxy._init(_dylib) for each struct.
  • New: isLeaf: true on sync primitive bindings — All synchronous FFI bindings with primitive-only return types (including read/write property accessors) are emitted with .asFunction<...>(isLeaf: true), skipping the Dart VM safepoint transition.
  • New: Indexed @HybridRecord list encodingDartFfiGenerator encodes list record params with RecordWriter.encodeIndexedList and decodes list record returns with LazyRecordList.decode. Kotlin and Swift encode with a writeIndexedList helper; the decode path skips the offset table.
  • New: _superDefault helper in StructGenerator — Returns a safe zero-value Dart literal for each field type so the proxy's super(...) call compiles without touching native data.
  • Breaking fix: struct stream override type — Generated struct stream overrides now emit Stream<${ValueType}> (matching the spec) while using openStream<${Proxy}> internally. Previously the impl emitted Stream<${Proxy}> which was an invalid override.
  • Fixed: missing struct release symbols on Android — Struct release functions (used by Dart's NativeFinalizer) were previously incorrectly guarded by platform preprocessor blocks in CppBridgeGenerator, causing them to be missing from Android builds. They are now generated in a common extern "C" block for all platforms.
  • Fixed: memory leaks in struct return paths — Implemented deep release of heap-allocated native fields (e.g., native strings char* allocated via strdup) in the struct release functions.
  • Fixed: struct property getter leaks — Updated the Dart FFI generator to correctly convert and deeply release struct properties, matching the safety logic used for method returns.
  • Fixed: struct release exports in C++ headerCppHeaderGenerator now includes NITRO_EXPORT declarations for all struct release functions, ensuring they are correctly exported and visible to the Dart FFI layer.
  • New: freeFields() for FFI structs — Generated FFI struct extensions now include a freeFields() method to safely release internal native resources.
  • Improved: memory safety in toDart() — Struct conversion now performs an eager copy of TypedData fields (using Uint8List.fromList), preventing use-after-free errors when the native buffer is quickly released.
  • Improved: cleaner bridge code — Struct release functions are now coalesced into a single extern "C" block in the generated bridge C++ source.
  • Tests: regression coverage for struct release — Added unit tests to cpp_header_generator_test.dart, cpp_bridge_generator_test.dart, and dart_ffi_generator_test.dart to verify memory safety and correct symbol generation across all layers.

0.3.0 #

  • New: Direct C++ Implementation support — Generator produces *.native.g.h, *.mock.g.h, and *.test.g.cpp when @NitroModule(ios: NativeImpl.cpp, android: NativeImpl.cpp) is specified.

  • New: Thread-safe bridgeCppBridgeGenerator uses std::atomic for g_impl and stream port storage; CppBridgeGenerator now uses direct virtual dispatch with no platform #ifdef blocks.

  • New: std::optional<T> for nullable typesCppInterfaceGenerator emits nullable Dart types as std::optional<T>.

  • New: Precise Pointer<T> C++ mappingPointer<SomeEnum>SomeEnum*, Pointer<SomeStruct>SomeStruct*, Pointer<Void>void*.

  • New: #ifndef struct guardsgenerateCStructs wraps each C struct in an include guard to prevent typedef redefinition errors in CocoaPods umbrella builds.

  • New: BridgeSpec.isCppImpl — convenience getter for detecting pure-C++ modules.

  • Improved: FFI memory safetyDartFfiGenerator emits try { ... } finally { malloc.free(...); } for all record/struct return paths.

  • Improved: checkDisposed() guards — Added to all generated methods including Fast (leaf) functions; annotated @pragma('vm:prefer-inline').

  • Fixed: Builder diagnosticsbuilder.printWarning now shows actual file paths instead of literal placeholders.

  • New: Single-platform targeting@NitroModule now accepts optional ios and android parameters. A module can target iOS only, Android only, or both. Generators skip output for untargeted platforms.

  • New: BridgeSpec.targetsIos / targetsAndroid — convenience getters derived from nullable iosImpl/androidImpl.

  • New: NO_TARGET_PLATFORM validation errorSpecValidator emits an error when neither ios nor android is specified.

  • Improved: BridgeSpec.isCppImpl — correctly handles single-platform C++ specs (ios: NativeImpl.cpp with android omitted, and vice versa).

  • Improved: SwiftGenerator — returns a placeholder comment when iOS is not targeted instead of generating an empty/broken file.

  • Improved: KotlinGenerator — returns a placeholder comment when Android is not targeted.

  • Improved: CppBridgeGenerator — omits #ifdef __ANDROID__ / #elif __APPLE__ / #endif platform guards for single-platform specs; routes to the appropriate single-platform code path.

  • Tests: 72 new tests — platform targeting unit tests, single-platform generator output, isCppImpl edge cases, additional validator rules, JNI parameter handling, CMake variable indirection, C++ mock and interface edge cases.

  • Tests: 100+ new regression tests — Benchmark spec tests, Pointer<T> param/return tests, nullable type tests, and stream backpressure isolation tests across all generators.

0.2.3 #

  • Fix: Array — Updated the Swift generator to correctly bridge Uint8List parameters as Data when matching native Swift signatures, ensuring type-safe binary data transfer without manual casts.
  • Improved: Header Generator — The generated C++ bridge headers now automatically include nitro.h.
  • Improved: Dependency Sync: Synchronized the Nitro ecosystem to version 0.2.3.

0.2.2 #

  • Fix: stable annotation resolution — updated SpecExtractor to use TypeChecker.fromRuntime for all Nitro annotations, ensuring they are correctly identified when re-exported through the nitro runtime package. This resolves "No @NitroModule annotated classes found" and "UNKNOWN_RETURN_TYPE" errors for enums/structs in complex specifications.
  • Improved: spec-level type registration — ensured that all enums and structs defined in a spec library are correctly added to the valid type set before function, property, and stream validation.

0.2.1 #

  • Fix: non-zero-copy TypedData function parameters now produce correct JNI arrays — previously the raw C pointer (float*, int32_t*, …) was passed directly as the JNI call argument, causing a crash at runtime. The generator now emits NewFloatArray / NewIntArray / SetFloatArrayRegion / etc. and passes the proper jarray reference. A DeleteLocalRef is emitted after the call in every return-type path.
  • Fix: removed redundant env->ExceptionClear() at JNI call sitesnitro_report_jni_exception already calls ExceptionClear() internally; the duplicate call at each call site was a no-op and has been removed.
  • Fix: _streamJobs map now uses a composite Pair<String, Long> key — keying only on dartPort meant two simultaneous subscriptions on different streams could theoretically overwrite each other's coroutine job if they received the same port value. The key is now Pair(streamName, dartPort).
  • Polish: spec-path attribution in all generated files — every generated file (Dart, Kotlin, Swift, C++, CMake) now includes // Generated from: <spec>.native.dart at the top, making it easy to trace any generated file back to its source spec when working with multiple modules.
  • Polish: checkDisposed() annotated @pragma('vm:prefer-inline') — the single-field _disposed check is now inlined by the Dart VM/AOT compiler, eliminating the call overhead on every generated method invocation.
  • Performance: single-pass AST extraction in SpecExtractor_extractRecordTypes previously called library.annotatedWith twice (once to collect names, once to build types); it now collects class elements in one pass and reuses the list. _extractProperties and _extractStreams previously made two separate loops over element.accessors; they are now merged into a single combined pass.
  • Decoupled from the nitro runtime package to resolve pub.dev platform warnings.
  • Now depends on the pure-Dart nitro_annotations package.
  • This ensures the generator is recognized as a cross-platform Dart package.

0.2.0 #

  • New: @HybridRecord Binary Bridge Generator — Generated extensions now use a compact binary protocol (uint8_t* / Pointer<Uint8>) instead of UTF-8 JSON strings, significantly reducing serialization overhead.
    • Breaking: Extension methods renamed to standard codec names: fromJsonfromNative / fromReader, toJsonwriteFields / toNative.
    • Full support for @HybridRecord in Kotlin (.bridge.g.kt) via @Keep data class with companion decode/encode methods. Swift support updated for toNative and RecordReader integrations.
  • New: Comprehensive Collection Bridging — Added binary-first support for:
    • List<primitive> (int, double, bool, String) via RecordWriter.encodePrimitiveList.
    • Map<String, T> using the UTF-8 JSON path (dynamic values).
    • Nested lists and nullable record fields.
  • Improved: Swift Stream Stability — Fixed a compiler error in _register_*_stream by heap-allocating @HybridStruct items before passing them to the C emit callback.
  • Improved: Code Quality & Lints — Generated code now follows strict Dart linting rules:
    • Cleaned up unbraced for-loops and unused local variable declarations.
    • Renamed internal variables to follow public naming conventions (e.g., _rawResultrawResult).
  • Testing: Added 28+ regression tests for Kotlin record emission and updated 200+ existing tests to match the binary wire format.

0.1.3 #

  • Swift generator: fixed @_cdecl String type crash (EXC_BAD_ACCESS)String parameters now use UnsafePointer<CChar>? (C const char*) and return values use UnsafeMutablePointer<CChar>? (malloc'd char*), with String(cString:) conversion at the boundary and strdup() for returns so Dart's toDartStringWithFree() / free() pairs correctly.
  • Swift generator: async String-returning methods use DispatchSemaphore + Task.detached with a strdup(result) return.
  • Swift generator: String property getters return strdup-allocated C strings; setters accept UnsafePointer<CChar>? and convert with String(cString:).

0.1.2 #

  • Swift generator: replaced @objc public static func _call_* pattern with top-level @_cdecl("_call_*") public func stubs. Swift structs and Swift-only protocols cannot cross the Objective-C boundary.
  • Swift generator: bool return type now maps to Int8 (matching C's int8_t) instead of Bool.
  • Swift generator: struct-returning functions now return UnsafeMutableRawPointer? (heap-allocated, caller frees) instead of Any?.

0.1.1 #

  • Renamed package from nitrogen to nitro_generator to avoid a naming conflict on pub.dev.

0.1.0 #

  • Initial release of Nitro code generator.
  • Generates Dart FFI, Kotlin, Swift, and C++ bindings.
  • Support for HybridObject, HybridStruct, and HybridEnum.
  • Support for @nitroAsync methods.
  • Support for @NitroStream with Backpressure strategies.
0
likes
80
points
238
downloads

Documentation

Documentation
API reference

Publisher

verified publishershreeman.dev

Weekly Downloads

Code generator for Nitro Modules (Nitrogen). Converts *.native.dart specs to Dart FFI, Kotlin, Swift, and C++ bindings.

Homepage
Repository (GitHub)
View/report issues

Topics

#codegen #ffi #flutter #native #bridge

Funding

Consider supporting this project:

buymeacoffee.com

License

MIT (license)

Dependencies

analyzer, build, dart_style, nitro_annotations, path, source_gen

More

Packages that depend on nitro_generator