@dforge-core/metadata 0.0.4 → 0.0.6

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": "@dforge-core/metadata",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "Canonical dForge authoring registries — field types, base datatypes, column types, traits, data-view kinds and chart types — with derivation helpers. Runtime-dependency-free; the single source of truth shared by editors, the web app and the CLI.",
5
5
  "license": "MIT",
6
6
  "author": "dForge",
@@ -53,6 +53,7 @@
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/node": "^25.9.4",
56
+ "ajv": "^8.20.0",
56
57
  "typescript": "^6.0.3",
57
58
  "vitest": "^4.1.9"
58
59
  }
@@ -472,6 +472,16 @@
472
472
  "field": { "type": "string" }
473
473
  },
474
474
  "additionalProperties": false
475
+ },
476
+ "onDelete": {
477
+ "type": "string",
478
+ "enum": ["cascade", "setNull", "restrict", "noAction"],
479
+ "description": "FK ON DELETE behaviour. Default (omitted) = noAction (plain FK). 'cascade' deletes children with the parent; 'setNull' nulls the FK column (must be nullable)."
480
+ },
481
+ "onUpdate": {
482
+ "type": "string",
483
+ "enum": ["cascade", "setNull", "restrict", "noAction"],
484
+ "description": "FK ON UPDATE behaviour. Default (omitted) = noAction. Fires when a parent's key value changes — a no-op for immutable cuid PKs, but useful for entities keyed on a natural/mutable PK."
475
485
  }
476
486
  },
477
487
  "additionalProperties": false
@@ -52,7 +52,7 @@
52
52
  "vizType": {
53
53
  "type": "string",
54
54
  "enum": ["table", "chart", "kpi", "pivot", "tree", "markdown"],
55
- "description": "Visualization type. (Older packages may use `metric` for `kpi`.)"
55
+ "description": "Visualization type. For any chart the vizType is `chart`; the chart kind goes in `config.chartType`."
56
56
  },
57
57
  "datasetCd": {
58
58
  "type": "string",
@@ -61,9 +61,142 @@
61
61
  "title": { "type": "string" },
62
62
  "config": {
63
63
  "type": "object",
64
- "description": "Viz-type-specific configuration.\n- chart: { chartType ('bar'|'horizontalBar'|'stackedBar'|'combo'|'line'|'area'|'pie'|'doughnut'|'scatter'|'bubble'|'funnel'|'heatmap'), categoryCol, valueCol, agg, seriesCol?, sizeCol?, chartSize? ('sm'|'m'|'l'|'xl'), clickAction?, showTrend?, series? }. `series` (a single object OR an array) declares CROSS-SOURCE overlay series on bar/horizontalBar/line/area, each { source?, categoryCol, valueCol, agg, label? }; `source` names a sibling dataset code (omit = the panel's own dataset). Overlays share one category axis (union of category values; bar gaps fill 0, line/area gap with null).\n- kpi: { metrics: [ metric, ... ] }. Each metric is EITHER an aggregation metric { column, agg ('sum'|'avg'|'min'|'max'|'count'), display?, label?, target?, min?, max?, icon?, sparklineDimension? } OR a FORMULA metric { formula (e.g. '[won] / [all] * 100'), inputs: [ { alias, column, agg, source? } ], format?: { style?: 'number'|'percent', decimals? }, display?, label? }. A formula input's `source` names a sibling dataset code for CROSS-DATASET metrics (omit = the panel's own dataset). Auto format (omit `format.style`) inherits the first input column's own formatter (currency/grouping).\n- table: { groupRules, aggregations, colorRules }."
64
+ "description": "Viz-type-specific configuration. `kpi` and `chart` are structurally validated (see kpiConfig / chartConfig below); `table`/`pivot`/`tree`/`markdown` accept any object."
65
65
  }
66
66
  },
