@objectstack/lint 15.1.0 → 16.0.0-rc.0
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/dist/index.cjs +251 -69
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -8
- package/dist/index.d.ts +61 -8
- package/dist/index.js +250 -69
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -20,14 +20,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
APPROVAL_APPROVER_NOT_MEMBERSHIP_TIER: () => APPROVAL_APPROVER_NOT_MEMBERSHIP_TIER,
|
|
24
|
+
APPROVAL_APPROVER_TYPE_DEPRECATED: () => APPROVAL_APPROVER_TYPE_DEPRECATED,
|
|
23
25
|
APPROVAL_APPROVER_TYPE_UNKNOWN: () => APPROVAL_APPROVER_TYPE_UNKNOWN,
|
|
24
26
|
APPROVAL_ESCALATION_REASSIGN_NO_TARGET: () => APPROVAL_ESCALATION_REASSIGN_NO_TARGET,
|
|
25
|
-
APPROVAL_ROLE_NOT_MEMBERSHIP_TIER: () => APPROVAL_ROLE_NOT_MEMBERSHIP_TIER,
|
|
26
27
|
CAPABILITY_REFERENCE_UNKNOWN: () => CAPABILITY_REFERENCE_UNKNOWN,
|
|
27
28
|
CHART_CONFIG_MISSING: () => CHART_CONFIG_MISSING,
|
|
28
29
|
CHART_FIELD_UNKNOWN: () => CHART_FIELD_UNKNOWN,
|
|
29
30
|
FIELD_GROUP_EMPTY: () => FIELD_GROUP_EMPTY,
|
|
30
31
|
FIELD_GROUP_UNDECLARED: () => FIELD_GROUP_UNDECLARED,
|
|
32
|
+
FLOW_DRAFT_STATUS_AMBIGUOUS: () => FLOW_DRAFT_STATUS_AMBIGUOUS,
|
|
33
|
+
FLOW_TRIGGER_UNKNOWN_OBJECT: () => FLOW_TRIGGER_UNKNOWN_OBJECT,
|
|
31
34
|
FORM_COLSPAN_ABSOLUTE: () => FORM_COLSPAN_ABSOLUTE,
|
|
32
35
|
FORM_FIELD_UNKNOWN: () => FORM_FIELD_UNKNOWN,
|
|
33
36
|
LIST_VIEW_FILTERS_IN_VIEWS_MODE: () => LIST_VIEW_FILTERS_IN_VIEWS_MODE,
|
|
@@ -53,6 +56,7 @@ __export(index_exports, {
|
|
|
53
56
|
TABLE_COUNT_ONLY: () => TABLE_COUNT_ONLY,
|
|
54
57
|
TITLE_FORMAT_RETIRED: () => TITLE_FORMAT_RETIRED,
|
|
55
58
|
TITLE_UNRESOLVABLE: () => TITLE_UNRESOLVABLE,
|
|
59
|
+
VIEW_CONTAINER_SHAPE: () => VIEW_CONTAINER_SHAPE,
|
|
56
60
|
VISIBILITY_ALIAS_DEPRECATED: () => VISIBILITY_ALIAS_DEPRECATED,
|
|
57
61
|
VISIBILITY_ROOT_MISLAYERED: () => VISIBILITY_ROOT_MISLAYERED,
|
|
58
62
|
WIDGET_DATASET_UNKNOWN: () => WIDGET_DATASET_UNKNOWN,
|
|
@@ -62,6 +66,7 @@ __export(index_exports, {
|
|
|
62
66
|
diffAccessMatrix: () => diffAccessMatrix,
|
|
63
67
|
validateApprovalApprovers: () => validateApprovalApprovers,
|
|
64
68
|
validateCapabilityReferences: () => validateCapabilityReferences,
|
|
69
|
+
validateFlowTriggerReadiness: () => validateFlowTriggerReadiness,
|
|
65
70
|
validateFormLayout: () => validateFormLayout,
|
|
66
71
|
validateJsxPages: () => validateJsxPages,
|
|
67
72
|
validateListViewMode: () => validateListViewMode,
|
|
@@ -73,6 +78,7 @@ __export(index_exports, {
|
|
|
73
78
|
validateSecurityPosture: () => validateSecurityPosture,
|
|
74
79
|
validateSemanticRoles: () => validateSemanticRoles,
|
|
75
80
|
validateStackExpressions: () => validateStackExpressions,
|
|
81
|
+
validateViewContainers: () => validateViewContainers,
|
|
76
82
|
validateVisibilityPredicates: () => validateVisibilityPredicates,
|
|
77
83
|
validateWidgetBindings: () => validateWidgetBindings
|
|
78
84
|
});
|
|
@@ -87,6 +93,18 @@ var CHART_FIELD_UNKNOWN = "chart-field-unknown";
|
|
|
87
93
|
var CHART_CONFIG_MISSING = "chart-config-missing";
|
|
88
94
|
var TABLE_COUNT_ONLY = "table-count-only";
|
|
89
95
|
var MEASURE_AGGREGATE_INCOHERENT = "measure-aggregate-incoherent";
|
|
96
|
+
var WIDGET_LEGACY_ANALYTICS_SHAPE = "widget-legacy-analytics-shape";
|
|
97
|
+
var WIDGET_LEGACY_ANALYTICS_UNRENDERABLE = "widget-legacy-analytics-unrenderable";
|
|
98
|
+
var LEGACY_ANALYTICS_KEYS = [
|
|
99
|
+
"categoryField",
|
|
100
|
+
"valueField",
|
|
101
|
+
"xAxisField",
|
|
102
|
+
"yAxisFields",
|
|
103
|
+
"aggregate",
|
|
104
|
+
"aggregation",
|
|
105
|
+
"rowField",
|
|
106
|
+
"columnField"
|
|
107
|
+
];
|
|
90
108
|
function asArray(v) {
|
|
91
109
|
if (Array.isArray(v)) return v;
|
|
92
110
|
if (v && typeof v === "object") {
|
|
@@ -208,6 +226,29 @@ function validateWidgetBindings(stack) {
|
|
|
208
226
|
if (f.severity === "warning" && suppressed(f.rule)) return;
|
|
209
227
|
findings.push({ ...f, where, path });
|
|
210
228
|
};
|
|
229
|
+
const legacyUsed = LEGACY_ANALYTICS_KEYS.filter((k) => w[k] !== void 0);
|
|
230
|
+
if (legacyUsed.length > 0) {
|
|
231
|
+
const optionsData = typeof w.options === "object" && w.options !== null && w.options.data !== void 0;
|
|
232
|
+
const hasDataSource = w.dataset !== void 0 || w.object !== void 0 || w.data !== void 0 || optionsData;
|
|
233
|
+
const keyList = legacyUsed.map((k) => `\`${k}\``).join(", ");
|
|
234
|
+
const plural = legacyUsed.length > 1;
|
|
235
|
+
const datasetHint = `Bind a semantic dataset and select fields BY NAME: \`dataset: '<name>', dimensions: [...], values: [...]\`. Dataset-bound widgets render through DatasetWidget (pivot rows/cols come from \`dimensions\`, cell values from \`values\`).`;
|
|
236
|
+
if (!hasDataSource) {
|
|
237
|
+
push({
|
|
238
|
+
severity: "error",
|
|
239
|
+
rule: WIDGET_LEGACY_ANALYTICS_UNRENDERABLE,
|
|
240
|
+
message: `sets legacy analytics key${plural ? "s" : ""} ${keyList} (removed by the ADR-0021 single-form cutover) and binds no data source (no \`dataset\`, \`object\`, or inline \`data\`) \u2014 it renders nothing.`,
|
|
241
|
+
hint: `${datasetHint} The renderer ignores the legacy keys, so without a data source this widget has no data at all.`
|
|
242
|
+
});
|
|
243
|
+
} else {
|
|
244
|
+
push({
|
|
245
|
+
severity: "warning",
|
|
246
|
+
rule: WIDGET_LEGACY_ANALYTICS_SHAPE,
|
|
247
|
+
message: `sets legacy analytics key${plural ? "s" : ""} ${keyList} that the ADR-0021 single-form cutover removed \u2014 the dashboard renderer ignores ${plural ? "them" : "it"}.`,
|
|
248
|
+
hint: `${datasetHint} These inline keys are a no-op. Suppress with suppressWarnings: ['${WIDGET_LEGACY_ANALYTICS_SHAPE}'] if intentional.`
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
211
252
|
const dsName = typeof w.dataset === "string" ? w.dataset : void 0;
|
|
212
253
|
const dataset = dsName ? datasets.get(dsName) : void 0;
|
|
213
254
|
if (dsName && !dataset) {
|
|
@@ -328,17 +369,42 @@ function buildFieldIndex(objects) {
|
|
|
328
369
|
}
|
|
329
370
|
return idx;
|
|
330
371
|
}
|
|
372
|
+
function buildFieldTypeIndex(objects) {
|
|
373
|
+
const idx = /* @__PURE__ */ new Map();
|
|
374
|
+
for (const obj of objects) {
|
|
375
|
+
const name = typeof obj.name === "string" ? obj.name : void 0;
|
|
376
|
+
if (!name) continue;
|
|
377
|
+
const fields = obj.fields;
|
|
378
|
+
const types = {};
|
|
379
|
+
if (Array.isArray(fields)) {
|
|
380
|
+
for (const f of fields) {
|
|
381
|
+
const fn = f?.name;
|
|
382
|
+
const ft = f?.type;
|
|
383
|
+
if (typeof fn === "string" && typeof ft === "string") types[fn] = ft;
|
|
384
|
+
}
|
|
385
|
+
} else if (fields && typeof fields === "object") {
|
|
386
|
+
for (const [fn, def] of Object.entries(fields)) {
|
|
387
|
+
const ft = def?.type;
|
|
388
|
+
if (typeof ft === "string") types[fn] = ft;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
idx.set(name, types);
|
|
392
|
+
}
|
|
393
|
+
return idx;
|
|
394
|
+
}
|
|
331
395
|
function validateStackExpressions(stack) {
|
|
332
396
|
const issues = [];
|
|
333
397
|
const objects = asArray2(stack.objects);
|
|
334
398
|
const fieldIndex = buildFieldIndex(objects);
|
|
399
|
+
const fieldTypeIndex = buildFieldTypeIndex(objects);
|
|
335
400
|
const check = (where, raw, objectName, scope = "flattened") => {
|
|
336
401
|
if (raw == null) return;
|
|
337
402
|
const fields = objectName ? fieldIndex.get(objectName) : void 0;
|
|
403
|
+
const fieldTypes = objectName ? fieldTypeIndex.get(objectName) : void 0;
|
|
338
404
|
const res = (0, import_formula.validateExpression)(
|
|
339
405
|
"predicate",
|
|
340
406
|
raw,
|
|
341
|
-
objectName ? { objectName, fields, scope } : { scope }
|
|
407
|
+
objectName ? { objectName, fields, fieldTypes, scope } : { scope }
|
|
342
408
|
);
|
|
343
409
|
for (const e of res.errors) issues.push({ where, message: e.message, source: e.source, severity: "error" });
|
|
344
410
|
for (const w of res.warnings) issues.push({ where, message: w.message, source: w.source, severity: "warning" });
|
|
@@ -386,19 +452,6 @@ function validateStackExpressions(stack) {
|
|
|
386
452
|
}
|
|
387
453
|
const fields = obj.fields;
|
|
388
454
|
const fieldList = Array.isArray(fields) ? fields : fields && typeof fields === "object" ? Object.values(fields) : [];
|
|
389
|
-
if (obj.external != null) {
|
|
390
|
-
const fieldEntries = Array.isArray(fields) ? fields.map((f) => [f?.name ?? "?", f]) : fields && typeof fields === "object" ? Object.entries(fields) : [];
|
|
391
|
-
for (const [fname, fdef] of fieldEntries) {
|
|
392
|
-
if (fdef && typeof fdef === "object" && fdef.columnName != null) {
|
|
393
|
-
issues.push({
|
|
394
|
-
where: `object '${objectName}' \xB7 field '${fname}'`,
|
|
395
|
-
message: `external object '${objectName}': field '${fname}' sets columnName='${String(fdef.columnName)}', which is not supported on federated objects (ADR-0062 D7). The driver's query pipeline ignores field.columnName for external objects; map remote columns via the datasource's external.columnMap instead.`,
|
|
396
|
-
source: `columnName='${String(fdef.columnName)}'`,
|
|
397
|
-
severity: "error"
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
455
|
for (const f of fieldList) {
|
|
403
456
|
if (f && typeof f === "object") {
|
|
404
457
|
const fname = f.name ?? "?";
|
|
@@ -410,7 +463,7 @@ function validateStackExpressions(stack) {
|
|
|
410
463
|
const res = (0, import_formula.validateExpression)(
|
|
411
464
|
"value",
|
|
412
465
|
f.formula,
|
|
413
|
-
objectName ? { objectName, fields: fieldIndex.get(objectName), scope: "record" } : { scope: "record" }
|
|
466
|
+
objectName ? { objectName, fields: fieldIndex.get(objectName), fieldTypes: fieldTypeIndex.get(objectName), scope: "record" } : { scope: "record" }
|
|
414
467
|
);
|
|
415
468
|
const fieldWhere = `object '${objectName}' \xB7 field '${f.name ?? "?"}' formula`;
|
|
416
469
|
for (const e of res.errors) issues.push({ where: fieldWhere, message: e.message, source: e.source, severity: "error" });
|
|
@@ -517,6 +570,117 @@ function validateListViewMode(stack) {
|
|
|
517
570
|
return out;
|
|
518
571
|
}
|
|
519
572
|
|
|
573
|
+
// src/validate-flow-trigger-readiness.ts
|
|
574
|
+
var FLOW_TRIGGER_UNKNOWN_OBJECT = "flow-trigger-unknown-object";
|
|
575
|
+
var FLOW_DRAFT_STATUS_AMBIGUOUS = "flow-draft-status-ambiguous";
|
|
576
|
+
function asArray4(v) {
|
|
577
|
+
if (Array.isArray(v)) return v;
|
|
578
|
+
if (v && typeof v === "object") {
|
|
579
|
+
return Object.entries(v).map(([name, def]) => ({
|
|
580
|
+
name,
|
|
581
|
+
...def
|
|
582
|
+
}));
|
|
583
|
+
}
|
|
584
|
+
return [];
|
|
585
|
+
}
|
|
586
|
+
function startNodeOf(flow) {
|
|
587
|
+
const nodes = Array.isArray(flow.nodes) ? flow.nodes : [];
|
|
588
|
+
const index = nodes.findIndex((n) => n?.type === "start");
|
|
589
|
+
return index >= 0 ? { node: nodes[index], index } : void 0;
|
|
590
|
+
}
|
|
591
|
+
function validateFlowTriggerReadiness(stack) {
|
|
592
|
+
const findings = [];
|
|
593
|
+
const flows = asArray4(stack.flows);
|
|
594
|
+
if (flows.length === 0) return findings;
|
|
595
|
+
const objectNames = new Set(
|
|
596
|
+
asArray4(stack.objects).map((o) => typeof o.name === "string" ? o.name : void 0).filter((n) => !!n)
|
|
597
|
+
);
|
|
598
|
+
flows.forEach((flow, flowIndex) => {
|
|
599
|
+
const flowName = typeof flow.name === "string" ? flow.name : `#${flowIndex}`;
|
|
600
|
+
const start = startNodeOf(flow);
|
|
601
|
+
const config = start?.node.config ?? {};
|
|
602
|
+
const triggerType = typeof config.triggerType === "string" ? config.triggerType : void 0;
|
|
603
|
+
const isRecordTriggered = !!triggerType && triggerType.startsWith("record-");
|
|
604
|
+
const isTimeRelative = config.timeRelative != null && typeof config.timeRelative === "object";
|
|
605
|
+
const isAutoTriggered = isRecordTriggered || triggerType === "api" || config.schedule != null || isTimeRelative || flow.type === "schedule" || flow.type === "api";
|
|
606
|
+
if (isRecordTriggered && start) {
|
|
607
|
+
const objectName = typeof config.objectName === "string" ? config.objectName : void 0;
|
|
608
|
+
if (objectName && !objectNames.has(objectName) && !objectName.startsWith("sys_")) {
|
|
609
|
+
findings.push({
|
|
610
|
+
severity: "warning",
|
|
611
|
+
rule: FLOW_TRIGGER_UNKNOWN_OBJECT,
|
|
612
|
+
where: `flow "${flowName}" \u203A start node`,
|
|
613
|
+
path: `flows[${flowIndex}].nodes[${start.index}].config.objectName`,
|
|
614
|
+
message: `targets object '${objectName}', which this stack does not define \u2014 if the name is wrong, the flow will never fire (and the runtime stays silent about it).`,
|
|
615
|
+
hint: `Object names match exactly. Check config.objectName against the object's registered name (e.g. 'app_candidate', not 'candidate'). If the object comes from another installed package, this warning can be ignored.`
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
if (isTimeRelative && start) {
|
|
620
|
+
const tr = config.timeRelative;
|
|
621
|
+
const objectName = typeof tr.object === "string" ? tr.object : void 0;
|
|
622
|
+
if (objectName && !objectNames.has(objectName) && !objectName.startsWith("sys_")) {
|
|
623
|
+
findings.push({
|
|
624
|
+
severity: "warning",
|
|
625
|
+
rule: FLOW_TRIGGER_UNKNOWN_OBJECT,
|
|
626
|
+
where: `flow "${flowName}" \u203A start node`,
|
|
627
|
+
path: `flows[${flowIndex}].nodes[${start.index}].config.timeRelative.object`,
|
|
628
|
+
message: `sweeps object '${objectName}', which this stack does not define \u2014 if the name is wrong, the sweep will match nothing (and the runtime stays quiet about it).`,
|
|
629
|
+
hint: `Object names match exactly. Check config.timeRelative.object against the object's registered name. If the object comes from another installed package, this warning can be ignored.`
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
if (isAutoTriggered && (flow.status == null || flow.status === "draft")) {
|
|
634
|
+
findings.push({
|
|
635
|
+
severity: "warning",
|
|
636
|
+
rule: FLOW_DRAFT_STATUS_AMBIGUOUS,
|
|
637
|
+
where: `flow "${flowName}"`,
|
|
638
|
+
path: `flows[${flowIndex}].status`,
|
|
639
|
+
message: `has status 'draft' (the default when none is authored). Draft flows DO still fire their triggers (only 'obsolete'/'invalid' disable), so the intent is ambiguous.`,
|
|
640
|
+
hint: `Declare status: 'active' to arm it deliberately, or status: 'obsolete' to disable it.`
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
return findings;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// src/validate-view-containers.ts
|
|
648
|
+
var VIEW_CONTAINER_SHAPE = "view-container-shape";
|
|
649
|
+
var CONTAINER_SLOT_KEYS = ["list", "form", "listViews", "formViews"];
|
|
650
|
+
function asEntries(v) {
|
|
651
|
+
if (Array.isArray(v)) return v.map((value, i) => ({ key: `[${i}]`, value }));
|
|
652
|
+
if (v && typeof v === "object") {
|
|
653
|
+
return Object.entries(v).map(([name, value]) => ({ key: `.${name}`, value }));
|
|
654
|
+
}
|
|
655
|
+
return [];
|
|
656
|
+
}
|
|
657
|
+
function containerViewCount(rec) {
|
|
658
|
+
const named = (slot) => slot && typeof slot === "object" && !Array.isArray(slot) ? Object.keys(slot).length : 0;
|
|
659
|
+
return (rec.list ? 1 : 0) + (rec.form ? 1 : 0) + named(rec.listViews) + named(rec.formViews);
|
|
660
|
+
}
|
|
661
|
+
function validateViewContainers(stack) {
|
|
662
|
+
const out = [];
|
|
663
|
+
if (!stack || typeof stack !== "object") return out;
|
|
664
|
+
for (const { key, value } of asEntries(stack.views)) {
|
|
665
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
666
|
+
const rec = value;
|
|
667
|
+
if (rec.viewKind != null) continue;
|
|
668
|
+
if (containerViewCount(rec) > 0) continue;
|
|
669
|
+
const label = typeof rec.name === "string" ? ` ("${rec.name}")` : "";
|
|
670
|
+
const hasContainerSlot = CONTAINER_SLOT_KEYS.some((k) => k in rec);
|
|
671
|
+
const looksFlat = !hasContainerSlot && ["type", "columns", "data", "filter", "sort"].some((k) => k in rec);
|
|
672
|
+
out.push({
|
|
673
|
+
severity: "error",
|
|
674
|
+
rule: VIEW_CONTAINER_SHAPE,
|
|
675
|
+
where: `views${key}${label}`,
|
|
676
|
+
path: `views${key}`,
|
|
677
|
+
message: looksFlat ? "Flat list-view object is not a view container: `ViewSchema` strips its keys, so it parses to an EMPTY container \u2014 zero views register and the Console renders no view for it." : "View container defines no views \u2014 all of `list` / `form` / `listViews` / `formViews` are absent or empty, so nothing registers.",
|
|
678
|
+
hint: "Wrap every view in a defineView container: defineView({ list: { type, data, columns, ... }, listViews: { ... }, formViews: { ... } }). See examples/app-showcase/src/ui/views/task.view.ts."
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
return out;
|
|
682
|
+
}
|
|
683
|
+
|
|
520
684
|
// src/validate-responsive-styles.ts
|
|
521
685
|
var STYLE_NODE_MISSING_ID = "style-node-missing-id";
|
|
522
686
|
var STYLE_CLASSNAME_TAILWIND = "style-classname-tailwind";
|
|
@@ -720,7 +884,7 @@ function looksLikeTailwind(className) {
|
|
|
720
884
|
return false;
|
|
721
885
|
});
|
|
722
886
|
}
|
|
723
|
-
function
|
|
887
|
+
function asArray5(v) {
|
|
724
888
|
if (Array.isArray(v)) return v;
|
|
725
889
|
if (v && typeof v === "object") {
|
|
726
890
|
return Object.entries(v).map(([name, def]) => ({ name, ...def }));
|
|
@@ -813,13 +977,13 @@ function checkNode(node, pageName, path, findings) {
|
|
|
813
977
|
}
|
|
814
978
|
function validateResponsiveStyles(stack) {
|
|
815
979
|
const findings = [];
|
|
816
|
-
const pages =
|
|
980
|
+
const pages = asArray5(stack.pages);
|
|
817
981
|
for (let p = 0; p < pages.length; p++) {
|
|
818
982
|
const page = pages[p];
|
|
819
983
|
const pageName = typeof page.name === "string" ? page.name : `pages[${p}]`;
|
|
820
|
-
const regions =
|
|
984
|
+
const regions = asArray5(page.regions);
|
|
821
985
|
for (let r = 0; r < regions.length; r++) {
|
|
822
|
-
const components =
|
|
986
|
+
const components = asArray5(regions[r].components);
|
|
823
987
|
for (let c = 0; c < components.length; c++) {
|
|
824
988
|
checkNode(components[c], pageName, `pages[${p}].regions[${r}].components[${c}]`, findings);
|
|
825
989
|
}
|
|
@@ -830,10 +994,10 @@ function validateResponsiveStyles(stack) {
|
|
|
830
994
|
|
|
831
995
|
// src/validate-jsx-pages.ts
|
|
832
996
|
var import_sdui_parser = require("@objectstack/sdui-parser");
|
|
833
|
-
var
|
|
997
|
+
var asArray6 = (v) => Array.isArray(v) ? v : [];
|
|
834
998
|
function validateJsxPages(stack, opts = {}) {
|
|
835
999
|
const findings = [];
|
|
836
|
-
const pages =
|
|
1000
|
+
const pages = asArray6(stack.pages);
|
|
837
1001
|
for (let p = 0; p < pages.length; p++) {
|
|
838
1002
|
const page = pages[p];
|
|
839
1003
|
if (!page || page.kind !== "html" && page.kind !== "jsx") continue;
|
|
@@ -881,10 +1045,10 @@ function loadSucraseTransform() {
|
|
|
881
1045
|
}
|
|
882
1046
|
return cachedTransform;
|
|
883
1047
|
}
|
|
884
|
-
var
|
|
1048
|
+
var asArray7 = (v) => Array.isArray(v) ? v : [];
|
|
885
1049
|
function validateReactPages(stack) {
|
|
886
1050
|
const findings = [];
|
|
887
|
-
const pages =
|
|
1051
|
+
const pages = asArray7(stack.pages);
|
|
888
1052
|
for (let p = 0; p < pages.length; p++) {
|
|
889
1053
|
const page = pages[p];
|
|
890
1054
|
if (!page || page.kind !== "react") continue;
|
|
@@ -936,7 +1100,7 @@ function loadTypeScript() {
|
|
|
936
1100
|
}
|
|
937
1101
|
return cachedTs;
|
|
938
1102
|
}
|
|
939
|
-
var
|
|
1103
|
+
var asArray8 = (v) => Array.isArray(v) ? v : [];
|
|
940
1104
|
var BLOCKS = new Map(
|
|
941
1105
|
import_ui.REACT_BLOCKS.map((b) => [
|
|
942
1106
|
b.tag,
|
|
@@ -975,7 +1139,7 @@ function nearestKnown(prop, known) {
|
|
|
975
1139
|
}
|
|
976
1140
|
function validateReactPageProps(stack) {
|
|
977
1141
|
const findings = [];
|
|
978
|
-
const pages =
|
|
1142
|
+
const pages = asArray8(stack.pages);
|
|
979
1143
|
for (let p = 0; p < pages.length; p++) {
|
|
980
1144
|
const page = pages[p];
|
|
981
1145
|
if (!page || page.kind !== "react") continue;
|
|
@@ -1043,11 +1207,11 @@ function validateReactPageProps(stack) {
|
|
|
1043
1207
|
|
|
1044
1208
|
// src/validate-page-source-styling.ts
|
|
1045
1209
|
var PAGE_SOURCE_CLASSNAME = "page-source-className-tailwind";
|
|
1046
|
-
var
|
|
1210
|
+
var asArray9 = (v) => Array.isArray(v) ? v : [];
|
|
1047
1211
|
var CLASSNAME_ATTR = /\bclassName\s*=\s*["'{]/g;
|
|
1048
1212
|
function validatePageSourceStyling(stack) {
|
|
1049
1213
|
const findings = [];
|
|
1050
|
-
const pages =
|
|
1214
|
+
const pages = asArray9(stack.pages);
|
|
1051
1215
|
for (let p = 0; p < pages.length; p++) {
|
|
1052
1216
|
const page = pages[p];
|
|
1053
1217
|
if (!page) continue;
|
|
@@ -1076,7 +1240,7 @@ function validatePageSourceStyling(stack) {
|
|
|
1076
1240
|
var import_data2 = require("@objectstack/spec/data");
|
|
1077
1241
|
var TITLE_FORMAT_RETIRED = "title-format-retired";
|
|
1078
1242
|
var TITLE_UNRESOLVABLE = "title-unresolvable";
|
|
1079
|
-
function
|
|
1243
|
+
function asArray10(v) {
|
|
1080
1244
|
if (Array.isArray(v)) return v;
|
|
1081
1245
|
if (v && typeof v === "object") {
|
|
1082
1246
|
return Object.entries(v).map(([name, def]) => ({ name, ...def }));
|
|
@@ -1085,7 +1249,7 @@ function asArray9(v) {
|
|
|
1085
1249
|
}
|
|
1086
1250
|
function validateRecordTitle(stack) {
|
|
1087
1251
|
const findings = [];
|
|
1088
|
-
const objects =
|
|
1252
|
+
const objects = asArray10(stack.objects);
|
|
1089
1253
|
for (let i = 0; i < objects.length; i++) {
|
|
1090
1254
|
const obj = objects[i];
|
|
1091
1255
|
const objName = typeof obj.name === "string" ? obj.name : `(object ${i})`;
|
|
@@ -1121,7 +1285,7 @@ var FIELD_GROUP_UNDECLARED = "field-group-undeclared";
|
|
|
1121
1285
|
var FIELD_GROUP_EMPTY = "field-group-empty";
|
|
1122
1286
|
var FIELD_GROUP_SHADOWED = "field-group-shadowed";
|
|
1123
1287
|
var SEMANTIC_ROLE_FIELD_UNKNOWN = "semantic-role-field-unknown";
|
|
1124
|
-
function
|
|
1288
|
+
function asArray11(v) {
|
|
1125
1289
|
if (Array.isArray(v)) return v;
|
|
1126
1290
|
if (v && typeof v === "object") {
|
|
1127
1291
|
return Object.entries(v).map(([name, def]) => ({ name, ...def }));
|
|
@@ -1130,7 +1294,7 @@ function asArray10(v) {
|
|
|
1130
1294
|
}
|
|
1131
1295
|
function validateSemanticRoles(stack) {
|
|
1132
1296
|
const findings = [];
|
|
1133
|
-
const objects =
|
|
1297
|
+
const objects = asArray11(stack.objects);
|
|
1134
1298
|
for (let i = 0; i < objects.length; i++) {
|
|
1135
1299
|
const obj = objects[i];
|
|
1136
1300
|
if (!obj || typeof obj !== "object") continue;
|
|
@@ -1225,7 +1389,7 @@ function validateSemanticRoles(stack) {
|
|
|
1225
1389
|
// src/validate-form-layout.ts
|
|
1226
1390
|
var FORM_FIELD_UNKNOWN = "form-field-unknown";
|
|
1227
1391
|
var FORM_COLSPAN_ABSOLUTE = "absolute-colspan-discouraged";
|
|
1228
|
-
function
|
|
1392
|
+
function asArray12(v) {
|
|
1229
1393
|
if (Array.isArray(v)) return v;
|
|
1230
1394
|
if (v && typeof v === "object") {
|
|
1231
1395
|
return Object.entries(v).map(([name, def]) => ({ name, ...def }));
|
|
@@ -1250,13 +1414,13 @@ function boundObject(view) {
|
|
|
1250
1414
|
function validateFormLayout(stack) {
|
|
1251
1415
|
const findings = [];
|
|
1252
1416
|
const objectFields = /* @__PURE__ */ new Map();
|
|
1253
|
-
for (const obj of
|
|
1417
|
+
for (const obj of asArray12(stack.objects)) {
|
|
1254
1418
|
const name = typeof obj.name === "string" ? obj.name : void 0;
|
|
1255
1419
|
if (!name) continue;
|
|
1256
1420
|
const fields = obj.fields && typeof obj.fields === "object" && !Array.isArray(obj.fields) ? Object.keys(obj.fields) : [];
|
|
1257
1421
|
objectFields.set(name, new Set(fields));
|
|
1258
1422
|
}
|
|
1259
|
-
const views =
|
|
1423
|
+
const views = asArray12(stack.views);
|
|
1260
1424
|
for (let i = 0; i < views.length; i++) {
|
|
1261
1425
|
const view = views[i];
|
|
1262
1426
|
if (!view || typeof view !== "object") continue;
|
|
@@ -1306,7 +1470,7 @@ var VISIBILITY_ALIAS_DEPRECATED = "visibility-alias-deprecated";
|
|
|
1306
1470
|
var VISIBILITY_ROOT_MISLAYERED = "visibility-root-mislayered";
|
|
1307
1471
|
var CANONICAL = "visibleWhen";
|
|
1308
1472
|
var ALIASES = ["visibleOn", "visibility"];
|
|
1309
|
-
function
|
|
1473
|
+
function asArray13(v) {
|
|
1310
1474
|
if (Array.isArray(v)) return v;
|
|
1311
1475
|
if (v && typeof v === "object") {
|
|
1312
1476
|
return Object.entries(v).map(([name, def]) => ({ name, ...def }));
|
|
@@ -1368,7 +1532,7 @@ function isFieldObject(entry) {
|
|
|
1368
1532
|
function validateVisibilityPredicates(stack, opts = {}) {
|
|
1369
1533
|
const layer = opts.layer ?? "runtime";
|
|
1370
1534
|
const findings = [];
|
|
1371
|
-
const views =
|
|
1535
|
+
const views = asArray13(stack.views);
|
|
1372
1536
|
for (let i = 0; i < views.length; i++) {
|
|
1373
1537
|
const view = views[i];
|
|
1374
1538
|
if (!view || typeof view !== "object") continue;
|
|
@@ -1391,7 +1555,7 @@ function validateVisibilityPredicates(stack, opts = {}) {
|
|
|
1391
1555
|
}
|
|
1392
1556
|
}
|
|
1393
1557
|
}
|
|
1394
|
-
const pages =
|
|
1558
|
+
const pages = asArray13(stack.pages);
|
|
1395
1559
|
for (let i = 0; i < pages.length; i++) {
|
|
1396
1560
|
const page = pages[i];
|
|
1397
1561
|
if (!page || typeof page !== "object") continue;
|
|
@@ -1415,7 +1579,7 @@ function validateVisibilityPredicates(stack, opts = {}) {
|
|
|
1415
1579
|
// src/validate-capability-references.ts
|
|
1416
1580
|
var import_security = require("@objectstack/spec/security");
|
|
1417
1581
|
var CAPABILITY_REFERENCE_UNKNOWN = "capability-reference-unknown";
|
|
1418
|
-
function
|
|
1582
|
+
function asArray14(v) {
|
|
1419
1583
|
if (Array.isArray(v)) return v;
|
|
1420
1584
|
if (v && typeof v === "object") {
|
|
1421
1585
|
return Object.entries(v).map(([name, def]) => ({ name, ...def }));
|
|
@@ -1440,13 +1604,13 @@ function validateCapabilityReferences(stack) {
|
|
|
1440
1604
|
const findings = [];
|
|
1441
1605
|
if (!stack || typeof stack !== "object") return findings;
|
|
1442
1606
|
const known = new Set(import_security.PLATFORM_CAPABILITY_NAMES);
|
|
1443
|
-
for (const cap of
|
|
1607
|
+
for (const cap of asArray14(stack.capabilities)) {
|
|
1444
1608
|
if (typeof cap.name === "string" && cap.name.length > 0) known.add(cap.name);
|
|
1445
1609
|
}
|
|
1446
|
-
for (const ps of
|
|
1610
|
+
for (const ps of asArray14(stack.permissions)) {
|
|
1447
1611
|
for (const cap of asCapArray(ps.systemPermissions)) known.add(cap);
|
|
1448
1612
|
}
|
|
1449
|
-
for (const seed of
|
|
1613
|
+
for (const seed of asArray14(stack.data)) {
|
|
1450
1614
|
if (seed.object !== "sys_capability") continue;
|
|
1451
1615
|
for (const rec of Array.isArray(seed.records) ? seed.records : []) {
|
|
1452
1616
|
const name = rec?.name;
|
|
@@ -1465,7 +1629,7 @@ function validateCapabilityReferences(stack) {
|
|
|
1465
1629
|
hint
|
|
1466
1630
|
});
|
|
1467
1631
|
};
|
|
1468
|
-
const objects =
|
|
1632
|
+
const objects = asArray14(stack.objects);
|
|
1469
1633
|
for (let i = 0; i < objects.length; i++) {
|
|
1470
1634
|
const obj = objects[i];
|
|
1471
1635
|
if (!obj || typeof obj !== "object") continue;
|
|
@@ -1474,27 +1638,27 @@ function validateCapabilityReferences(stack) {
|
|
|
1474
1638
|
for (const { cap, key } of flattenObjectRequired(obj.requiredPermissions)) {
|
|
1475
1639
|
flag(cap, `object "${objName}"`, `${objPath}.requiredPermissions${key ? `.${key}` : ""}`);
|
|
1476
1640
|
}
|
|
1477
|
-
const fields =
|
|
1641
|
+
const fields = asArray14(obj.fields);
|
|
1478
1642
|
for (const f of fields) {
|
|
1479
1643
|
const fname = typeof f.name === "string" ? f.name : "(field)";
|
|
1480
1644
|
for (const cap of asCapArray(f.requiredPermissions)) {
|
|
1481
1645
|
flag(cap, `field "${objName}.${fname}"`, `${objPath}.fields.${fname}.requiredPermissions`);
|
|
1482
1646
|
}
|
|
1483
1647
|
}
|
|
1484
|
-
for (const [ai, action] of
|
|
1648
|
+
for (const [ai, action] of asArray14(obj.actions).entries()) {
|
|
1485
1649
|
const aName = typeof action.name === "string" ? action.name : `(action ${ai})`;
|
|
1486
1650
|
for (const cap of asCapArray(action.requiredPermissions)) {
|
|
1487
1651
|
flag(cap, `action "${objName}.${aName}"`, `${objPath}.actions[${ai}].requiredPermissions`);
|
|
1488
1652
|
}
|
|
1489
1653
|
}
|
|
1490
1654
|
}
|
|
1491
|
-
for (const [i, action] of
|
|
1655
|
+
for (const [i, action] of asArray14(stack.actions).entries()) {
|
|
1492
1656
|
const aName = typeof action.name === "string" ? action.name : `(action ${i})`;
|
|
1493
1657
|
for (const cap of asCapArray(action.requiredPermissions)) {
|
|
1494
1658
|
flag(cap, `action "${aName}"`, `actions[${i}].requiredPermissions`);
|
|
1495
1659
|
}
|
|
1496
1660
|
}
|
|
1497
|
-
const apps =
|
|
1661
|
+
const apps = asArray14(stack.apps);
|
|
1498
1662
|
for (let i = 0; i < apps.length; i++) {
|
|
1499
1663
|
const app = apps[i];
|
|
1500
1664
|
if (!app || typeof app !== "object") continue;
|
|
@@ -1522,7 +1686,8 @@ function validateCapabilityReferences(stack) {
|
|
|
1522
1686
|
|
|
1523
1687
|
// src/validate-approval-approvers.ts
|
|
1524
1688
|
var import_automation = require("@objectstack/spec/automation");
|
|
1525
|
-
var
|
|
1689
|
+
var APPROVAL_APPROVER_NOT_MEMBERSHIP_TIER = "approval-approver-not-membership-tier";
|
|
1690
|
+
var APPROVAL_APPROVER_TYPE_DEPRECATED = "approval-approver-type-deprecated";
|
|
1526
1691
|
var APPROVAL_APPROVER_TYPE_UNKNOWN = "approval-approver-type-unknown";
|
|
1527
1692
|
var APPROVAL_ESCALATION_REASSIGN_NO_TARGET = "approval-escalation-reassign-no-target";
|
|
1528
1693
|
var MEMBERSHIP_TIERS = /* @__PURE__ */ new Set(["owner", "admin", "member", "guest"]);
|
|
@@ -1530,7 +1695,7 @@ var TYPE_FIX = {
|
|
|
1530
1695
|
business_unit: "department",
|
|
1531
1696
|
bu: "department"
|
|
1532
1697
|
};
|
|
1533
|
-
function
|
|
1698
|
+
function asArray15(v) {
|
|
1534
1699
|
if (Array.isArray(v)) return v;
|
|
1535
1700
|
if (v && typeof v === "object") {
|
|
1536
1701
|
return Object.entries(v).map(([name, def]) => ({ name, ...def }));
|
|
@@ -1540,7 +1705,7 @@ function asArray14(v) {
|
|
|
1540
1705
|
function validateApprovalApprovers(stack) {
|
|
1541
1706
|
const findings = [];
|
|
1542
1707
|
if (!stack || typeof stack !== "object") return findings;
|
|
1543
|
-
const flows =
|
|
1708
|
+
const flows = asArray15(stack.flows);
|
|
1544
1709
|
const validTypes = new Set(import_automation.ApproverType.options);
|
|
1545
1710
|
for (let fi = 0; fi < flows.length; fi++) {
|
|
1546
1711
|
const flow = flows[fi];
|
|
@@ -1572,14 +1737,25 @@ function validateApprovalApprovers(stack) {
|
|
|
1572
1737
|
});
|
|
1573
1738
|
continue;
|
|
1574
1739
|
}
|
|
1575
|
-
|
|
1740
|
+
const canonical = (0, import_automation.canonicalApproverType)(type);
|
|
1741
|
+
if (canonical === "org_membership_level" && value && !MEMBERSHIP_TIERS.has(value.toLowerCase())) {
|
|
1576
1742
|
findings.push({
|
|
1577
1743
|
severity: "warning",
|
|
1578
|
-
rule:
|
|
1744
|
+
rule: APPROVAL_APPROVER_NOT_MEMBERSHIP_TIER,
|
|
1579
1745
|
where,
|
|
1580
1746
|
path: `${path}.value`,
|
|
1581
|
-
message: `approver { type: '
|
|
1582
|
-
hint: `If '${value}' is an org position, author { type: 'position', value: '${value}' } (resolved via sys_user_position, ADR-0090 D3). Keep type '
|
|
1747
|
+
message: `approver { type: '${type}', value: '${value}' } resolves against the better-auth org-membership tier (sys_member.role: owner/admin/member) \u2014 '${value}' is not a membership tier, so this approver matches nobody and the request stalls.`,
|
|
1748
|
+
hint: `If '${value}' is an org position, author { type: 'position', value: '${value}' } (resolved via sys_user_position, ADR-0090 D3). Keep type 'org_membership_level' only for membership tiers (owner/admin/member).`
|
|
1749
|
+
});
|
|
1750
|
+
} else if (type in import_automation.DEPRECATED_APPROVER_TYPES) {
|
|
1751
|
+
const fix = (0, import_automation.canonicalApproverType)(type);
|
|
1752
|
+
findings.push({
|
|
1753
|
+
severity: "warning",
|
|
1754
|
+
rule: APPROVAL_APPROVER_TYPE_DEPRECATED,
|
|
1755
|
+
where,
|
|
1756
|
+
path: `${path}.type`,
|
|
1757
|
+
message: `approver type '${type}' is the deprecated spelling of '${fix}' (ADR-0090 D3) and is removed in the next major.`,
|
|
1758
|
+
hint: `Author { type: '${fix}', value: '${value}' }. It resolves identically today.`
|
|
1583
1759
|
});
|
|
1584
1760
|
}
|
|
1585
1761
|
}
|
|
@@ -1628,7 +1804,7 @@ var OWD_WIDTH = {
|
|
|
1628
1804
|
public_read: 1,
|
|
1629
1805
|
public_read_write: 2
|
|
1630
1806
|
};
|
|
1631
|
-
function
|
|
1807
|
+
function asArray16(v) {
|
|
1632
1808
|
if (Array.isArray(v)) return v;
|
|
1633
1809
|
if (v && typeof v === "object") {
|
|
1634
1810
|
return Object.entries(v).map(([name, def]) => ({ name, ...def }));
|
|
@@ -1654,7 +1830,7 @@ function refOf(def) {
|
|
|
1654
1830
|
return typeof r === "string" && r ? r : void 0;
|
|
1655
1831
|
}
|
|
1656
1832
|
function firstMasterDetailField(obj) {
|
|
1657
|
-
for (const f of
|
|
1833
|
+
for (const f of asArray16(obj.fields)) {
|
|
1658
1834
|
if (f.type === "master_detail") {
|
|
1659
1835
|
return { name: String(f.name ?? "?"), parent: refOf(f) };
|
|
1660
1836
|
}
|
|
@@ -1667,8 +1843,8 @@ function grantsObjectAccess(p) {
|
|
|
1667
1843
|
function validateSecurityPosture(stack, opts) {
|
|
1668
1844
|
const findings = [];
|
|
1669
1845
|
if (!stack || typeof stack !== "object") return findings;
|
|
1670
|
-
const objects =
|
|
1671
|
-
const permissionSets =
|
|
1846
|
+
const objects = asArray16(stack.objects);
|
|
1847
|
+
const permissionSets = asArray16(stack.permissions);
|
|
1672
1848
|
for (let i = 0; i < objects.length; i++) {
|
|
1673
1849
|
const obj = objects[i];
|
|
1674
1850
|
if (!obj || typeof obj !== "object") continue;
|
|
@@ -1797,10 +1973,10 @@ function validateSecurityPosture(stack, opts) {
|
|
|
1797
1973
|
if (!obj || typeof obj !== "object" || isSystemObject(obj)) continue;
|
|
1798
1974
|
const objName = typeof obj.name === "string" ? obj.name : `(object ${i})`;
|
|
1799
1975
|
flagRole("object", obj.name, obj.label, `object "${objName}"`, `objects[${i}].name`);
|
|
1800
|
-
for (const f of
|
|
1976
|
+
for (const f of asArray16(obj.fields)) {
|
|
1801
1977
|
flagRole("field", f.name, f.label, `field "${objName}.${String(f.name ?? "?")}"`, `objects[${i}].fields.${String(f.name ?? "?")}.name`);
|
|
1802
1978
|
}
|
|
1803
|
-
for (const [ai, action] of
|
|
1979
|
+
for (const [ai, action] of asArray16(obj.actions).entries()) {
|
|
1804
1980
|
flagRole("action", action.name, action.label, `action "${objName}.${String(action.name ?? "?")}"`, `objects[${i}].actions[${ai}].name`);
|
|
1805
1981
|
}
|
|
1806
1982
|
}
|
|
@@ -1809,19 +1985,19 @@ function validateSecurityPosture(stack, opts) {
|
|
|
1809
1985
|
if (!ps || typeof ps !== "object") continue;
|
|
1810
1986
|
flagRole("permission set", ps.name, ps.label, `permission set "${String(ps.name ?? i)}"`, `permissions[${i}].name`);
|
|
1811
1987
|
}
|
|
1812
|
-
for (const [i, pos] of
|
|
1988
|
+
for (const [i, pos] of asArray16(stack.positions).entries()) {
|
|
1813
1989
|
flagRole("position", pos.name, pos.label, `position "${String(pos.name ?? i)}"`, `positions[${i}].name`);
|
|
1814
1990
|
}
|
|
1815
|
-
for (const [i, app] of
|
|
1991
|
+
for (const [i, app] of asArray16(stack.apps).entries()) {
|
|
1816
1992
|
flagRole("app", app.name, app.label, `app "${String(app.name ?? i)}"`, `apps[${i}].name`);
|
|
1817
1993
|
}
|
|
1818
|
-
for (const [i, book] of
|
|
1994
|
+
for (const [i, book] of asArray16(stack.books).entries()) {
|
|
1819
1995
|
flagRole("book", book.name, book.label, `book "${String(book.name ?? i)}"`, `books[${i}].name`);
|
|
1820
1996
|
}
|
|
1821
1997
|
const stackSetNames = new Set(
|
|
1822
1998
|
permissionSets.map((ps) => typeof ps.name === "string" ? ps.name : void 0).filter((n) => !!n)
|
|
1823
1999
|
);
|
|
1824
|
-
for (const [i, book] of
|
|
2000
|
+
for (const [i, book] of asArray16(stack.books).entries()) {
|
|
1825
2001
|
const audience = book.audience;
|
|
1826
2002
|
if (!audience || typeof audience !== "object") continue;
|
|
1827
2003
|
const setName = audience.permissionSet;
|
|
@@ -1899,7 +2075,7 @@ function validateSecurityPosture(stack, opts) {
|
|
|
1899
2075
|
}
|
|
1900
2076
|
const GRANT_SEED_OBJECTS = /* @__PURE__ */ new Set(["sys_user_position", "sys_user_permission_set"]);
|
|
1901
2077
|
const nowMs = opts?.nowMs ?? Date.now();
|
|
1902
|
-
for (const [i, seed] of
|
|
2078
|
+
for (const [i, seed] of asArray16(stack.data).entries()) {
|
|
1903
2079
|
const seedObject = typeof seed.object === "string" ? seed.object : "";
|
|
1904
2080
|
if (!GRANT_SEED_OBJECTS.has(seedObject)) continue;
|
|
1905
2081
|
const records = Array.isArray(seed.records) ? seed.records : [];
|
|
@@ -1940,7 +2116,7 @@ function validateSecurityPosture(stack, opts) {
|
|
|
1940
2116
|
}
|
|
1941
2117
|
|
|
1942
2118
|
// src/build-access-matrix.ts
|
|
1943
|
-
function
|
|
2119
|
+
function asArray17(v) {
|
|
1944
2120
|
if (Array.isArray(v)) return v;
|
|
1945
2121
|
if (v && typeof v === "object") {
|
|
1946
2122
|
return Object.entries(v).map(([name, def]) => ({ name, ...def }));
|
|
@@ -1951,13 +2127,13 @@ function buildAccessMatrix(stack) {
|
|
|
1951
2127
|
const entries = [];
|
|
1952
2128
|
if (!stack || typeof stack !== "object") return { version: 1, entries };
|
|
1953
2129
|
const owdByObject = /* @__PURE__ */ new Map();
|
|
1954
|
-
for (const obj of
|
|
2130
|
+
for (const obj of asArray17(stack.objects)) {
|
|
1955
2131
|
const name = typeof obj.name === "string" ? obj.name : "";
|
|
1956
2132
|
if (!name) continue;
|
|
1957
2133
|
const owd = obj.sharingModel ?? obj.security?.sharingModel;
|
|
1958
2134
|
if (typeof owd === "string") owdByObject.set(name, owd);
|
|
1959
2135
|
}
|
|
1960
|
-
for (const ps of
|
|
2136
|
+
for (const ps of asArray17(stack.permissions)) {
|
|
1961
2137
|
const psName = typeof ps.name === "string" ? ps.name : "";
|
|
1962
2138
|
if (!psName) continue;
|
|
1963
2139
|
const objects = ps.objects && typeof ps.objects === "object" ? ps.objects : {};
|
|
@@ -2029,14 +2205,17 @@ function diffAccessMatrix(before, after) {
|
|
|
2029
2205
|
}
|
|
2030
2206
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2031
2207
|
0 && (module.exports = {
|
|
2208
|
+
APPROVAL_APPROVER_NOT_MEMBERSHIP_TIER,
|
|
2209
|
+
APPROVAL_APPROVER_TYPE_DEPRECATED,
|
|
2032
2210
|
APPROVAL_APPROVER_TYPE_UNKNOWN,
|
|
2033
2211
|
APPROVAL_ESCALATION_REASSIGN_NO_TARGET,
|
|
2034
|
-
APPROVAL_ROLE_NOT_MEMBERSHIP_TIER,
|
|
2035
2212
|
CAPABILITY_REFERENCE_UNKNOWN,
|
|
2036
2213
|
CHART_CONFIG_MISSING,
|
|
2037
2214
|
CHART_FIELD_UNKNOWN,
|
|
2038
2215
|
FIELD_GROUP_EMPTY,
|
|
2039
2216
|
FIELD_GROUP_UNDECLARED,
|
|
2217
|
+
FLOW_DRAFT_STATUS_AMBIGUOUS,
|
|
2218
|
+
FLOW_TRIGGER_UNKNOWN_OBJECT,
|
|
2040
2219
|
FORM_COLSPAN_ABSOLUTE,
|
|
2041
2220
|
FORM_FIELD_UNKNOWN,
|
|
2042
2221
|
LIST_VIEW_FILTERS_IN_VIEWS_MODE,
|
|
@@ -2062,6 +2241,7 @@ function diffAccessMatrix(before, after) {
|
|
|
2062
2241
|
TABLE_COUNT_ONLY,
|
|
2063
2242
|
TITLE_FORMAT_RETIRED,
|
|
2064
2243
|
TITLE_UNRESOLVABLE,
|
|
2244
|
+
VIEW_CONTAINER_SHAPE,
|
|
2065
2245
|
VISIBILITY_ALIAS_DEPRECATED,
|
|
2066
2246
|
VISIBILITY_ROOT_MISLAYERED,
|
|
2067
2247
|
WIDGET_DATASET_UNKNOWN,
|
|
@@ -2071,6 +2251,7 @@ function diffAccessMatrix(before, after) {
|
|
|
2071
2251
|
diffAccessMatrix,
|
|
2072
2252
|
validateApprovalApprovers,
|
|
2073
2253
|
validateCapabilityReferences,
|
|
2254
|
+
validateFlowTriggerReadiness,
|
|
2074
2255
|
validateFormLayout,
|
|
2075
2256
|
validateJsxPages,
|
|
2076
2257
|
validateListViewMode,
|
|
@@ -2082,6 +2263,7 @@ function diffAccessMatrix(before, after) {
|
|
|
2082
2263
|
validateSecurityPosture,
|
|
2083
2264
|
validateSemanticRoles,
|
|
2084
2265
|
validateStackExpressions,
|
|
2266
|
+
validateViewContainers,
|
|
2085
2267
|
validateVisibilityPredicates,
|
|
2086
2268
|
validateWidgetBindings
|
|
2087
2269
|
});
|