@githolon/dsl 0.2.2 → 0.2.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githolon/dsl",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
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",
@@ -55,7 +55,13 @@ import path from "node:path";
55
55
  import { fileURLToPath, pathToFileURL } from "node:url";
56
56
 
57
57
  import type { AggregateHandle } from "./aggregate.js";
58
- import { generateDartDomain, type DomainModule } from "./codegen_dart.js";
58
+ import {
59
+ generateDartDomain,
60
+ type DartImport,
61
+ type DartRefImport,
62
+ type DomainModule,
63
+ type PermissionVocabulary,
64
+ } from "./codegen_dart.js";
59
65
  import type { AnyCount } from "./count.js";
60
66
  import type { QueryDecl } from "./query.js";
61
67
  import type { SpatialDecl } from "./spatial.js";
@@ -102,6 +108,23 @@ interface DomainConfig {
102
108
  readonly impureCapabilities?: readonly string[];
103
109
  readonly extraAggregates?: readonly string[];
104
110
  readonly readModelAggregates?: readonly string[];
111
+ // DART CODEGEN HINTS (#codegen_dart; NEVER law: none of these enter the USD IR,
112
+ // the package bytes, or the identity manifest — they shape ONLY the generated
113
+ // `dart/` frontend, so adding them does not move the domainHash):
114
+ /** LITERAL extra imports for the generated `<domain>.dart` (e.g. a sibling
115
+ * domain file whose types this domain's payloads reference). */
116
+ readonly dartImports?: readonly DartImport[];
117
+ /** LITERAL cross-domain read-model routing: an aggregate TYPE this domain
118
+ * references resolves through the named import prefix instead of a local decl. */
119
+ readonly dartRefImports?: readonly DartRefImport[];
120
+ /** EXPORT-NAME escape hatch (resolved on the merged module exports, like
121
+ * `impureCapabilities`): `resourceTypes` names a `readonly string[]` export and
122
+ * `roleCatalogue` a `Record<string, string[]>` export; together they emit the
123
+ * frontend permission vocabulary (PermissionRoles/PermissionCapabilities). */
124
+ readonly permissionVocabulary?: {
125
+ readonly resourceTypes: string;
126
+ readonly roleCatalogue: string;
127
+ };
105
128
  }
106
129
 
107
130
  interface PackageConfig {
@@ -228,6 +251,66 @@ function discover<T>(merged: Mod, match: (v: unknown) => v is T): T[] {
228
251
  return out;
229
252
  }
230
253
 
254
+ /** Validate the LITERAL dart-codegen import hints (config data, not module exports). */
255
+ function checkDartImports(domainKey: string, imports: readonly DartImport[] | undefined): void {
256
+ for (const imp of imports ?? []) {
257
+ if (typeof imp?.uri !== "string" || (imp.prefix !== undefined && typeof imp.prefix !== "string")) {
258
+ fail(`domain '${domainKey}': each dartImports entry must be { uri, prefix? }; got ${JSON.stringify(imp)}`);
259
+ }
260
+ }
261
+ }
262
+
263
+ function checkDartRefImports(domainKey: string, imports: readonly DartRefImport[] | undefined): void {
264
+ for (const imp of imports ?? []) {
265
+ if (
266
+ typeof imp?.aggregateType !== "string" ||
267
+ typeof imp?.uri !== "string" ||
268
+ typeof imp?.prefix !== "string"
269
+ ) {
270
+ fail(
271
+ `domain '${domainKey}': each dartRefImports entry must be { aggregateType, uri, prefix }; got ${JSON.stringify(imp)}`,
272
+ );
273
+ }
274
+ }
275
+ }
276
+
277
+ /** Resolve the permissionVocabulary EXPORT NAMES on the merged exports, fail-closed. */
278
+ function resolvePermissionVocabulary(
279
+ domainKey: string,
280
+ merged: Mod,
281
+ cfg: DomainConfig["permissionVocabulary"],
282
+ ): PermissionVocabulary | undefined {
283
+ if (cfg === undefined) return undefined;
284
+ if (typeof cfg?.resourceTypes !== "string" || typeof cfg?.roleCatalogue !== "string") {
285
+ fail(
286
+ `domain '${domainKey}': permissionVocabulary must be { resourceTypes: "<exportName>", roleCatalogue: "<exportName>" }; got ${JSON.stringify(cfg)}`,
287
+ );
288
+ }
289
+ const resourceTypes = merged[cfg.resourceTypes];
290
+ if (!Array.isArray(resourceTypes) || !resourceTypes.every((t) => typeof t === "string")) {
291
+ fail(
292
+ `domain '${domainKey}': permissionVocabulary.resourceTypes names export '${cfg.resourceTypes}', which the modules do not export as a string[]`,
293
+ );
294
+ }
295
+ const roleCatalogue = merged[cfg.roleCatalogue];
296
+ if (
297
+ !roleCatalogue ||
298
+ typeof roleCatalogue !== "object" ||
299
+ Array.isArray(roleCatalogue) ||
300
+ !Object.values(roleCatalogue).every(
301
+ (caps) => Array.isArray(caps) && caps.every((c) => typeof c === "string"),
302
+ )
303
+ ) {
304
+ fail(
305
+ `domain '${domainKey}': permissionVocabulary.roleCatalogue names export '${cfg.roleCatalogue}', which the modules do not export as a Record<string, string[]>`,
306
+ );
307
+ }
308
+ return {
309
+ resourceTypes: resourceTypes as string[],
310
+ roleCatalogue: roleCatalogue as Record<string, string[]>,
311
+ };
312
+ }
313
+
231
314
  /** Resolve explicit EXPORT NAMES (the config escape hatch) on the merged exports. */
232
315
  function resolveNamed<T>(merged: Mod, names: readonly string[] | undefined, what: string): T[] {
233
316
  const out: T[] = [];
@@ -397,6 +480,11 @@ async function main(): Promise<void> {
397
480
  );
398
481
  const extraAggregates = resolveNamed<AggregateHandle>(merged, d.extraAggregates, "extraAggregates");
399
482
 
483
+ // Dart-codegen hints (frontend-only — never law; see DomainConfig):
484
+ checkDartImports(d.key, d.dartImports);
485
+ checkDartRefImports(d.key, d.dartRefImports);
486
+ const permissionVocabulary = resolvePermissionVocabulary(d.key, merged, d.permissionVocabulary);
487
+
400
488
  domainModules.push(
401
489
  composeDomainModule({
402
490
  name: d.name ?? d.key,
@@ -413,6 +501,13 @@ async function main(): Promise<void> {
413
501
  ...(impureCapabilities.length > 0 ? { impureCapabilities } : {}),
414
502
  ...(sums.length > 0 ? { sums } : {}),
415
503
  ...(spatials.length > 0 ? { spatials } : {}),
504
+ ...(d.dartImports !== undefined && d.dartImports.length > 0
505
+ ? { dartImports: d.dartImports }
506
+ : {}),
507
+ ...(d.dartRefImports !== undefined && d.dartRefImports.length > 0
508
+ ? { dartRefImports: d.dartRefImports }
509
+ : {}),
510
+ ...(permissionVocabulary !== undefined ? { permissionVocabulary } : {}),
416
511
  }),
417
512
  );
418
513