@githolon/dsl 0.40.0 → 0.41.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.
package/dart/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
## 0.30.0
|
|
2
|
+
|
|
3
|
+
- RUNTIME AGGREGATE METADATA: `NomosAggregateMeta` / `NomosFieldMeta` / `mergeAggregateMeta` (`src/aggregate_meta.dart`) — the support types for the generated per-domain `const Map<String, NomosAggregateMeta> <domain>AggregateMeta` registry (`nomos-compile` ≥0.41 tooling). Generic surfaces (history/audit UIs, op renderers, in-app agents) resolve `NomosAggregateMeta.typeOfId(op.aggregate)` → field kinds, enum wire values, VO/variant names, and the typed `fromJson` decoder — the compiler's knowledge emitted as data, derived from the law's own declarations.
|
|
4
|
+
|
|
1
5
|
## 0.29.0
|
|
2
6
|
|
|
3
7
|
- LAW-MINTED IDS RETURN TO THE CALLER: `NomosBridge.offerCreates(...)` → `NomosOfferOutcome{head, created}` — a `.creates` plan mints its aggregate id inside the sealed intent (payloads never carry one); the offer now hands the minted ids back, so generated create methods return the typed id with no query-after round-trip. New types `NomosOfferOutcome` / `NomosCreated`.
|
|
@@ -30,6 +30,9 @@ export 'src/offer.dart';
|
|
|
30
30
|
export 'src/home.dart';
|
|
31
31
|
export 'src/subscriptions.dart';
|
|
32
32
|
export 'src/schema_validation.dart';
|
|
33
|
+
// RUNTIME AGGREGATE METADATA — the generated per-domain registry's support types
|
|
34
|
+
// (lookup by aggregateType for generic surfaces: history UIs, op renderers, agents).
|
|
35
|
+
export 'src/aggregate_meta.dart';
|
|
33
36
|
// THE WEBVIEW BRIDGE (app-binding boundary) — the async Dart runtime that drives the REAL githolon running
|
|
34
37
|
// in a WebView, so the generated typed client never needs a `MemoryPersistence` fake.
|
|
35
38
|
export 'src/webview_bridge.dart';
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// RUNTIME AGGREGATE METADATA (architecture/dart_codegen_parity.md — the registry slice).
|
|
2
|
+
//
|
|
3
|
+
// Dart is nominal and has no runtime type derivation, so everything the compiler knows about an
|
|
4
|
+
// aggregate's shape is invisible at runtime unless it is EMITTED AS DATA. `nomos-compile`
|
|
5
|
+
// generates one `const Map<String, NomosAggregateMeta>` per domain (keyed by the projection's
|
|
6
|
+
// wire type, e.g. `drawing.Site`), so generic surfaces — history/audit UIs over `historyOf`,
|
|
7
|
+
// undo previews, op renderers, an in-app agent introspecting state — can resolve
|
|
8
|
+
// `(aggregateType, field, rawValue)` to typed knowledge with NO hand-maintained switch.
|
|
9
|
+
//
|
|
10
|
+
// THE LINE THIS HOLDS: this is client-side reflection over the LAW'S DECLARED SHAPE — derived
|
|
11
|
+
// from the same descriptors the package IR carries, never hand-authored, never a second source
|
|
12
|
+
// of truth. If it disagrees with the law, the generator is broken, not the registry.
|
|
13
|
+
|
|
14
|
+
/// Runtime metadata for ONE field of an aggregate — the compiler's knowledge, emitted as data.
|
|
15
|
+
class NomosFieldMeta {
|
|
16
|
+
/// The DSL field kind (`string` | `int` | `double` | `bool` | `enum` | `set` | `map` |
|
|
17
|
+
/// `json` | `ref` | `counter` | `position` | `evidence` | ...).
|
|
18
|
+
final String kind;
|
|
19
|
+
|
|
20
|
+
/// For `enum` kinds: the exact wire values the law's zod validates.
|
|
21
|
+
final List<String>? enumValues;
|
|
22
|
+
|
|
23
|
+
/// For `json` leaves that are DECLARED value objects: the VO / variant name
|
|
24
|
+
/// (the generated Dart class / sealed base of the same name decodes it).
|
|
25
|
+
final String? vo;
|
|
26
|
+
|
|
27
|
+
/// True when [vo] names a `variant(...)` sum type (decode lands on a sealed hierarchy
|
|
28
|
+
/// whose `Unknown` arm carries arms this client's law version doesn't know).
|
|
29
|
+
final bool isVariant;
|
|
30
|
+
|
|
31
|
+
/// For `ref` kinds: the referenced aggregate's wire type, when the law declares it.
|
|
32
|
+
final String? refType;
|
|
33
|
+
|
|
34
|
+
const NomosFieldMeta({
|
|
35
|
+
required this.kind,
|
|
36
|
+
this.enumValues,
|
|
37
|
+
this.vo,
|
|
38
|
+
this.isVariant = false,
|
|
39
|
+
this.refType,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/// Runtime metadata for ONE aggregate, keyed by its projection wire type. [fromRow] is the
|
|
44
|
+
/// generated typed decoder (`<Agg>.fromJson`) — the same one every generated accessor uses,
|
|
45
|
+
/// surfaced here so a runtime-dispatched row still decodes to the REAL typed class.
|
|
46
|
+
class NomosAggregateMeta {
|
|
47
|
+
/// The projection wire type (`<domain>.<Aggregate>`).
|
|
48
|
+
final String type;
|
|
49
|
+
|
|
50
|
+
/// The aggregate's declared label (`Site`).
|
|
51
|
+
final String label;
|
|
52
|
+
|
|
53
|
+
/// Declared field name → its metadata.
|
|
54
|
+
final Map<String, NomosFieldMeta> fields;
|
|
55
|
+
|
|
56
|
+
/// The generated typed decoder (`Site.fromJson`) — returns the generated aggregate class
|
|
57
|
+
/// (typed as [Object] here; cast at the call site, or drive it generically via [fields]).
|
|
58
|
+
final Object Function(Map<String, dynamic> data, [String rowId]) fromRow;
|
|
59
|
+
|
|
60
|
+
const NomosAggregateMeta({
|
|
61
|
+
required this.type,
|
|
62
|
+
required this.label,
|
|
63
|
+
required this.fields,
|
|
64
|
+
required this.fromRow,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
/// The AGGREGATE WIRE TYPE of a kernel aggregate id: minted ids are
|
|
68
|
+
/// `<domain>.<Type>_<uuidv7>`, so the type is the prefix before the trailing
|
|
69
|
+
/// `_<uuid>` (the same rule `@githolon/client` applies to Create events).
|
|
70
|
+
/// Returns the input unchanged when no uuid suffix is present (already a type).
|
|
71
|
+
static String typeOfId(String aggregateId) =>
|
|
72
|
+
aggregateId.replaceFirst(RegExp(r'_[0-9a-fA-F-]+$'), '');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// Merge per-domain registries into one lookup (a package with several domains). Later maps
|
|
76
|
+
/// win on key collisions — collisions only occur when two domains declare the SAME wire type,
|
|
77
|
+
/// which the compiler already refuses.
|
|
78
|
+
Map<String, NomosAggregateMeta> mergeAggregateMeta(
|
|
79
|
+
Iterable<Map<String, NomosAggregateMeta>> registries) =>
|
|
80
|
+
{for (final r in registries) ...r};
|
package/dart/pubspec.yaml
CHANGED
|
@@ -11,7 +11,7 @@ description: >-
|
|
|
11
11
|
Nomos 2 Dart frontend types — the hand-written kernel wire types plus the
|
|
12
12
|
code-generated per-domain aggregate + directive-payload types. (De)serializes
|
|
13
13
|
the EXACT serde JSON the Rust kernel + projection produce/consume.
|
|
14
|
-
version: 0.
|
|
14
|
+
version: 0.30.0
|
|
15
15
|
|
|
16
16
|
environment:
|
|
17
17
|
sdk: ^3.5.0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@githolon/dsl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Nomos 2 domain-authoring DSL: aggregates + directives in TS, executed and encoded to the Rust kernel's wire shapes.",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
package/src/codegen_dart.ts
CHANGED
|
@@ -1536,6 +1536,60 @@ function emitUnionClasses(d: ValueObjectDescriptor): string {
|
|
|
1536
1536
|
return [base, ...armClasses, unknown].join("\n\n");
|
|
1537
1537
|
}
|
|
1538
1538
|
|
|
1539
|
+
/** THE RUNTIME AGGREGATE-META REGISTRY (dart_codegen_parity.md): one generated
|
|
1540
|
+
* `const Map<String, NomosAggregateMeta>` per domain, keyed by the projection wire type
|
|
1541
|
+
* (`<domain>.<Aggregate>`). Generic surfaces (history/audit UIs, op renderers, in-app agents)
|
|
1542
|
+
* resolve `op.aggregateType` → field kinds / enum wire values / VO+variant names / the typed
|
|
1543
|
+
* `fromJson` decoder — the compiler's knowledge, emitted as data, derived from the SAME
|
|
1544
|
+
* declarations the law carries (never hand-authored; never a second source of truth). */
|
|
1545
|
+
function emitAggregateMetaRegistry(
|
|
1546
|
+
domainKey: string,
|
|
1547
|
+
aggregates: readonly AggregateHandle[],
|
|
1548
|
+
): string {
|
|
1549
|
+
if (aggregates.length === 0) return "";
|
|
1550
|
+
const entries = aggregates.map((agg) => {
|
|
1551
|
+
const wireType = `${domainKey}.${agg.id}`;
|
|
1552
|
+
const fieldLines = Object.entries(agg.fields as Record<string, Field>).map(([name, f]) => {
|
|
1553
|
+
const parts: string[] = [`kind: '${f.kind}'`];
|
|
1554
|
+
if (f.kind === "enum") {
|
|
1555
|
+
try {
|
|
1556
|
+
const values = zodEnumValues(f.zod as z.ZodTypeAny);
|
|
1557
|
+
parts.push(`enumValues: [${values.map((v) => `'${v}'`).join(", ")}]`);
|
|
1558
|
+
} catch { /* enum without introspectable values — kind alone still serves */ }
|
|
1559
|
+
}
|
|
1560
|
+
const vo = (f as { valueObject?: { name: string; descriptor?: { union?: unknown } } }).valueObject;
|
|
1561
|
+
if (vo !== undefined) {
|
|
1562
|
+
parts.push(`vo: '${vo.name}'`);
|
|
1563
|
+
if (vo.descriptor && (vo.descriptor as { union?: unknown }).union !== undefined) parts.push(`isVariant: true`);
|
|
1564
|
+
}
|
|
1565
|
+
const refTarget = (f as { refAggregateId?: string }).refAggregateId;
|
|
1566
|
+
if (f.kind === "ref" && refTarget !== undefined) {
|
|
1567
|
+
parts.push(`refType: '${domainKey}.${refTarget}'`);
|
|
1568
|
+
}
|
|
1569
|
+
return ` '${name}': NomosFieldMeta(${parts.join(", ")}),`;
|
|
1570
|
+
});
|
|
1571
|
+
return [
|
|
1572
|
+
` '${wireType}': NomosAggregateMeta(`,
|
|
1573
|
+
` type: '${wireType}',`,
|
|
1574
|
+
` label: '${agg.id}',`,
|
|
1575
|
+
` fields: {`,
|
|
1576
|
+
...fieldLines,
|
|
1577
|
+
` },`,
|
|
1578
|
+
` fromRow: ${agg.id}.fromJson,`,
|
|
1579
|
+
` ),`,
|
|
1580
|
+
].join("\n");
|
|
1581
|
+
});
|
|
1582
|
+
const mapName = `${dartMemberName(domainKey)}AggregateMeta`;
|
|
1583
|
+
return [
|
|
1584
|
+
`/// RUNTIME lookup of this domain's aggregate shapes by projection wire type`,
|
|
1585
|
+
`/// (\`NomosAggregateMeta.typeOfId(op.aggregate)\` resolves an instance id to its key).`,
|
|
1586
|
+
`/// Derived from the law's own declarations — the compiler's knowledge as const data.`,
|
|
1587
|
+
`const Map<String, NomosAggregateMeta> ${mapName} = {`,
|
|
1588
|
+
...entries,
|
|
1589
|
+
`};`,
|
|
1590
|
+
].join("\n");
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1539
1593
|
function emitValueObjectClass(d: ValueObjectDescriptor): string {
|
|
1540
1594
|
if (d.union !== undefined) return emitUnionClasses(d);
|
|
1541
1595
|
if (d.geometry !== undefined) {
|
|
@@ -3212,6 +3266,8 @@ export function generateDartDomain(mod: DomainModule, opts: GenerateDartDomainOp
|
|
|
3212
3266
|
),
|
|
3213
3267
|
)
|
|
3214
3268
|
.join("\n\n");
|
|
3269
|
+
// the runtime aggregate-meta registry (lookup by op.aggregateType — generic surfaces).
|
|
3270
|
+
const aggregateMetaBlock = emitAggregateMetaRegistry(domainKey, localAggregates);
|
|
3215
3271
|
const dirBlock = localDirectives
|
|
3216
3272
|
.map((d) => emitDirective(d, domainKey, dartTypes))
|
|
3217
3273
|
.join("\n\n");
|
|
@@ -3426,6 +3482,13 @@ export function generateDartDomain(mod: DomainModule, opts: GenerateDartDomainOp
|
|
|
3426
3482
|
`// ---- aggregates (projection types) ----`,
|
|
3427
3483
|
aggBlock,
|
|
3428
3484
|
``,
|
|
3485
|
+
...(aggregateMetaBlock !== ""
|
|
3486
|
+
? [
|
|
3487
|
+
`// ---- runtime aggregate metadata (lookup by op.aggregateType) ----`,
|
|
3488
|
+
aggregateMetaBlock,
|
|
3489
|
+
``,
|
|
3490
|
+
]
|
|
3491
|
+
: []),
|
|
3429
3492
|
...(readModelBlock !== ""
|
|
3430
3493
|
? [
|
|
3431
3494
|
`// ---- generated read models (from aggregate DSL fields) ----`,
|
|
@@ -353,6 +353,9 @@ const DART_SUPPORT_SRC = [
|
|
|
353
353
|
"offer.dart",
|
|
354
354
|
"subscriptions.dart",
|
|
355
355
|
"provider.dart",
|
|
356
|
+
// Runtime aggregate-meta support types (NomosAggregateMeta/NomosFieldMeta) — the generated
|
|
357
|
+
// per-domain registry consts reference them through the barrel.
|
|
358
|
+
"aggregate_meta.dart",
|
|
356
359
|
// The async WebView bridge runtime (NomosBridge / BridgeTransport) the generated
|
|
357
360
|
// `<name>.client.dart` drives — the barrel re-exports it, so it must be vendored too.
|
|
358
361
|
"webview_bridge.dart",
|