@dforge-core/metadata 0.0.23 → 0.0.25
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/CHANGELOG.md +93 -0
- package/dist/dsl/index.d.ts +37 -9
- package/dist/dsl/index.js +340 -12
- package/dist/dsl/index.js.map +1 -1
- package/dist/index.d.ts +24 -3
- package/dist/index.js +17 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/dsl/check.ts +391 -7
- package/src/dsl/index.ts +2 -1
- package/src/dsl/lexer.ts +31 -1
- package/src/dsl/parse.ts +93 -19
- package/src/dsl/types.ts +8 -0
- package/src/index.ts +1 -0
- package/src/traits.ts +49 -9
- package/src/types.ts +15 -0
package/src/dsl/types.ts
CHANGED
|
@@ -79,6 +79,14 @@ export interface DslContext {
|
|
|
79
79
|
action?: {
|
|
80
80
|
code: string;
|
|
81
81
|
executionMode?: ActionExecutionMode;
|
|
82
|
+
/**
|
|
83
|
+
* True when a scheduled job invokes this action. A job runs as the
|
|
84
|
+
* system user with no current record, so record context is a hard
|
|
85
|
+
* error there even in a mode that would otherwise allow it. Only a
|
|
86
|
+
* reader that has the module's jobs can know this, so it is the host's
|
|
87
|
+
* to supply; absent, the rule stands down like every other.
|
|
88
|
+
*/
|
|
89
|
+
viaJob?: boolean;
|
|
82
90
|
};
|
|
83
91
|
/**
|
|
84
92
|
* Entity behind the record context (`[field]`). `null` or absent when it
|
package/src/index.ts
CHANGED
package/src/traits.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// these as checkboxes and previews the expanded fields, so authors never
|
|
7
7
|
// hand-write `created_date` / `{entity}_id` etc.
|
|
8
8
|
|
|
9
|
-
import type { FieldDef, TraitDef } from "./types";
|
|
9
|
+
import type { FieldDef, TraitDef, TraitsFile } from "./types";
|
|
10
10
|
|
|
11
11
|
export const traits: readonly TraitDef[] = [
|
|
12
12
|
{
|
|
@@ -107,21 +107,61 @@ function templateFields(fields: Record<string, FieldDef>, entity: string): Recor
|
|
|
107
107
|
* for `entityName`, with `{entity}` / `{Entity}` tokens resolved. Returns an
|
|
108
108
|
* empty object for unknown or marker traits. Field order follows include-depth
|
|
109
109
|
* first, then declaration order; later definitions win on key collisions.
|
|
110
|
+
*
|
|
111
|
+
* `localTraits` is a module's own `traits.json`. A module may declare traits of
|
|
112
|
+
* its own, and an entity in it names them exactly like a platform trait — so a
|
|
113
|
+
* reader that knows only this registry sees an entity missing columns that
|
|
114
|
+
* install will give it. Pass the file and those traits resolve; a code declared
|
|
115
|
+
* in both wins locally, mirroring the installer, which overlays the module's
|
|
116
|
+
* traits on the platform ones (`TraitExpanderFactory.ForPackage`).
|
|
110
117
|
*/
|
|
111
|
-
export function expandTrait(
|
|
112
|
-
|
|
113
|
-
|
|
118
|
+
export function expandTrait(
|
|
119
|
+
traitCd: string,
|
|
120
|
+
entityName: string,
|
|
121
|
+
localTraits?: TraitsFile,
|
|
122
|
+
): Record<string, FieldDef> {
|
|
123
|
+
return expandTraitInner(traitCd, entityName, localTraits, new Set());
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function expandTraitInner(
|
|
127
|
+
traitCd: string,
|
|
128
|
+
entityName: string,
|
|
129
|
+
localTraits: TraitsFile | undefined,
|
|
130
|
+
path: Set<string>,
|
|
131
|
+
): Record<string, FieldDef> {
|
|
132
|
+
// `includes` is author-supplied once local traits are in play, so a cycle is
|
|
133
|
+
// reachable from a module file. Unguarded that is an editor hang, not a bad
|
|
134
|
+
// expansion.
|
|
135
|
+
//
|
|
136
|
+
// The guard is the current path, not every trait already visited: in a
|
|
137
|
+
// diamond — two includes that both reach a third — the third has to expand
|
|
138
|
+
// under each of them, or which definition wins a key collision would depend
|
|
139
|
+
// on which branch got there first.
|
|
140
|
+
if (path.has(traitCd)) return {};
|
|
141
|
+
path.add(traitCd);
|
|
142
|
+
|
|
143
|
+
const trait = localTraits?.[traitCd] ?? byCd.get(traitCd);
|
|
114
144
|
const result: Record<string, FieldDef> = {};
|
|
115
|
-
|
|
116
|
-
|
|
145
|
+
if (trait) {
|
|
146
|
+
for (const included of trait.includes ?? []) {
|
|
147
|
+
Object.assign(result, expandTraitInner(included, entityName, localTraits, path));
|
|
148
|
+
}
|
|
149
|
+
Object.assign(result, templateFields(trait.fields ?? {}, entityName));
|
|
117
150
|
}
|
|
118
|
-
|
|
151
|
+
|
|
152
|
+
path.delete(traitCd);
|
|
119
153
|
return result;
|
|
120
154
|
}
|
|
121
155
|
|
|
122
156
|
/** Expand several traits in order into one merged field map. */
|
|
123
|
-
export function expandTraits(
|
|
157
|
+
export function expandTraits(
|
|
158
|
+
traitCds: readonly string[],
|
|
159
|
+
entityName: string,
|
|
160
|
+
localTraits?: TraitsFile,
|
|
161
|
+
): Record<string, FieldDef> {
|
|
124
162
|
const result: Record<string, FieldDef> = {};
|
|
125
|
-
for (const cd of traitCds)
|
|
163
|
+
for (const cd of traitCds) {
|
|
164
|
+
Object.assign(result, expandTraitInner(cd, entityName, localTraits, new Set()));
|
|
165
|
+
}
|
|
126
166
|
return result;
|
|
127
167
|
}
|
package/src/types.ts
CHANGED
|
@@ -179,6 +179,21 @@ export interface TraitDef {
|
|
|
179
179
|
references?: Record<string, unknown>;
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
+
/**
|
|
183
|
+
* A module's own `traits.json`, keyed by trait code — the key is the `cd`, so a
|
|
184
|
+
* definition here is otherwise a {@link TraitDef} with everything optional
|
|
185
|
+
* (a marker trait declares no fields at all).
|
|
186
|
+
*/
|
|
187
|
+
export interface TraitsFile {
|
|
188
|
+
[traitCd: string]: {
|
|
189
|
+
description?: string;
|
|
190
|
+
includes?: string[];
|
|
191
|
+
fields?: Record<string, FieldDef>;
|
|
192
|
+
references?: Record<string, unknown>;
|
|
193
|
+
constraints?: Record<string, unknown>;
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
182
197
|
/** Description of a column kind for friendly pickers. */
|
|
183
198
|
export interface ColumnTypeDef {
|
|
184
199
|
cd: ColumnTypeCd;
|