67
+ "additionalProperties": false,
68
+ "allOf": [
69
+ {
70
+ "if": { "required": ["vizType"], "properties": { "vizType": { "const": "kpi" } } },
71
+ "then": { "properties": { "config": { "$ref": "#/$defs/kpiConfig" } } }
72
+ },
73
+ {
74
+ "if": { "required": ["vizType"], "properties": { "vizType": { "const": "chart" } } },
75
+ "then": { "properties": { "config": { "$ref": "#/$defs/chartConfig" } } }
76
+ }
77
+ ]
78
+ },
79
+
80
+ "aggFunc": {
81
+ "type": "string",
82
+ "enum": ["sum", "avg", "min", "max", "count"],
83
+ "description": "Aggregation function."
84
+ },
85
+
86
+ "kpiConfig": {
87
+ "type": "object",
88
+ "description": "KPI panel config: one or more metric cards.",
89
+ "required": ["metrics"],
90
+ "properties": {
91
+ "metrics": {
92
+ "type": "array",
93
+ "minItems": 1,
94
+ "items": { "$ref": "#/$defs/kpiMetric" }
95
+ }
96
+ },
97
+ "additionalProperties": false
98
+ },
99
+
100
+ "kpiMetric": {
101
+ "type": "object",
102
+ "description": "A KPI metric — EITHER an aggregation metric (`column` + `agg`, and no formula/inputs) OR a formula metric (`formula` + `inputs`, and no column/agg).",
103
+ "properties": {
104
+ "column": { "type": "string", "description": "Column to aggregate (aggregation metric)." },
105
+ "agg": { "$ref": "#/$defs/aggFunc" },
106
+ "formula": { "type": "string", "description": "Expression over `[alias]` inputs, e.g. '[won] / [all] * 100' (formula metric)." },
107
+ "inputs": {
108
+ "type": "array",
109
+ "minItems": 1,
110
+ "description": "Named aggregation inputs the formula references by `[alias]`.",
111
+ "items": { "$ref": "#/$defs/kpiInput" }
112
+ },
113
+ "format": { "$ref": "#/$defs/metricFormat" },
114
+ "display": { "type": "string", "enum": ["value", "gauge", "progress", "sparkline", "icon"] },
115
+ "label": { "type": "string" },
116
+ "target": { "type": "number" },
117
+ "min": { "type": "number" },
118
+ "max": { "type": "number" },
119
+ "icon": { "type": "string" },
120
+ "sparklineDimension": { "type": "string" }
121
+ },
122
+ "additionalProperties": false,
123
+ "allOf": [
124
+ {
125
+ "if": { "required": ["formula"] },
126
+ "then": {
127
+ "required": ["formula", "inputs"],
128
+ "not": { "anyOf": [ { "required": ["column"] }, { "required": ["agg"] } ] }
129
+ },
130
+ "else": {
131
+ "required": ["column", "agg"],
132
+ "not": { "anyOf": [ { "required": ["formula"] }, { "required": ["inputs"] } ] }
133
+ }
134
+ }
135
+ ]
136
+ },
137
+
138
+ "kpiInput": {
139
+ "type": "object",
140
+ "description": "One named aggregation a formula metric references by `[alias]`.",
141
+ "required": ["alias", "column", "agg"],
142
+ "properties": {
143
+ "alias": { "type": "string", "description": "Token used in the formula as `[alias]`." },
144
+ "column": { "type": "string" },
145
+ "agg": { "$ref": "#/$defs/aggFunc" },
146
+ "source": { "type": "string", "description": "Sibling dataset code to aggregate over (CROSS-DATASET); omit = the panel's own dataset." }
147
+ },
148
+ "additionalProperties": false
149
+ },
150
+
151
+ "metricFormat": {
152
+ "type": "object",
153
+ "description": "Formula-result format. OMIT for Auto — inherits the first input column's own formatter (currency/grouping).",
154
+ "properties": {
155
+ "style": { "type": "string", "enum": ["number", "percent"] },
156
+ "decimals": { "type": "integer", "minimum": 0 }
157
+ },
158
+ "additionalProperties": false
159
+ },
160
+
161
+ "chartConfig": {
162
+ "type": "object",
163
+ "description": "Chart panel config. The chart kind is `chartType`; the panel `vizType` is always `chart`.",
164
+ "required": ["chartType", "categoryCol", "valueCol"],
165
+ "properties": {
166
+ "chartType": {
167
+ "type": "string",
168
+ "enum": ["bar", "horizontalBar", "stackedBar", "combo", "line", "area", "pie", "doughnut", "scatter", "bubble", "funnel", "heatmap"]
169
+ },
170
+ "categoryCol": { "type": "string" },
171
+ "valueCol": { "type": "string" },
172
+ "agg": { "$ref": "#/$defs/aggFunc" },
173
+ "seriesCol": { "type": "string", "description": "Split-by dimension (same dataset)." },
174
+ "sizeCol": { "type": "string", "description": "Bubble radius column." },
175
+ "chartSize": { "type": "string", "enum": ["sm", "m", "l", "xl"] },
176
+ "clickAction": { "type": "string", "enum": ["crossFilter", "drillThrough", "none"] },
177
+ "showTrend": { "type": "boolean" },
178
+ "series": {
179
+ "description": "CROSS-SOURCE overlay series (bar/horizontalBar/line/area) — a single series OR an array. Each aligns on the shared category axis.",
180
+ "oneOf": [
181
+ { "$ref": "#/$defs/chartSeries" },
182
+ { "type": "array", "items": { "$ref": "#/$defs/chartSeries" } }
183
+ ]
184
+ }
185
+ },
186
+ "additionalProperties": false
187
+ },
188
+
189
+ "chartSeries": {
190
+ "type": "object",
191
+ "description": "One cross-source overlay series.",
192
+ "required": ["categoryCol", "valueCol", "agg"],
193
+ "properties": {
194
+ "source": { "type": "string", "description": "Sibling dataset code; omit = the panel's own dataset." },
195
+ "categoryCol": { "type": "string" },
196
+ "valueCol": { "type": "string" },
197
+ "agg": { "$ref": "#/$defs/aggFunc" },
198
+ "label": { "type": "string" }
199
+ },
67
200
  "additionalProperties": false
68
201
  },
69
202
 
@@ -140,11 +273,13 @@
140
273
  "leafKey": { "type": "string", "description": "Column on the query entity identifying the tree node a row belongs to (e.g. 'account_id' on balance_register)." },
141
274
  "measures": {
142
275
  "type": "array",
276
+ "minItems": 1,
143
277
  "items": { "type": "string" },
144
278
  "description": "Value column codes (on the query entity) to SUM into ancestors. Must be additively-rollable."
145
279
  },
146
280
  "labels": {
147
281
  "type": "array",
282
+ "minItems": 1,
148
283
  "items": { "type": "string" },
149
284
  "description": "Node-describing columns, expressed as the report column keys ('account.account_code'). Sourced from the tree entity's physical column (the segment after the dot); emitted under the same key so the report layout is unchanged."
150
285
  },