@weave-kit/engine 0.2.0 → 0.2.2
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/README.md +1 -0
- package/dist/adapters/auth/source.d.ts.map +1 -1
- package/dist/adapters/auth/source.js +4 -1
- package/dist/adapters/auth/source.js.map +1 -1
- package/dist/cli/index.js +1 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/core/object/validate/field.d.ts +5 -0
- package/dist/core/object/validate/field.d.ts.map +1 -0
- package/dist/core/object/validate/field.js +432 -0
- package/dist/core/object/validate/field.js.map +1 -0
- package/dist/core/object/validate/formulas.d.ts +8 -0
- package/dist/core/object/validate/formulas.d.ts.map +1 -0
- package/dist/core/object/validate/formulas.js +112 -0
- package/dist/core/object/validate/formulas.js.map +1 -0
- package/dist/core/object/validate/indexes.d.ts +5 -0
- package/dist/core/object/validate/indexes.d.ts.map +1 -0
- package/dist/core/object/validate/indexes.js +21 -0
- package/dist/core/object/validate/indexes.js.map +1 -0
- package/dist/core/object/validate/labels.d.ts +4 -0
- package/dist/core/object/validate/labels.d.ts.map +1 -0
- package/dist/core/object/validate/labels.js +21 -0
- package/dist/core/object/validate/labels.js.map +1 -0
- package/dist/core/object/validate/object.d.ts +21 -0
- package/dist/core/object/validate/object.d.ts.map +1 -0
- package/dist/core/object/validate/object.js +129 -0
- package/dist/core/object/validate/object.js.map +1 -0
- package/dist/core/object/validate/permissions.d.ts +4 -0
- package/dist/core/object/validate/permissions.d.ts.map +1 -0
- package/dist/core/object/validate/permissions.js +69 -0
- package/dist/core/object/validate/permissions.js.map +1 -0
- package/dist/core/object/validate/primitives.d.ts +34 -0
- package/dist/core/object/validate/primitives.d.ts.map +1 -0
- package/dist/core/object/validate/primitives.js +57 -0
- package/dist/core/object/validate/primitives.js.map +1 -0
- package/dist/core/object/validate.d.ts +5 -18
- package/dist/core/object/validate.d.ts.map +1 -1
- package/dist/core/object/validate.js +4 -816
- package/dist/core/object/validate.js.map +1 -1
- package/dist/core/script/index.d.ts +1 -1
- package/dist/core/script/index.d.ts.map +1 -1
- package/dist/core/script/index.js +1 -1
- package/dist/core/script/index.js.map +1 -1
- package/dist/core/script/source.d.ts +9 -0
- package/dist/core/script/source.d.ts.map +1 -1
- package/dist/core/script/source.js +46 -4
- package/dist/core/script/source.js.map +1 -1
- package/dist/runtime/sql-analyzer/index.d.ts +7 -0
- package/dist/runtime/sql-analyzer/index.d.ts.map +1 -1
- package/dist/runtime/sql-analyzer/index.js +29 -0
- package/dist/runtime/sql-analyzer/index.js.map +1 -1
- package/dist/subsystems/script/backend/isolated-vm.d.ts.map +1 -1
- package/dist/subsystems/script/backend/isolated-vm.js +3 -10
- package/dist/subsystems/script/backend/isolated-vm.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -2
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { FORMULA_EXCLUDED_ATTRS, FORMULA_TYPES, FormulaOperandError, checkOperands, detectCycle, extractRefs, inferType, parseFormula, typeCompatible, } from '../../formula/index.js';
|
|
2
|
+
import { FIELD_TYPES } from '../../types/values.js';
|
|
3
|
+
import { fail } from './primitives.js';
|
|
4
|
+
/**
|
|
5
|
+
* Same-object formula validation: exclusions, reference existence, operand/type
|
|
6
|
+
* checks and local formula-formula cycle detection.
|
|
7
|
+
*/
|
|
8
|
+
export function validateFormulas(fields, vc) {
|
|
9
|
+
const formulaFields = fields.filter((f) => f.formula !== undefined);
|
|
10
|
+
if (formulaFields.length === 0)
|
|
11
|
+
return;
|
|
12
|
+
const fieldByName = new Map(fields.map((f) => [f.name, f]));
|
|
13
|
+
const fieldTypeOf = (name) => {
|
|
14
|
+
const f = fieldByName.get(name);
|
|
15
|
+
if (f === undefined)
|
|
16
|
+
return undefined;
|
|
17
|
+
switch (f.type) {
|
|
18
|
+
case FIELD_TYPES.STRING:
|
|
19
|
+
case FIELD_TYPES.TEXT:
|
|
20
|
+
return FORMULA_TYPES.STRING;
|
|
21
|
+
case FIELD_TYPES.INTEGER:
|
|
22
|
+
case FIELD_TYPES.NUMBER:
|
|
23
|
+
case FIELD_TYPES.CURRENCY:
|
|
24
|
+
return FORMULA_TYPES.NUMBER;
|
|
25
|
+
case FIELD_TYPES.BOOLEAN:
|
|
26
|
+
return FORMULA_TYPES.BOOLEAN;
|
|
27
|
+
default:
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
for (const field of formulaFields) {
|
|
32
|
+
const formula = field.formula;
|
|
33
|
+
const fieldType = field.type;
|
|
34
|
+
for (const attr of Object.values(FORMULA_EXCLUDED_ATTRS)) {
|
|
35
|
+
if (field[attr] !== undefined) {
|
|
36
|
+
fail(vc, 'formula.excludedAttr', { attr });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
let ast;
|
|
40
|
+
try {
|
|
41
|
+
ast = parseFormula(formula);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
fail(vc, 'formula.syntax', { detail: err.message });
|
|
45
|
+
}
|
|
46
|
+
const { fields: refs, aggregates } = extractRefs(ast);
|
|
47
|
+
for (const ref of refs) {
|
|
48
|
+
const target = fieldByName.get(ref.parent ?? ref.name);
|
|
49
|
+
if (target === undefined) {
|
|
50
|
+
fail(vc, 'formula.refMissing', { field: ref.parent ?? ref.name });
|
|
51
|
+
}
|
|
52
|
+
const referenced = ref.parent === null ? target : fieldByName.get(ref.parent);
|
|
53
|
+
if (referenced !== undefined && ref.parent === null) {
|
|
54
|
+
if (referenced.type === FIELD_TYPES.RELATION ||
|
|
55
|
+
referenced.type === FIELD_TYPES.DETAILS ||
|
|
56
|
+
referenced.type === FIELD_TYPES.MULTI_RELATION ||
|
|
57
|
+
referenced.type === FIELD_TYPES.SEQ_NO) {
|
|
58
|
+
fail(vc, 'formula.refType', { type: referenced.type, field: ref.name });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else if (referenced !== undefined && ref.parent !== null) {
|
|
62
|
+
if (referenced.type !== FIELD_TYPES.RELATION && referenced.type !== FIELD_TYPES.DETAILS) {
|
|
63
|
+
fail(vc, 'formula.refType', { type: referenced.type, field: ref.parent });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
for (const agg of aggregates) {
|
|
68
|
+
const parent = fieldByName.get(agg.parent);
|
|
69
|
+
if (parent === undefined) {
|
|
70
|
+
fail(vc, 'formula.refMissing', { field: agg.parent });
|
|
71
|
+
}
|
|
72
|
+
else if (parent.type !== FIELD_TYPES.DETAILS) {
|
|
73
|
+
fail(vc, 'formula.refType', { type: parent.type, field: agg.parent });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
checkOperands(ast, fieldTypeOf);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
if (err instanceof FormulaOperandError) {
|
|
81
|
+
fail(vc, 'formula.operandType', { op: err.op, expected: err.expected, got: err.got });
|
|
82
|
+
}
|
|
83
|
+
fail(vc, 'formula.syntax', { detail: err.message });
|
|
84
|
+
}
|
|
85
|
+
const exprType = inferType(ast, fieldTypeOf);
|
|
86
|
+
if (exprType !== 'any' && !typeCompatible(fieldType, exprType)) {
|
|
87
|
+
fail(vc, 'formula.typeMismatch', { got: exprType, expected: fieldType });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const nodes = formulaFields.map((f) => f.name);
|
|
91
|
+
const edges = [];
|
|
92
|
+
for (const field of formulaFields) {
|
|
93
|
+
const formula = field.formula;
|
|
94
|
+
let ast;
|
|
95
|
+
try {
|
|
96
|
+
ast = parseFormula(formula);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const { fields: refs } = extractRefs(ast);
|
|
102
|
+
for (const ref of refs) {
|
|
103
|
+
if (ref.parent === null && nodes.includes(ref.name)) {
|
|
104
|
+
edges.push([field.name, ref.name]);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const cycle = detectCycle(nodes, edges);
|
|
109
|
+
if (cycle)
|
|
110
|
+
fail(vc, 'formula.cycle', { chain: cycle.join(' -> ') });
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=formulas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formulas.js","sourceRoot":"","sources":["../../../../src/core/object/validate/formulas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ObjectDefinition } from '../../types/index.js';
|
|
2
|
+
import { type Vc } from './primitives.js';
|
|
3
|
+
/** validate the optional indexes array (btree/gin/gist + non-empty string fields) */
|
|
4
|
+
export declare function validateIndexes(raw: unknown, vc: Vc): ObjectDefinition['indexes'] | undefined;
|
|
5
|
+
//# sourceMappingURL=indexes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexes.d.ts","sourceRoot":"","sources":["../../../../src/core/object/validate/indexes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAqC,KAAK,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAE7E,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,GAAG,gBAAgB,CAAC,SAAS,CAAC,GAAG,SAAS,CAc7F"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { fail, isRecord, INDEX_TYPE_VALUES } from './primitives.js';
|
|
2
|
+
/** validate the optional indexes array (btree/gin/gist + non-empty string fields) */
|
|
3
|
+
export function validateIndexes(raw, vc) {
|
|
4
|
+
if (raw === undefined)
|
|
5
|
+
return undefined;
|
|
6
|
+
if (!Array.isArray(raw))
|
|
7
|
+
fail(vc, 'index.notArray');
|
|
8
|
+
return raw.map((entry, i) => {
|
|
9
|
+
if (!isRecord(entry))
|
|
10
|
+
fail(vc, 'index.notObject', { i });
|
|
11
|
+
const type = entry.type;
|
|
12
|
+
if (typeof type !== 'string' || !INDEX_TYPE_VALUES.includes(type)) {
|
|
13
|
+
fail(vc, 'index.type.invalid', { i, types: INDEX_TYPE_VALUES.join('/') });
|
|
14
|
+
}
|
|
15
|
+
if (!Array.isArray(entry.fields) || entry.fields.length === 0 || !entry.fields.every((f) => typeof f === 'string')) {
|
|
16
|
+
fail(vc, 'index.fields.invalid', { i });
|
|
17
|
+
}
|
|
18
|
+
return { type: type, fields: entry.fields };
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=indexes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexes.js","sourceRoot":"","sources":["../../../../src/core/object/validate/indexes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,iBAAiB,EAAW,MAAM,iBAAiB,CAAC;AAE7E,qFAAqF;AACrF,MAAM,UAAU,eAAe,CAAC,GAAY,EAAE,EAAM;IAClD,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,IAAI,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;IACpD,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,IAAI,CAAC,EAAE,EAAE,iBAAiB,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACxB,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAClE,IAAI,CAAC,EAAE,EAAE,oBAAoB,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5E,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC;YACnH,IAAI,CAAC,EAAE,EAAE,sBAAsB,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,IAAgC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAkB,EAAE,CAAC;IACtF,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type Vc } from './primitives.js';
|
|
2
|
+
/** validate a labels map: keys must be valid BCP-47 locale tags, values non-empty strings */
|
|
3
|
+
export declare function validateLabels(raw: unknown, vc: Vc): Record<string, string> | undefined;
|
|
4
|
+
//# sourceMappingURL=labels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../../../../src/core/object/validate/labels.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAEtE,6FAA6F;AAC7F,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAavF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { fail, isRecord, LOCALE_TAG } from './primitives.js';
|
|
2
|
+
/** validate a labels map: keys must be valid BCP-47 locale tags, values non-empty strings */
|
|
3
|
+
export function validateLabels(raw, vc) {
|
|
4
|
+
if (raw === undefined)
|
|
5
|
+
return undefined;
|
|
6
|
+
if (!isRecord(raw))
|
|
7
|
+
fail(vc, 'field.labels.notObject');
|
|
8
|
+
const result = {};
|
|
9
|
+
for (const [locale, value] of Object.entries(raw)) {
|
|
10
|
+
if (!LOCALE_TAG.test(locale))
|
|
11
|
+
fail(vc, 'field.labels.locale.invalid', { locale });
|
|
12
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
13
|
+
fail(vc, 'field.labels.value.string', { locale });
|
|
14
|
+
}
|
|
15
|
+
result[locale] = value;
|
|
16
|
+
}
|
|
17
|
+
if (Object.keys(result).length === 0)
|
|
18
|
+
fail(vc, 'field.labels.empty');
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=labels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"labels.js","sourceRoot":"","sources":["../../../../src/core/object/validate/labels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAW,MAAM,iBAAiB,CAAC;AAEtE,6FAA6F;AAC7F,MAAM,UAAU,cAAc,CAAC,GAAY,EAAE,EAAM;IACjD,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,IAAI,CAAC,EAAE,EAAE,wBAAwB,CAAC,CAAC;IACvD,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,IAAI,CAAC,EAAE,EAAE,6BAA6B,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QAClF,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,IAAI,CAAC,EAAE,EAAE,2BAA2B,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QACpD,CAAC;QACD,MAAM,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;IACzB,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,EAAE,oBAAoB,CAAC,CAAC;IACrE,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Locale } from '../../i18n/index.js';
|
|
2
|
+
import type { ObjectDefinition } from '../../types/index.js';
|
|
3
|
+
export interface ValidateOptions {
|
|
4
|
+
/** directory name hint; must equal object name when provided */
|
|
5
|
+
nameHint?: string;
|
|
6
|
+
/** message locale; defaults to English */
|
|
7
|
+
locale?: Locale;
|
|
8
|
+
/**
|
|
9
|
+
* field-type whitelist (config `features.fieldTypes`). When provided, a field
|
|
10
|
+
* declaring a type outside the whitelist is rejected (fail-closed). Defaults
|
|
11
|
+
* to all types (gating is opt-in via config).
|
|
12
|
+
*/
|
|
13
|
+
allowedFieldTypes?: readonly string[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Validate a raw object definition (single object, self-contained checks only).
|
|
17
|
+
* Includes field validation, primary-key rules, titleTemplate placeholder checks
|
|
18
|
+
* and same-object formula validation. Cross-object checks live in buildGraph.
|
|
19
|
+
*/
|
|
20
|
+
export declare function validateObject(raw: unknown, options?: ValidateOptions): ObjectDefinition;
|
|
21
|
+
//# sourceMappingURL=object.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../../../../src/core/object/validate/object.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,KAAK,EAAmB,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAS9E,MAAM,WAAW,eAAe;IAC9B,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,gBAAgB,CA2FxF"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { DEFAULT_LOCALE } from '../../i18n/index.js';
|
|
2
|
+
import { SCHEMA_FORMAT_VERSION } from '../schema-version.js';
|
|
3
|
+
import { FIELD_TYPES, READ_SCOPES } from '../../types/values.js';
|
|
4
|
+
import { validateField } from './field.js';
|
|
5
|
+
import { validateFormulas } from './formulas.js';
|
|
6
|
+
import { validateIndexes } from './indexes.js';
|
|
7
|
+
import { validateLabels } from './labels.js';
|
|
8
|
+
import { validatePermissions } from './permissions.js';
|
|
9
|
+
import { fail, isRecord, expectString, SNAKE_CASE, SCALAR_TYPE_VALUES, TITLE_PLACEHOLDER_RE } from './primitives.js';
|
|
10
|
+
/**
|
|
11
|
+
* Validate a raw object definition (single object, self-contained checks only).
|
|
12
|
+
* Includes field validation, primary-key rules, titleTemplate placeholder checks
|
|
13
|
+
* and same-object formula validation. Cross-object checks live in buildGraph.
|
|
14
|
+
*/
|
|
15
|
+
export function validateObject(raw, options) {
|
|
16
|
+
const vc = { object: '(unknown)', locale: options?.locale ?? DEFAULT_LOCALE };
|
|
17
|
+
if (!isRecord(raw))
|
|
18
|
+
fail(vc, 'object.notObject');
|
|
19
|
+
const name = expectString(raw, 'name', vc);
|
|
20
|
+
if (name === undefined)
|
|
21
|
+
fail(vc, 'object.name.required');
|
|
22
|
+
vc.object = name;
|
|
23
|
+
if (!SNAKE_CASE.test(name))
|
|
24
|
+
fail(vc, 'object.name.snake', { name });
|
|
25
|
+
if (options?.nameHint !== undefined && options.nameHint !== name) {
|
|
26
|
+
fail(vc, 'object.nameHint.mismatch', { dir: options.nameHint, name });
|
|
27
|
+
}
|
|
28
|
+
// on-disk format version gate (fail-closed on unknown/future versions)
|
|
29
|
+
let schemaVersion;
|
|
30
|
+
const rawVersion = raw.schemaVersion;
|
|
31
|
+
if (rawVersion !== undefined) {
|
|
32
|
+
if (typeof rawVersion !== 'number' ||
|
|
33
|
+
!Number.isInteger(rawVersion) ||
|
|
34
|
+
rawVersion < 1 ||
|
|
35
|
+
rawVersion > SCHEMA_FORMAT_VERSION) {
|
|
36
|
+
fail(vc, 'schema.version.unsupported', {
|
|
37
|
+
version: String(rawVersion),
|
|
38
|
+
supported: SCHEMA_FORMAT_VERSION,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
schemaVersion = rawVersion;
|
|
42
|
+
}
|
|
43
|
+
if (raw.label !== undefined)
|
|
44
|
+
fail(vc, 'object.label.removed');
|
|
45
|
+
const labels = validateLabels(raw.labels, vc);
|
|
46
|
+
const description = expectString(raw, 'description', vc);
|
|
47
|
+
const rawFields = raw.fields;
|
|
48
|
+
if (!Array.isArray(rawFields) || rawFields.length === 0)
|
|
49
|
+
fail(vc, 'object.fields.required');
|
|
50
|
+
const fields = rawFields.map((f) => validateField(f, vc, options?.allowedFieldTypes));
|
|
51
|
+
const seen = new Set();
|
|
52
|
+
for (const field of fields) {
|
|
53
|
+
if (seen.has(field.name))
|
|
54
|
+
fail(vc, 'object.field.duplicate', { field: field.name });
|
|
55
|
+
seen.add(field.name);
|
|
56
|
+
}
|
|
57
|
+
validateFormulas(fields, vc);
|
|
58
|
+
const primaries = fields.filter((f) => f.primary);
|
|
59
|
+
if (primaries.length === 0)
|
|
60
|
+
fail(vc, 'object.primary.none');
|
|
61
|
+
if (primaries.length > 1)
|
|
62
|
+
fail(vc, 'object.primary.many');
|
|
63
|
+
const primaryField = primaries[0];
|
|
64
|
+
if (primaryField !== undefined && !SCALAR_TYPE_VALUES.includes(primaryField.type)) {
|
|
65
|
+
fail(vc, 'object.primary.scalarOnly', { type: primaryField.type });
|
|
66
|
+
}
|
|
67
|
+
if (primaryField !== undefined && primaryField.formula !== undefined) {
|
|
68
|
+
fail(vc, 'formula.excludedAttr', { attr: 'primary' });
|
|
69
|
+
}
|
|
70
|
+
const permissions = validatePermissions(raw.permissions, vc, fields);
|
|
71
|
+
const indexes = validateIndexes(raw.indexes, vc);
|
|
72
|
+
// alter: opt-in additive auto-DDL for an existing table (default false)
|
|
73
|
+
if (raw.alter !== undefined && typeof raw.alter !== 'boolean')
|
|
74
|
+
fail(vc, 'object.alter.boolean');
|
|
75
|
+
const alter = raw.alter === true;
|
|
76
|
+
const titleTemplate = validateTitleTemplate(raw.titleTemplate, fields, vc);
|
|
77
|
+
const ownershipFields = fields.filter((f) => f.ownership === true);
|
|
78
|
+
if (ownershipFields.length > 1)
|
|
79
|
+
fail(vc, 'field.ownership.many');
|
|
80
|
+
const teamFields = fields.filter((f) => f.team === true);
|
|
81
|
+
if (teamFields.length > 1)
|
|
82
|
+
fail(vc, 'field.team.many');
|
|
83
|
+
if (permissions !== undefined) {
|
|
84
|
+
const hasOwnership = ownershipFields.length > 0;
|
|
85
|
+
const hasTeam = teamFields.length > 0;
|
|
86
|
+
for (const [role, p] of Object.entries(permissions)) {
|
|
87
|
+
if (p.read === READ_SCOPES.OWN && !hasOwnership)
|
|
88
|
+
fail(vc, 'permission.own.ownershipField', { role });
|
|
89
|
+
if (p.read === READ_SCOPES.TEAM && !hasTeam)
|
|
90
|
+
fail(vc, 'permission.team.teamField', { role });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
schemaVersion,
|
|
95
|
+
name,
|
|
96
|
+
labels,
|
|
97
|
+
description,
|
|
98
|
+
fields,
|
|
99
|
+
permissions,
|
|
100
|
+
workflow: raw.workflow,
|
|
101
|
+
indexes,
|
|
102
|
+
titleTemplate,
|
|
103
|
+
alter,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/** validate titleTemplate placeholders reference existing scalar/seq_no fields */
|
|
107
|
+
function validateTitleTemplate(raw, fields, vc) {
|
|
108
|
+
if (raw === undefined)
|
|
109
|
+
return undefined;
|
|
110
|
+
if (typeof raw !== 'string')
|
|
111
|
+
fail(vc, 'title.notString');
|
|
112
|
+
const fieldMap = new Map(fields.map((f) => [f.name, f]));
|
|
113
|
+
for (const m of raw.matchAll(TITLE_PLACEHOLDER_RE)) {
|
|
114
|
+
const fieldName = m[1] ?? '';
|
|
115
|
+
const field = fieldMap.get(fieldName);
|
|
116
|
+
if (field === undefined) {
|
|
117
|
+
fail(vc, 'title.placeholder.missing', { field: fieldName });
|
|
118
|
+
}
|
|
119
|
+
else if (field.type === FIELD_TYPES.DETAILS ||
|
|
120
|
+
field.type === FIELD_TYPES.MULTI_RELATION) {
|
|
121
|
+
fail(vc, 'title.placeholder.relation', { field: fieldName, type: field.type });
|
|
122
|
+
}
|
|
123
|
+
else if (field.type === FIELD_TYPES.ENUM && field.multiple === true) {
|
|
124
|
+
fail(vc, 'title.placeholder.multiEnum', { field: fieldName });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return raw;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=object.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"object.js","sourceRoot":"","sources":["../../../../src/core/object/validate/object.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,oBAAoB,EAAW,MAAM,iBAAiB,CAAC;AAe9H;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,GAAY,EAAE,OAAyB;IACpE,MAAM,EAAE,GAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,cAAc,EAAE,CAAC;IAClF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,IAAI,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC;IAEjD,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;IAC3C,IAAI,IAAI,KAAK,SAAS;QAAE,IAAI,CAAC,EAAE,EAAE,sBAAsB,CAAC,CAAC;IACzD,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC;IACjB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,IAAI,CAAC,EAAE,EAAE,mBAAmB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,IAAI,OAAO,EAAE,QAAQ,KAAK,SAAS,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;QACjE,IAAI,CAAC,EAAE,EAAE,0BAA0B,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,uEAAuE;IACvE,IAAI,aAAiC,CAAC;IACtC,MAAM,UAAU,GAAG,GAAG,CAAC,aAAa,CAAC;IACrC,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,IACE,OAAO,UAAU,KAAK,QAAQ;YAC9B,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC;YAC7B,UAAU,GAAG,CAAC;YACd,UAAU,GAAG,qBAAqB,EAClC,CAAC;YACD,IAAI,CAAC,EAAE,EAAE,4BAA4B,EAAE;gBACrC,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC;gBAC3B,SAAS,EAAE,qBAAqB;aACjC,CAAC,CAAC;QACL,CAAC;QACD,aAAa,GAAG,UAAU,CAAC;IAC7B,CAAC;IAED,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,EAAE,EAAE,sBAAsB,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,YAAY,CAAC,GAAG,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC;IAEzD,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC;IAC7B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,EAAE,wBAAwB,CAAC,CAAC;IAE5F,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC;IACtF,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,EAAE,EAAE,wBAAwB,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACpF,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IACD,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAE7B,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAClD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,EAAE,qBAAqB,CAAC,CAAC;IAC5D,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,EAAE,EAAE,qBAAqB,CAAC,CAAC;IAC1D,MAAM,YAAY,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IAClC,IAAI,YAAY,KAAK,SAAS,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QAClF,IAAI,CAAC,EAAE,EAAE,2BAA2B,EAAE,EAAE,IAAI,EAAE,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,YAAY,KAAK,SAAS,IAAK,YAAqC,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC/F,IAAI,CAAC,EAAE,EAAE,sBAAsB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,WAAW,GAAG,mBAAmB,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;IACrE,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAEjD,wEAAwE;IACxE,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,EAAE,EAAE,sBAAsB,CAAC,CAAC;IAChG,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC;IAEjC,MAAM,aAAa,GAAG,qBAAqB,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;IAE3E,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,CAA6B,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC;IAChG,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,EAAE,EAAE,sBAAsB,CAAC,CAAC;IACjE,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,CAAwB,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACjF,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC;IAEvD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAG,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC;QAChD,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;QACtC,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;YACpD,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,GAAG,IAAI,CAAC,YAAY;gBAAE,IAAI,CAAC,EAAE,EAAE,+BAA+B,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YACrG,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,IAAI,IAAI,CAAC,OAAO;gBAAE,IAAI,CAAC,EAAE,EAAE,2BAA2B,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/F,CAAC;IACH,CAAC;IAED,OAAO;QACL,aAAa;QACb,IAAI;QACJ,MAAM;QACN,WAAW;QACX,MAAM;QACN,WAAW;QACX,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,OAAO;QACP,aAAa;QACb,KAAK;KACN,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,SAAS,qBAAqB,CAC5B,GAAY,EACZ,MAAyB,EACzB,EAAM;IAEN,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,IAAI,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC;QACnD,MAAM,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,CAAC,EAAE,EAAE,2BAA2B,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAC9D,CAAC;aAAM,IACL,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,OAAO;YAClC,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,cAAc,EACzC,CAAC;YACD,IAAI,CAAC,EAAE,EAAE,4BAA4B,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACjF,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,IAAI,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtE,IAAI,CAAC,EAAE,EAAE,6BAA6B,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { FieldDefinition, Permissions } from '../../types/index.js';
|
|
2
|
+
import { type Vc } from './primitives.js';
|
|
3
|
+
export declare function validatePermissions(raw: unknown, vc: Vc, fields: readonly FieldDefinition[]): Permissions | undefined;
|
|
4
|
+
//# sourceMappingURL=permissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../../../src/core/object/validate/permissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAa,MAAM,sBAAsB,CAAC;AAEpF,OAAO,EAAkB,KAAK,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAK1D,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,eAAe,EAAE,GAAG,WAAW,GAAG,SAAS,CAqCrH"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { FIELD_TYPES, READ_SCOPES } from '../../types/values.js';
|
|
2
|
+
import { fail, isRecord } from './primitives.js';
|
|
3
|
+
/** validate the permissions map: role -> read/create/update/delete/fields.exclude */
|
|
4
|
+
const READ_SCOPE_VALUES = Object.values(READ_SCOPES);
|
|
5
|
+
export function validatePermissions(raw, vc, fields) {
|
|
6
|
+
if (raw === undefined)
|
|
7
|
+
return undefined;
|
|
8
|
+
if (!isRecord(raw))
|
|
9
|
+
fail(vc, 'permission.notObject');
|
|
10
|
+
const result = {};
|
|
11
|
+
for (const [role, value] of Object.entries(raw)) {
|
|
12
|
+
if (!isRecord(value))
|
|
13
|
+
fail(vc, 'permission.role.notObject', { role });
|
|
14
|
+
if (value.read !== undefined && !READ_SCOPE_VALUES.includes(value.read)) {
|
|
15
|
+
fail(vc, 'permission.read.invalid', { role });
|
|
16
|
+
}
|
|
17
|
+
if (value.create !== undefined && typeof value.create !== 'boolean')
|
|
18
|
+
fail(vc, 'permission.create.boolean', { role });
|
|
19
|
+
if (value.delete !== undefined && typeof value.delete !== 'boolean')
|
|
20
|
+
fail(vc, 'permission.delete.boolean', { role });
|
|
21
|
+
if (value.update !== undefined) {
|
|
22
|
+
if (typeof value.update !== 'boolean' && (!Array.isArray(value.update) || !value.update.every((f) => typeof f === 'string'))) {
|
|
23
|
+
fail(vc, 'permission.update.invalid', { role });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (value.fields !== undefined) {
|
|
27
|
+
if (!isRecord(value.fields))
|
|
28
|
+
fail(vc, 'permission.fields.notObject', { role });
|
|
29
|
+
if (value.fields.exclude !== undefined && (!Array.isArray(value.fields.exclude) || !value.fields.exclude.every((f) => typeof f === 'string'))) {
|
|
30
|
+
fail(vc, 'permission.exclude.strings', { role });
|
|
31
|
+
}
|
|
32
|
+
if (value.fields.create !== undefined) {
|
|
33
|
+
if (!Array.isArray(value.fields.create) || !value.fields.create.every((f) => typeof f === 'string')) {
|
|
34
|
+
fail(vc, 'permission.createFields.strings', { role });
|
|
35
|
+
}
|
|
36
|
+
validateCreateFields(role, value.fields.create, fields, vc);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
result[role] = {
|
|
40
|
+
read: value.read,
|
|
41
|
+
create: value.create,
|
|
42
|
+
update: value.update,
|
|
43
|
+
delete: value.delete,
|
|
44
|
+
fields: value.fields,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
/** a create whitelist must name real fields and cover every required writable field */
|
|
50
|
+
function validateCreateFields(role, create, fields, vc) {
|
|
51
|
+
const byName = new Map(fields.map((f) => [f.name, f]));
|
|
52
|
+
const pk = fields.find((f) => f.primary)?.name;
|
|
53
|
+
for (const name of create) {
|
|
54
|
+
if (!byName.has(name))
|
|
55
|
+
fail(vc, 'permission.createFields.unknown', { role, field: name });
|
|
56
|
+
}
|
|
57
|
+
for (const field of fields) {
|
|
58
|
+
if (field.primary === true || field.name === pk)
|
|
59
|
+
continue;
|
|
60
|
+
const required = 'required' in field && field.required === true;
|
|
61
|
+
const readonly = field.system === true || field.type === FIELD_TYPES.SEQ_NO || field.formula !== undefined;
|
|
62
|
+
if (!required || readonly)
|
|
63
|
+
continue;
|
|
64
|
+
if (!create.includes(field.name)) {
|
|
65
|
+
fail(vc, 'permission.createFields.missingRequired', { role, field: field.name });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../../../src/core/object/validate/permissions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Locale, MessageKey } from '../../i18n/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Shared validation primitives: the validation context, the localized-fail
|
|
4
|
+
* helper, small attribute readers, and the value-array/regex constants reused
|
|
5
|
+
* across the object validators.
|
|
6
|
+
*/
|
|
7
|
+
/** validation context: object being validated + active locale */
|
|
8
|
+
export interface Vc {
|
|
9
|
+
object: string;
|
|
10
|
+
locale: Locale;
|
|
11
|
+
}
|
|
12
|
+
export declare function fail(vc: Vc, code: MessageKey, params?: Record<string, unknown>): never;
|
|
13
|
+
/** type guard: plain object (not array/null) */
|
|
14
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
15
|
+
/** read an optional string attribute; fails with a localized error if present but not a string */
|
|
16
|
+
export declare function expectString(record: Record<string, unknown>, key: string, vc: Vc): string | undefined;
|
|
17
|
+
/** read an optional boolean attribute; fails if present but not boolean */
|
|
18
|
+
export declare function expectBoolean(record: Record<string, unknown>, key: string, vc: Vc): boolean | undefined;
|
|
19
|
+
/** read an optional numeric attribute; fails if present but not a finite number */
|
|
20
|
+
export declare function expectNumber(record: Record<string, unknown>, key: string, vc: Vc): number | undefined;
|
|
21
|
+
/** read an optional positive integer attribute (used for lengths/precision/padding) */
|
|
22
|
+
export declare function expectPositiveInt(record: Record<string, unknown>, key: string, vc: Vc): number | undefined;
|
|
23
|
+
export declare const SNAKE_CASE: RegExp;
|
|
24
|
+
export declare const LOCALE_TAG: RegExp;
|
|
25
|
+
export declare const FIELD_TYPE_VALUES: readonly string[];
|
|
26
|
+
export declare const ON_DELETE_ACTION_VALUES: readonly string[];
|
|
27
|
+
export declare const INDEX_TYPE_VALUES: readonly string[];
|
|
28
|
+
export declare const SCALAR_TYPE_VALUES: readonly string[];
|
|
29
|
+
export declare const SEQUENCE_TOKEN_VALUES: readonly string[];
|
|
30
|
+
export declare const SEQUENCE_CYCLE_VALUES: readonly string[];
|
|
31
|
+
export declare const SEQUENCE_PLACEHOLDER: RegExp;
|
|
32
|
+
/** placeholders allowed in titleTemplate */
|
|
33
|
+
export declare const TITLE_PLACEHOLDER_RE: RegExp;
|
|
34
|
+
//# sourceMappingURL=primitives.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../../../src/core/object/validate/primitives.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAW9D;;;;GAIG;AAEH,iEAAiE;AACjE,MAAM,WAAW,EAAE;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,KAAK,CAE1F;AAED,gDAAgD;AAChD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED,kGAAkG;AAClG,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,MAAM,GAAG,SAAS,CAKrG;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,OAAO,GAAG,SAAS,CAKvG;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,MAAM,GAAG,SAAS,CAKrG;AAED,uFAAuF;AACvF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,MAAM,GAAG,SAAS,CAK1G;AAED,eAAO,MAAM,UAAU,QAAsB,CAAC;AAE9C,eAAO,MAAM,UAAU,QAAqC,CAAC;AAE7D,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAA+B,CAAC;AAC/E,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAAqC,CAAC;AAC3F,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAA+B,CAAC;AAC/E,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAAsC,CAAC;AACvF,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAAmC,CAAC;AACvF,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAAmC,CAAC;AAEvF,eAAO,MAAM,oBAAoB,QAAqB,CAAC;AAEvD,4CAA4C;AAC5C,eAAO,MAAM,oBAAoB,QAAe,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { SchemaError } from '../../types/errors.js';
|
|
2
|
+
import { FIELD_TYPES, INDEX_TYPES, ON_DELETE_ACTIONS, SCALAR_FIELD_TYPES, SEQUENCE_CYCLES, SEQUENCE_TOKENS, } from '../../types/values.js';
|
|
3
|
+
export function fail(vc, code, params = {}) {
|
|
4
|
+
throw new SchemaError(code, { object: vc.object, ...params }, vc.locale);
|
|
5
|
+
}
|
|
6
|
+
/** type guard: plain object (not array/null) */
|
|
7
|
+
export function isRecord(value) {
|
|
8
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
9
|
+
}
|
|
10
|
+
/** read an optional string attribute; fails with a localized error if present but not a string */
|
|
11
|
+
export function expectString(record, key, vc) {
|
|
12
|
+
const value = record[key];
|
|
13
|
+
if (value === undefined)
|
|
14
|
+
return undefined;
|
|
15
|
+
if (typeof value !== 'string')
|
|
16
|
+
fail(vc, 'field.attr.string', { attr: key });
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
/** read an optional boolean attribute; fails if present but not boolean */
|
|
20
|
+
export function expectBoolean(record, key, vc) {
|
|
21
|
+
const value = record[key];
|
|
22
|
+
if (value === undefined)
|
|
23
|
+
return undefined;
|
|
24
|
+
if (typeof value !== 'boolean')
|
|
25
|
+
fail(vc, 'field.attr.boolean', { attr: key });
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
/** read an optional numeric attribute; fails if present but not a finite number */
|
|
29
|
+
export function expectNumber(record, key, vc) {
|
|
30
|
+
const value = record[key];
|
|
31
|
+
if (value === undefined)
|
|
32
|
+
return undefined;
|
|
33
|
+
if (typeof value !== 'number' || Number.isNaN(value))
|
|
34
|
+
fail(vc, 'field.attr.number', { attr: key });
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
/** read an optional positive integer attribute (used for lengths/precision/padding) */
|
|
38
|
+
export function expectPositiveInt(record, key, vc) {
|
|
39
|
+
const value = expectNumber(record, key, vc);
|
|
40
|
+
if (value === undefined)
|
|
41
|
+
return undefined;
|
|
42
|
+
if (!Number.isInteger(value) || value <= 0)
|
|
43
|
+
fail(vc, 'field.attr.positiveInt', { attr: key });
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
export const SNAKE_CASE = /^[a-z][a-z0-9_]*$/;
|
|
47
|
+
export const LOCALE_TAG = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;
|
|
48
|
+
export const FIELD_TYPE_VALUES = Object.values(FIELD_TYPES);
|
|
49
|
+
export const ON_DELETE_ACTION_VALUES = Object.values(ON_DELETE_ACTIONS);
|
|
50
|
+
export const INDEX_TYPE_VALUES = Object.values(INDEX_TYPES);
|
|
51
|
+
export const SCALAR_TYPE_VALUES = Object.values(SCALAR_FIELD_TYPES);
|
|
52
|
+
export const SEQUENCE_TOKEN_VALUES = Object.values(SEQUENCE_TOKENS);
|
|
53
|
+
export const SEQUENCE_CYCLE_VALUES = Object.values(SEQUENCE_CYCLES);
|
|
54
|
+
export const SEQUENCE_PLACEHOLDER = /\{seq(?::\d+)?\}/;
|
|
55
|
+
/** placeholders allowed in titleTemplate */
|
|
56
|
+
export const TITLE_PLACEHOLDER_RE = /\{(\w+)\}/g;
|
|
57
|
+
//# sourceMappingURL=primitives.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primitives.js","sourceRoot":"","sources":["../../../../src/core/object/validate/primitives.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,21 +1,8 @@
|
|
|
1
|
-
import type { Locale } from '../i18n/index.js';
|
|
2
|
-
import type { ObjectDefinition } from '../types/index.js';
|
|
3
|
-
export interface ValidateOptions {
|
|
4
|
-
/** directory name hint; must equal object name when provided */
|
|
5
|
-
nameHint?: string;
|
|
6
|
-
/** message locale; defaults to English */
|
|
7
|
-
locale?: Locale;
|
|
8
|
-
/**
|
|
9
|
-
* field-type whitelist (config `features.fieldTypes`). When provided, a field
|
|
10
|
-
* declaring a type outside the whitelist is rejected (fail-closed). Defaults
|
|
11
|
-
* to all types (gating is opt-in via config).
|
|
12
|
-
*/
|
|
13
|
-
allowedFieldTypes?: readonly string[];
|
|
14
|
-
}
|
|
15
1
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
2
|
+
* Object validation entry point. The implementation is split by concern under
|
|
3
|
+
* `./validate/` (primitives, labels, field, permissions, indexes, formulas,
|
|
4
|
+
* object); this barrel keeps the stable `./validate.js` import path.
|
|
19
5
|
*/
|
|
20
|
-
export
|
|
6
|
+
export { validateObject } from './validate/object.js';
|
|
7
|
+
export type { ValidateOptions } from './validate/object.js';
|
|
21
8
|
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/core/object/validate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/core/object/validate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|