@dforge-core/metadata 0.0.33 → 0.0.35

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.
@@ -12,11 +12,22 @@
12
12
  },
13
13
  "records": {
14
14
  "type": "array",
15
- "description": "Array of records, each record is an object with column_code → value",
15
+ "description": "Array of records, each record is an object with column_code → value. In demo-data/ a value may be a formula: { \"$f\": \"DATEADD(@yearStart, 42, 'DAY')\" }",
16
16
  "items": {
17
17
  "type": "object",
18
18
  "additionalProperties": true
19
19
  }
20
+ },
21
+ "repeat": {
22
+ "type": "object",
23
+ "description": "demo-data/ only: insert every record once per value of @var, from..to inclusive",
24
+ "required": ["to"],
25
+ "properties": {
26
+ "var": { "type": "string", "default": "i" },
27
+ "from": { "type": "integer", "default": 1 },
28
+ "to": { "type": "integer" }
29
+ },
30
+ "additionalProperties": false
20
31
  }
21
32
  },
22
33
  "additionalProperties": false
@@ -10,7 +10,6 @@
10
10
  "$defs": {
11
11
  "setting": {
12
12
  "type": "object",
13
- "required": ["fieldTypeCd"],
14
13
  "properties": {
15
14
  "fieldTypeCd": {
16
15
  "type": "string",
@@ -47,8 +46,32 @@
47
46
  "params": {
48
47
  "type": "object",
49
48
  "description": "Field-type-specific parameters. Examples: dropdown → { options: [...] }; number → { min, max }; lookup → { link: { entity, otherKey } }."
49
+ },
50
+ "domain": {
51
+ "type": "string",
52
+ "description": "Reference to a reusable column domain. A bare 'domain_cd' means this module's own domain, then a tenant-created one, and never another module's, even one with the same code. 'module_cd.domain_cd' names a domain of any installed module; declare that module as a dependency. The domain supplies fieldTypeCd, baseDatatypeCd and params; declaring any of those alongside 'domain' is rejected at install. The setting keeps its own label, defaultValue, formula and required flag."
50
53
  }
51
54
  },
55
+ "oneOf": [
56
+ {
57
+ "title": "Domain-backed setting",
58
+ "description": "Setting whose control and option list come from a reusable column domain. Requires 'domain' and must NOT restate what the domain owns.",
59
+ "required": ["domain"],
60
+ "properties": {
61
+ "fieldTypeCd": false,
62
+ "baseDatatypeCd": false,
63
+ "params": false
64
+ }
65
+ },
66
+ {
67
+ "title": "Inline setting",
68
+ "description": "Setting that declares its own control and parameters. Requires 'fieldTypeCd'.",
69
+ "required": ["fieldTypeCd"],
70
+ "properties": {
71
+ "domain": false
72
+ }
73
+ }
74
+ ],
52
75
  "additionalProperties": false
53
76
  }
54
77
  }
@@ -117,9 +117,32 @@
117
117
  "type": "object",
118
118
  "description": "Control parameters, the same shape an entity column's `params` takes — `options` for a dropdown or flags, `currency`, `align`, and so on.",
119
119
  "additionalProperties": true
120
+ },
121
+ "domain": {
122
+ "type": "string",
123
+ "description": "Reference to a reusable column domain. Unqualified resolves within this module, then tenant-created domains; 'module_cd.domain_cd' binds to that module. The domain supplies the control, datatype and option list — and its options are translated once, for every consumer."
120
124
  }
121
125
  },
122
- "additionalProperties": false
126
+ "additionalProperties": false,
127
+ "oneOf": [
128
+ {
129
+ "title": "Domain-backed result column",
130
+ "description": "Defers to a column domain. Must not restate what the domain owns.",
131
+ "required": ["domain"],
132
+ "properties": {
133
+ "fieldTypeCd": false,
134
+ "baseDatatypeCd": false,
135
+ "params": false
136
+ }
137
+ },
138
+ {
139
+ "title": "Inline result column",
140
+ "description": "Declares its own control and datatype.",
141
+ "properties": {
142
+ "domain": false
143
+ }
144
+ }
145
+ ]
123
146
  }
124
147
  }
125
148
  }
