feat(dsl): add constructor to js.Object(T) for one-line object creation
- Dominant language
- Zig
- Stars
- 4
- Forks
- 4
- Avg merge
- 16h 14m
- Merged PRs (30d)
- 2
Description
## Summary
Add a constructor (`init` / `from`) to `js.Object(T)` so user code can create and populate a JS object in a single call, instead of manually creating a raw object, wrapping it, and calling `set`.
## Motivation
Defining an object shape is ergonomic:
```zig
pub const BitArray = js.Object(struct {
uint8Array: js.Uint8Array,
bitLen: js.Number,
});
```
But creating an instance at runtime currently requires the low-level dance:
```zig
const e = js.env();
const raw = try e.createObject(); // napi.Value, a fresh {} object
var obj = BitArray{ .val = raw }; // wrap it
try obj.set(.{ .uint8Array = ..., .bitLen = ... });
```
`Object(T)` (`src/js/object.zig`) currently exposes only `validateArg`, `get`, `set`, and `toValue` — there is no constructor. This boilerplate is repetitive and leaks N-API details into otherwise high-level DSL code.
## Proposed solution
Add an `init` method to the type returned by `Object(T)`. It already knows `T` and has `set`, so it just needs to create the underlying object and populate it:
```zig
/// Creates a new JS object and populates it from the Zig struct `T`.
pub fn init(value: T) !Self {
const self = Self{ .val = try env().createObject() };
try self.set(value);
return self;
}
```
(using the in-scope env accessor, matching how `String.from` / `Number.from` reach the env)
Call site collapses to:
```zig
const ba = try BitArray.init(.{
.uint8Array = js.Uint8Array.from(&bytes),
.bitLen = js.Number.from(@as(i32, 42)),
});
```
## Naming
The scalar DSL wrappers already use `from(...)` (`String.from`, `Number.from`, `Boolean.from`, `Date.from`, `Uint8Array.from`). For consistency we could name it `from` instead of `init` — open to either. `init` reads slightly better here since the argument is a struct of fields rather than a single scalar.
## Notes / open questions
- Should there also be an empty constructor (e.g. `empty()` / `init(.{})` when all fields are optional) for incremental population? Probably out of scope for the first pass.
- Keep the existing `set`/`get`/`toValue` API unchanged; this is purely additive.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.