@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 +1 -1
- package/src/compile_package_main.ts +96 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@githolon/dsl",
|
|
3
|
-
"version": "0.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 {
|
|
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
|
|