@@ -79,9 +79,34 @@
79
79
  "serverDefault": { "$ref": "#/$defs/serverDefault" }
80
80
  },
81
81
  "additionalProperties": true
82
+ },
83
+ "domain": {
84
+ "type": "string",
85
+ "description": "Reference to a reusable column domain. A bare 'domain_cd' resolves in the module of the entity taking the trait, then tenant-created domains, so one generic trait gives each module its own list; 'module_cd.domain_cd' pins one module's domain for every entity. A module's own traits.json must qualify a domain the module itself defines: written bare, it would bind to a same-named domain of whichever module takes the trait, and pack rejects it. The domain supplies the type, control, sizing and options."
82
86
  }
83
87
  },
84
- "additionalProperties": false
88
+ "additionalProperties": false,
89
+ "oneOf": [
90
+ {
91
+ "title": "Domain-backed trait field",
92
+ "description": "Defers to a column domain. Must not restate what the domain owns, and takes no 'link' — it is a plain scalar column.",
93
+ "required": ["domain"],
94
+ "properties": {
95
+ "link": false,
96
+ "dbDatatype": false,
97
+ "fieldTypeCd": false,
98
+ "maxLen": false,
99
+ "params": false
100
+ }
101
+ },
102
+ {
103
+ "title": "Inline trait field",
104
+ "description": "Declares its own type and control, as trait fields always have.",
105
+ "properties": {
106
+ "domain": false
107
+ }
108
+ }
109
+ ]
85
110
  },
86
111
  "serverDefault": {
87
112
  "type": "object",
@@ -58,6 +58,13 @@
58
58
  "$ref": "#/$defs/labelOnly"
59
59
  }
60
60
  },
61
+ "registers": {
62
+ "type": "object",
63
+ "description": "Register code (as registers.json keys it) → label and description.",
64
+ "additionalProperties": {
65
+ "$ref": "#/$defs/labelDesc"
66
+ }
67
+ },
61
68
  "reports": {
62
69
  "type": "object",
63
70
  "description": "Report code → label, dataset captions and parameter labels.",
@@ -1,6 +1,11 @@
1
1
  // The DSL's platform globals. Signatures and prose track
2
- // dforge-mcp/skills/dforge-mcp-author/references/action-dsl.md — that file is
3
- // the source of truth; re-sync when it changes.
2
+ // skills/dforge-module-author/references/action-dsl.md — that file is the source
3
+ // of truth; re-sync when it changes. (The path used to name a dforge-mcp
4
+ // checkout, which this repo has no such directory for.)
5
+ //
6
+ // The list itself is pinned against the server's DslBuiltins.FunctionNames by
7
+ // test/dsl-builtins.test.ts, in both directions: a builtin core defines and this
8
+ // catalog omits is reported as dsl/unknown-builtin on correct code.
4
9
 
5
10
  export interface Builtin {
6
11
  name: string;
@@ -71,6 +76,46 @@ export const BUILTINS: Builtin[] = [
71
76
  doc: "Load the referenced record for a FK column. Read its fields with `ref.get('field')`.",
72
77
  },
73
78
 
79
+ // Register reads. The first argument names a REGISTER (`module_cd.register_cd`,
80
+ // declared in that module's registers.json) and not an entity, so none of these
81
+ // carries `entityArg` — entity-code completion there would offer the wrong list.
82
+ {
83
+ name: "getBalance",
84
+ signature: "getBalance(register, dims?, asOf?)",
85
+ returns: "object",
86
+ doc: "Balance of an accumulation register per resource. A dimension left out of `dims` is summed over, so passing none gives the register's total. `asOf` reads as of a date instead of now.",
87
+ },
88
+ {
89
+ name: "getTurnover",
90
+ signature: "getTurnover(register, dims, from, to)",
91
+ returns: "object",
92
+ doc: "What moved through a register over an interval: `{in, out, net}` per resource. `dims` may be `null` to sum over every dimension; `from` and `to` are both required.",
93
+ },
94
+ {
95
+ name: "getSlice",
96
+ signature: "getSlice(register, dims, onDate?, mode?)",
97
+ returns: "object | null",
98
+ doc: "One record of an information register — the latest on or before `onDate`, or `null` when there is none. Returns the record plus `_period`. Unlike a balance, a dimension may NOT be omitted: a slice is one keyed record, not a sum.",
99
+ },
100
+ {
101
+ name: "getAccountBalance",
102
+ signature: "getAccountBalance(register, account, filter?, asOf?)",
103
+ returns: "object",
104
+ doc: "Balance of one account of an accounting register: `{debit, credit, net}` per resource. `filter` narrows by a dimension, or by an analytic kind the ACCOUNT declares — an analytic takes the key alone, or `{ entity, value }` to name one entity of a kind that is a union of several.",
105
+ },
106
+ {
107
+ name: "getAccountTurnover",
108
+ signature: "getAccountTurnover(register, account, filter, from, to)",
109
+ returns: "object",
110
+ doc: "What moved through one account over an interval: `{debit, credit, net}` per resource. `filter` narrows as in `getAccountBalance` and may be `null`; `from` and `to` are both required.",
111
+ },
112
+ {
113
+ name: "getCorrespondence",
114
+ signature: "getCorrespondence(register, debitAccount, creditAccount, filter, from, to)",
115
+ returns: "object",
116
+ doc: "What moved between two accounts over an interval. Needs `lineMode: \"compound\"` — a classic register records the other half of an entry as an untied second row and cannot answer this. `filter` narrows by dimensions the two sides share, never by an analytic (an analytic belongs to one account and this read names two).",
117
+ },
118
+
74
119
  // Messaging
75
120
  {
76
121
  name: "error",
package/src/index.ts CHANGED
@@ -148,7 +148,7 @@ export type {
148
148
  SetSection,
149
149
  TabGroupSection,
150
150
  } from "./card-layouts";
151
- export type { SeedDataFile } from "./seed-data";
151
+ export type { SeedDataFile, SeedDataRepeat } from "./seed-data";
152
152
  export type { ActionsFile, ActionDef, ActionExecutionMode } from "./actions";
153
153
 
154
154
  // Flag catalog — the only letters valid on an authored column, at field level and
package/src/reports.ts CHANGED
@@ -120,12 +120,33 @@ export interface ColumnDef {
120
120
  width?: number;
121
121
  }
122
122
 
123
+ /**
124
+ * An accounting register read over an interval: one row per account of the register's chart,
125
+ * with opening, turnover and closing debit/credit for one resource, netted per account.
126
+ */
127
+ export interface RegisterSource {
128
+ /** The register, `module_cd.register_cd`. */
129
+ name: string;
130
+ /** The one resource the six balance columns are about. */
131
+ resource: string;
132
+ /** Two date params, or the record of `entity` a key param finds and its two date columns. */
133
+ interval: { entity?: string; key?: string; from: string; to: string };
134
+ /** Chart columns in nav notation, `<chart>.<column>`. */
135
+ columns?: string[];
136
+ /** A filter over the chart, in the same nav notation. */
137
+ filter?: Filter;
138
+ /** Chart columns to sort by, in nav notation. */
139
+ sort?: SortClause[];
140
+ /** The query rollup without `leafKey` and `measures`. */
141
+ rollup?: { tree: string; treeKey: string; parentField: string; labels: string[]; order?: string };
142
+ }
143
+
123
144
  /** A report dataset (value in the report's `datasets` map). */
124
145
  export interface Dataset {
125
146
  /** Display label (used in panel headings if no `title`). */
126
147
  caption?: string;
127
- /** Q = SQL/entity query, S = stored procedure. */
128
- datasetType: "Q" | "S";
148
+ /** Q = SQL/entity query, S = stored procedure, R = an accounting register read over an interval. */
149
+ datasetType: "Q" | "S" | "R";
129
150
  /** Used when `datasetType` is 'Q'. */
130
151
  query?: ReportQuery;
131
152
  /**
@@ -134,6 +155,8 @@ export interface Dataset {
134
155
  * and never schema-qualified. `module.spCd` binds a dependency's procedure.
135
156
  */
136
157
  spCd?: string;
158
+ /** Used when `datasetType` is 'R'. */
159
+ register?: RegisterSource;
137
160
  /** Optional column metadata overrides: field code → override. */
138
161
  columnsDef?: Record<string, ColumnDef>;
139
162
  /**
@@ -188,7 +211,9 @@ export interface ReportLayout {
188
211
 
189
212
  /** A single report (value in the `ui/reports.json` map). */
190
213
  export interface ReportDef {
191
- /** Human-readable report title. */
214
+ /** Report name: page title, breadcrumb and menu entry. Omit and `description` is the name. */
215
+ label?: string;
216
+ /** What the report shows, under its name on the page. */
192
217
  description: string;
193
218
  layout: ReportLayout;
194
219
  /** Dataset code → dataset definition. */
package/src/seed-data.ts CHANGED
@@ -5,6 +5,14 @@
5
5
  export interface SeedDataFile {
6
6
  /** Target entity code. */
7
7
  entityCode: string;
8
- /** Records to insert; each is a `column_code → value` map. */
8
+ /** Records to insert; each is a `column_code → value` map. In `demo-data/` a value may be `{ "$f": "<formula>" }`. */
9
9
  records: Record<string, unknown>[];
10
+ /** `demo-data/` only: insert every record once per value of `@var`, `from`..`to` inclusive. */
11
+ repeat?: SeedDataRepeat;
12
+ }
13
+
14
+ export interface SeedDataRepeat {
15
+ var?: string;
16
+ from?: number;
17
+ to: number;
10
18
  }
package/src/settings.ts CHANGED
@@ -3,12 +3,8 @@
3
3
  /** Underlying primitive datatype for a setting. */
4
4
  export type SettingBaseDatatype = "string" | "number" | "bool" | "date" | "dateTime" | "time" | "json";
5
5
 
6
- /** A single setting definition (value in the settings map). */
7
- export interface SettingDef {
8
- /** Field type code (must match a `dforge.field_type` code). */
9
- fieldTypeCd: string;
10
- /** Underlying primitive datatype (older settings declare this explicitly). */
11
- baseDatatypeCd?: SettingBaseDatatype;
6
+ /** Properties carried by every setting regardless of where its control comes from. */
7
+ export interface SettingDefBase {
12
8
  /** Display label (preferred for new settings). */
13
9
  label?: string;
14
10
  /** Display label (older style). Prefer `label`. */
@@ -21,9 +17,26 @@ export interface SettingDef {
21
17
  formula?: string;
22
18
  /** If true, must be set somewhere in the folder chain for install to proceed. */
23
19
  required?: boolean;
24
- /** Field-type-specific parameters (dropdown options, min/max, lookup link, …). */
25
- params?: Record<string, unknown>;
26
20
  }
27
21
 
22
+ /** A setting declares its control inline or borrows it from a reusable column domain. */
23
+ export type SettingDef =
24
+ | (SettingDefBase & {
25
+ /** Field type code (must match a `dforge.field_type` code). */
26
+ fieldTypeCd: string;
27
+ /** Underlying primitive datatype (older settings declare this explicitly). */
28
+ baseDatatypeCd?: SettingBaseDatatype;
29
+ /** Field-type-specific parameters (dropdown options, min/max, lookup link, …). */
30
+ params?: Record<string, unknown>;
31
+ domain?: never;
32
+ })
33
+ | (SettingDefBase & {
34
+ /** Column domain supplying fieldTypeCd, baseDatatypeCd and params. */
35
+ domain: string;
36
+ fieldTypeCd?: never;
37
+ baseDatatypeCd?: never;
38
+ params?: never;
39
+ });
40
+
28
41
  /** A `settings.json` file: setting code → definition. */
29
42
  export type SettingsFile = Record<string, SettingDef>;
@@ -72,4 +72,11 @@ export interface SpColumnDef {
72
72
  width?: number;
73
73
  /** Control parameters, the same shape an entity column's `params` takes. */
74
74
  params?: Record<string, unknown>;
75
+ /**
76
+ * Reusable column domain supplying the control, datatype and option list.
77
+ * Unqualified resolves within this module, then tenant-created domains;
78
+ * `module_cd.domain_cd` binds to that module. Mutually exclusive with
79
+ * `fieldTypeCd`, `baseDatatypeCd` and `params`.
80
+ */
81
+ domain?: string;
75
82
  }