@objectstack/lint 17.0.0-rc.0 → 17.0.0-rc.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/CHANGELOG.md +4315 -0
- package/dist/index.cjs +6302 -3075
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +825 -87
- package/dist/index.d.ts +825 -87
- package/dist/index.js +5364 -2197
- package/dist/index.js.map +1 -1
- package/dist/runtime-Cs64ShwN.d.cts +254 -0
- package/dist/runtime-Cs64ShwN.d.ts +254 -0
- package/dist/runtime.cjs +7740 -0
- package/dist/runtime.cjs.map +1 -0
- package/dist/runtime.d.cts +1 -0
- package/dist/runtime.d.ts +1 -0
- package/dist/runtime.js +7733 -0
- package/dist/runtime.js.map +1 -0
- package/package.json +16 -9
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Manifest } from '@objectstack/sdui-parser';
|
|
2
2
|
import { AccessMatrix } from '@objectstack/spec/security';
|
|
3
|
+
export { A as AUTHORING_COMMANDS, a as AUTHORING_RULES, b as AUTHORING_SURFACES, c as AuthoringCommand, d as AuthoringFinding, e as AuthoringRule, f as AuthoringRuleContext, g as AuthoringRuleInputTier, h as AuthoringRuleRun, i as AuthoringRuleTier, j as AuthoringSeverity, k as AuthoringSurface, E as EXPRESSION_INVALID, R as RuntimeGateResult, l as RuntimeStackContext, m as authoringRulesFor, r as runAuthoringRules, n as runRuntimeAuthoringRules, o as runtimeAuthoringRulesFor, p as runtimeGatedTypes, s as splitBySeverity, q as stackKeyForType } from './runtime-Cs64ShwN.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Build-time dashboard widget binding diagnostics (issues #1719, #1721).
|
|
@@ -94,7 +95,7 @@ interface WidgetBindingFinding {
|
|
|
94
95
|
/** How to fix (or deliberately suppress) it. */
|
|
95
96
|
hint: string;
|
|
96
97
|
}
|
|
97
|
-
type AnyRec$
|
|
98
|
+
type AnyRec$C = Record<string, unknown>;
|
|
98
99
|
/**
|
|
99
100
|
* Validate every dashboard widget's dataset binding. Returns the list of
|
|
100
101
|
* findings (empty = clean). Caller decides how to surface them: `error`
|
|
@@ -102,7 +103,7 @@ type AnyRec$t = Record<string, unknown>;
|
|
|
102
103
|
* should fail validate/build; `warning` findings are advisory and must
|
|
103
104
|
* never fail the build on their own.
|
|
104
105
|
*/
|
|
105
|
-
declare function validateWidgetBindings(stack: AnyRec$
|
|
106
|
+
declare function validateWidgetBindings(stack: AnyRec$C): WidgetBindingFinding[];
|
|
106
107
|
|
|
107
108
|
interface ExprIssue {
|
|
108
109
|
where: string;
|
|
@@ -115,12 +116,56 @@ interface ExprIssue {
|
|
|
115
116
|
*/
|
|
116
117
|
severity?: 'error' | 'warning';
|
|
117
118
|
}
|
|
118
|
-
type AnyRec$
|
|
119
|
+
type AnyRec$B = Record<string, unknown>;
|
|
119
120
|
/**
|
|
120
121
|
* Validate every predicate in the stack. Returns the list of issues (empty =
|
|
121
122
|
* clean). Caller decides how to surface / whether to fail the build.
|
|
122
123
|
*/
|
|
123
|
-
declare function validateStackExpressions(stack: AnyRec$
|
|
124
|
+
declare function validateStackExpressions(stack: AnyRec$B): ExprIssue[];
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The corrective sentence, lifted **verbatim** from `unevaluableRuleError` in
|
|
128
|
+
* `packages/objectql/src/validation/rule-validator.ts` so the publish-time and
|
|
129
|
+
* runtime messages read identically — an author who hits one and then the other
|
|
130
|
+
* must not have to reconcile two phrasings of one rule (#4763).
|
|
131
|
+
*/
|
|
132
|
+
declare const NULL_GUARD_HINT: string;
|
|
133
|
+
interface NullGuardOptions {
|
|
134
|
+
/** Field names of the object that may hold `null` at evaluation time. */
|
|
135
|
+
nullableFields: ReadonlySet<string>;
|
|
136
|
+
/** Roots bound to the object's record shape. Defaults to `record`/`previous`. */
|
|
137
|
+
roots?: readonly string[];
|
|
138
|
+
}
|
|
139
|
+
interface NullGuardFinding {
|
|
140
|
+
/** The operand as written, e.g. `record.end_date`. */
|
|
141
|
+
operand: string;
|
|
142
|
+
/** The declared field the operand resolves to, e.g. `end_date`. */
|
|
143
|
+
field: string;
|
|
144
|
+
/** The operator with no null overload, e.g. `<`. */
|
|
145
|
+
operator: string;
|
|
146
|
+
/**
|
|
147
|
+
* True when the predicate "guards" this operand with `has()` and nothing
|
|
148
|
+
* else — the exact trap #4763 exists to reject. Used only to sharpen the
|
|
149
|
+
* message; the verdict is the same either way.
|
|
150
|
+
*/
|
|
151
|
+
hasOnlyGuard: boolean;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Find every ordering/arithmetic operand that resolves to a nullable declared
|
|
155
|
+
* field and is not dominated by a real null guard. Returns `[]` for anything
|
|
156
|
+
* that does not parse (syntax is reported by `validateExpression`, not here) —
|
|
157
|
+
* this pass never invents a second syntax verdict.
|
|
158
|
+
*/
|
|
159
|
+
declare function findUnguardedNullableOperands(source: string, opts: NullGuardOptions): NullGuardFinding[];
|
|
160
|
+
/**
|
|
161
|
+
* The publish-time message for one finding. Names the rule, the operand and the
|
|
162
|
+
* `!= null` fix (the three things the author needs), then closes with the
|
|
163
|
+
* verbatim runtime sentence so the two gates speak with one voice.
|
|
164
|
+
*
|
|
165
|
+
* @param subject How the site names itself, e.g. `validation rule 'end_after_start'`.
|
|
166
|
+
* @param objectName The object whose field list decided nullability.
|
|
167
|
+
*/
|
|
168
|
+
declare function nullGuardMessage(subject: string, objectName: string | undefined, finding: NullGuardFinding): string;
|
|
124
169
|
|
|
125
170
|
type ListViewModeSeverity = 'error' | 'warning';
|
|
126
171
|
interface ListViewModeFinding {
|
|
@@ -134,7 +179,7 @@ interface ListViewModeFinding {
|
|
|
134
179
|
hint: string;
|
|
135
180
|
}
|
|
136
181
|
declare const LIST_VIEW_FILTERS_IN_VIEWS_MODE = "list-view-filters-in-views-mode";
|
|
137
|
-
type AnyRec$
|
|
182
|
+
type AnyRec$A = Record<string, unknown>;
|
|
138
183
|
/**
|
|
139
184
|
* Flag ADR-0047 "views" mode violations on an object's built-in named views or a
|
|
140
185
|
* `defineView` default `list` / named `listViews`: `quickFilters`, or a `tabs`
|
|
@@ -144,7 +189,25 @@ type AnyRec$r = Record<string, unknown>;
|
|
|
144
189
|
*
|
|
145
190
|
* Feed the PRE-parse stack (normalizeStackInput output) — see file header.
|
|
146
191
|
*/
|
|
147
|
-
declare function validateListViewMode(stack: AnyRec$
|
|
192
|
+
declare function validateListViewMode(stack: AnyRec$A): ListViewModeFinding[];
|
|
193
|
+
|
|
194
|
+
type FunctionalCompletenessSeverity = 'error' | 'warning';
|
|
195
|
+
interface FunctionalCompletenessFinding {
|
|
196
|
+
severity: FunctionalCompletenessSeverity;
|
|
197
|
+
/** Stable rule id from the shared predicate (e.g. `field/summary-without-operations`). */
|
|
198
|
+
rule: string;
|
|
199
|
+
/** Human-readable location, e.g. `object "order" › fields.total`. */
|
|
200
|
+
where: string;
|
|
201
|
+
/** Config path, e.g. `objects[2].fields.total.summaryOperations`. */
|
|
202
|
+
path: string;
|
|
203
|
+
message: string;
|
|
204
|
+
hint: string;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Walk every field definition and every list-view definition in the stack
|
|
208
|
+
* through the shared completeness predicate.
|
|
209
|
+
*/
|
|
210
|
+
declare function validateFunctionalCompleteness(stack: unknown): FunctionalCompletenessFinding[];
|
|
148
211
|
|
|
149
212
|
type FlowTriggerReadinessSeverity = 'error' | 'warning';
|
|
150
213
|
interface FlowTriggerReadinessFinding {
|
|
@@ -159,12 +222,12 @@ interface FlowTriggerReadinessFinding {
|
|
|
159
222
|
}
|
|
160
223
|
declare const FLOW_TRIGGER_UNKNOWN_OBJECT = "flow-trigger-unknown-object";
|
|
161
224
|
declare const FLOW_DRAFT_STATUS_AMBIGUOUS = "flow-draft-status-ambiguous";
|
|
162
|
-
type AnyRec$
|
|
225
|
+
type AnyRec$z = Record<string, unknown>;
|
|
163
226
|
/**
|
|
164
227
|
* Validate auto-launched flow trigger wiring against the stack definition.
|
|
165
228
|
* Pure and dependency-free; safe on pre- or post-parse stacks.
|
|
166
229
|
*/
|
|
167
|
-
declare function validateFlowTriggerReadiness(stack: AnyRec$
|
|
230
|
+
declare function validateFlowTriggerReadiness(stack: AnyRec$z): FlowTriggerReadinessFinding[];
|
|
168
231
|
|
|
169
232
|
type FlowTemplatePathSeverity = 'error' | 'warning';
|
|
170
233
|
interface FlowTemplatePathFinding {
|
|
@@ -179,12 +242,12 @@ interface FlowTemplatePathFinding {
|
|
|
179
242
|
}
|
|
180
243
|
declare const FLOW_TEMPLATE_UNKNOWN_FIELD = "flow-template-unknown-field";
|
|
181
244
|
declare const FLOW_TEMPLATE_LOOKUP_TRAVERSAL = "flow-template-lookup-traversal";
|
|
182
|
-
type AnyRec$
|
|
245
|
+
type AnyRec$y = Record<string, unknown>;
|
|
183
246
|
/**
|
|
184
247
|
* Validate `{record.<path>}` template references across every record-change
|
|
185
248
|
* flow. Pure and dependency-free; safe on pre- or post-parse stacks.
|
|
186
249
|
*/
|
|
187
|
-
declare function validateFlowTemplatePaths(stack: AnyRec$
|
|
250
|
+
declare function validateFlowTemplatePaths(stack: AnyRec$y): FlowTemplatePathFinding[];
|
|
188
251
|
|
|
189
252
|
type ReadonlyFlowWriteSeverity = 'error' | 'warning';
|
|
190
253
|
interface ReadonlyFlowWriteFinding {
|
|
@@ -199,12 +262,12 @@ interface ReadonlyFlowWriteFinding {
|
|
|
199
262
|
}
|
|
200
263
|
declare const FLOW_UPDATE_READONLY_FIELD = "flow-update-readonly-field";
|
|
201
264
|
declare const FLOW_UPDATE_READONLY_WHEN_FIELD = "flow-update-readonly-when-field";
|
|
202
|
-
type AnyRec$
|
|
265
|
+
type AnyRec$x = Record<string, unknown>;
|
|
203
266
|
/**
|
|
204
267
|
* Validate flow `update_record` writes against target-object readonly
|
|
205
268
|
* declarations. Pure and dependency-free; safe on pre- or post-parse stacks.
|
|
206
269
|
*/
|
|
207
|
-
declare function validateReadonlyFlowWrites(stack: AnyRec$
|
|
270
|
+
declare function validateReadonlyFlowWrites(stack: AnyRec$x): ReadonlyFlowWriteFinding[];
|
|
208
271
|
|
|
209
272
|
type ViewContainerSeverity = 'error' | 'warning';
|
|
210
273
|
interface ViewContainerFinding {
|
|
@@ -241,14 +304,14 @@ declare const STYLE_CLASSNAME_TAILWIND = "style-classname-tailwind";
|
|
|
241
304
|
declare const STYLE_RESPONSIVE_NO_BASE = "style-responsive-no-base";
|
|
242
305
|
declare const STYLE_UNKNOWN_CSS_PROPERTY = "style-unknown-css-property";
|
|
243
306
|
declare const STYLE_UNKNOWN_TOKEN = "style-unknown-token";
|
|
244
|
-
type AnyRec$
|
|
307
|
+
type AnyRec$w = Record<string, unknown>;
|
|
245
308
|
/**
|
|
246
309
|
* Validate every page's component tree for SDUI styling correctness (ADR-0065).
|
|
247
310
|
* Returns findings (empty = clean). `error` findings describe styles that are
|
|
248
311
|
* silently dropped and should fail validate/build; `warning` findings are
|
|
249
312
|
* advisory (typos, drift, footguns).
|
|
250
313
|
*/
|
|
251
|
-
declare function validateResponsiveStyles(stack: AnyRec$
|
|
314
|
+
declare function validateResponsiveStyles(stack: AnyRec$w): StyleFinding[];
|
|
252
315
|
|
|
253
316
|
type JsxPageSeverity = 'error' | 'warning';
|
|
254
317
|
interface JsxPageFinding {
|
|
@@ -261,8 +324,8 @@ interface JsxPageFinding {
|
|
|
261
324
|
message: string;
|
|
262
325
|
hint: string;
|
|
263
326
|
}
|
|
264
|
-
type AnyRec$
|
|
265
|
-
declare function validateJsxPages(stack: AnyRec$
|
|
327
|
+
type AnyRec$v = Record<string, unknown>;
|
|
328
|
+
declare function validateJsxPages(stack: AnyRec$v, opts?: {
|
|
266
329
|
manifest?: Manifest;
|
|
267
330
|
}): JsxPageFinding[];
|
|
268
331
|
|
|
@@ -275,8 +338,8 @@ interface ReactPageFinding {
|
|
|
275
338
|
message: string;
|
|
276
339
|
hint: string;
|
|
277
340
|
}
|
|
278
|
-
type AnyRec$
|
|
279
|
-
declare function validateReactPages(stack: AnyRec$
|
|
341
|
+
type AnyRec$u = Record<string, unknown>;
|
|
342
|
+
declare function validateReactPages(stack: AnyRec$u): ReactPageFinding[];
|
|
280
343
|
|
|
281
344
|
type ReactPropSeverity = 'error' | 'warning';
|
|
282
345
|
interface ReactPropFinding {
|
|
@@ -287,11 +350,12 @@ interface ReactPropFinding {
|
|
|
287
350
|
message: string;
|
|
288
351
|
hint: string;
|
|
289
352
|
}
|
|
290
|
-
type AnyRec$
|
|
353
|
+
type AnyRec$t = Record<string, unknown>;
|
|
291
354
|
declare const REACT_CHART_FIELD_UNKNOWN = "react-chart-field-unknown";
|
|
292
355
|
declare const REACT_CHART_AGGREGATE_INVALID = "react-chart-aggregate-invalid";
|
|
293
356
|
declare const REACT_CHART_AXIS_UNKNOWN = "react-chart-axis-unknown";
|
|
294
|
-
declare
|
|
357
|
+
declare const REACT_BLOCK_NEEDS_RECORD_CONTEXT = "react-block-needs-record-context";
|
|
358
|
+
declare function validateReactPageProps(stack: AnyRec$t): ReactPropFinding[];
|
|
295
359
|
|
|
296
360
|
type SourceStyleSeverity = 'error' | 'warning';
|
|
297
361
|
interface SourceStyleFinding {
|
|
@@ -303,8 +367,8 @@ interface SourceStyleFinding {
|
|
|
303
367
|
hint: string;
|
|
304
368
|
}
|
|
305
369
|
declare const PAGE_SOURCE_CLASSNAME = "page-source-className-tailwind";
|
|
306
|
-
type AnyRec$
|
|
307
|
-
declare function validatePageSourceStyling(stack: AnyRec$
|
|
370
|
+
type AnyRec$s = Record<string, unknown>;
|
|
371
|
+
declare function validatePageSourceStyling(stack: AnyRec$s): SourceStyleFinding[];
|
|
308
372
|
|
|
309
373
|
/**
|
|
310
374
|
* Build-time record-title diagnostics (ADR-0079).
|
|
@@ -348,14 +412,14 @@ interface RecordTitleFinding {
|
|
|
348
412
|
/** How to fix it. */
|
|
349
413
|
hint: string;
|
|
350
414
|
}
|
|
351
|
-
type AnyRec$
|
|
415
|
+
type AnyRec$r = Record<string, unknown>;
|
|
352
416
|
/**
|
|
353
417
|
* Validate every object's record-title declaration. Returns the list of
|
|
354
418
|
* findings (empty = clean). Both rules are advisory (`warning`): the caller
|
|
355
419
|
* must never fail the build on them alone — auto-provision + the `Record #<id>`
|
|
356
420
|
* floor guarantee a resolvable title at runtime.
|
|
357
421
|
*/
|
|
358
|
-
declare function validateRecordTitle(stack: AnyRec$
|
|
422
|
+
declare function validateRecordTitle(stack: AnyRec$r): RecordTitleFinding[];
|
|
359
423
|
|
|
360
424
|
/**
|
|
361
425
|
* Build-time semantic-role diagnostics (ADR-0085).
|
|
@@ -392,13 +456,13 @@ interface SemanticRoleFinding {
|
|
|
392
456
|
/** How to fix it. */
|
|
393
457
|
hint: string;
|
|
394
458
|
}
|
|
395
|
-
type AnyRec$
|
|
459
|
+
type AnyRec$q = Record<string, unknown>;
|
|
396
460
|
/**
|
|
397
461
|
* Validate every object's semantic-role pointers. Returns the list of
|
|
398
462
|
* findings (empty = clean). Advisory only — the caller must never fail the
|
|
399
463
|
* build on these alone.
|
|
400
464
|
*/
|
|
401
|
-
declare function validateSemanticRoles(stack: AnyRec$
|
|
465
|
+
declare function validateSemanticRoles(stack: AnyRec$q): SemanticRoleFinding[];
|
|
402
466
|
|
|
403
467
|
/**
|
|
404
468
|
* Build-time form-layout diagnostics (#2578).
|
|
@@ -441,12 +505,12 @@ interface FormLayoutFinding {
|
|
|
441
505
|
/** How to fix it. */
|
|
442
506
|
hint: string;
|
|
443
507
|
}
|
|
444
|
-
type AnyRec$
|
|
508
|
+
type AnyRec$p = Record<string, unknown>;
|
|
445
509
|
/**
|
|
446
510
|
* Validate authored form-view layout. Returns findings (empty = clean).
|
|
447
511
|
* Advisory only — the caller must never fail the build on these alone.
|
|
448
512
|
*/
|
|
449
|
-
declare function validateFormLayout(stack: AnyRec$
|
|
513
|
+
declare function validateFormLayout(stack: AnyRec$p): FormLayoutFinding[];
|
|
450
514
|
|
|
451
515
|
/**
|
|
452
516
|
* Build-time conditional-visibility diagnostics (ADR-0089 D3b).
|
|
@@ -508,7 +572,7 @@ interface VisibilityFinding {
|
|
|
508
572
|
/** How to fix it. */
|
|
509
573
|
hint: string;
|
|
510
574
|
}
|
|
511
|
-
type AnyRec$
|
|
575
|
+
type AnyRec$o = Record<string, unknown>;
|
|
512
576
|
/**
|
|
513
577
|
* Validate conditional-visibility keys across authored views and pages.
|
|
514
578
|
*
|
|
@@ -523,7 +587,7 @@ type AnyRec$f = Record<string, unknown>;
|
|
|
523
587
|
* `*.view.ts` / `*.page.ts` surfaces (so a `data.`-rooted predicate is flagged). The
|
|
524
588
|
* alias-deprecated check is layer-agnostic.
|
|
525
589
|
*/
|
|
526
|
-
declare function validateVisibilityPredicates(stack: AnyRec$
|
|
590
|
+
declare function validateVisibilityPredicates(stack: AnyRec$o, opts?: VisibilityOptions): VisibilityFinding[];
|
|
527
591
|
|
|
528
592
|
declare const CAPABILITY_REFERENCE_UNKNOWN = "capability-reference-unknown";
|
|
529
593
|
type CapabilityRefSeverity = 'error' | 'warning';
|
|
@@ -541,12 +605,12 @@ interface CapabilityRefFinding {
|
|
|
541
605
|
/** How to fix it. */
|
|
542
606
|
hint: string;
|
|
543
607
|
}
|
|
544
|
-
type AnyRec$
|
|
608
|
+
type AnyRec$n = Record<string, unknown>;
|
|
545
609
|
/**
|
|
546
610
|
* Validate every capability reference in a stack. Returns findings (empty =
|
|
547
611
|
* clean). Advisory only — callers must not fail the build on these alone.
|
|
548
612
|
*/
|
|
549
|
-
declare function validateCapabilityReferences(stack: AnyRec$
|
|
613
|
+
declare function validateCapabilityReferences(stack: AnyRec$n): CapabilityRefFinding[];
|
|
550
614
|
|
|
551
615
|
declare const APPROVAL_APPROVER_NOT_MEMBERSHIP_TIER = "approval-approver-not-membership-tier";
|
|
552
616
|
declare const APPROVAL_APPROVER_TYPE_DEPRECATED = "approval-approver-type-deprecated";
|
|
@@ -571,12 +635,12 @@ interface ApprovalApproverFinding {
|
|
|
571
635
|
/** How to fix it. */
|
|
572
636
|
hint: string;
|
|
573
637
|
}
|
|
574
|
-
type AnyRec$
|
|
638
|
+
type AnyRec$m = Record<string, unknown>;
|
|
575
639
|
/**
|
|
576
640
|
* Validate the approvers of every Approval node in the stack's flows.
|
|
577
641
|
* Returns findings (empty = clean).
|
|
578
642
|
*/
|
|
579
|
-
declare function validateApprovalApprovers(stack: AnyRec$
|
|
643
|
+
declare function validateApprovalApprovers(stack: AnyRec$m): ApprovalApproverFinding[];
|
|
580
644
|
|
|
581
645
|
type SeedReplaySafetySeverity = 'error' | 'warning';
|
|
582
646
|
interface SeedReplaySafetyFinding {
|
|
@@ -590,7 +654,7 @@ interface SeedReplaySafetyFinding {
|
|
|
590
654
|
hint: string;
|
|
591
655
|
}
|
|
592
656
|
declare const SEED_INSERT_MODE_DUPLICATES_ON_REPLAY = "seed-insert-mode-duplicates-on-replay";
|
|
593
|
-
type AnyRec$
|
|
657
|
+
type AnyRec$l = Record<string, unknown>;
|
|
594
658
|
/**
|
|
595
659
|
* Flag every seed dataset declared with `mode: 'insert'` — the one non-idempotent
|
|
596
660
|
* mode, which duplicates its rows on every replay boot (framework#3434). Returns
|
|
@@ -600,7 +664,7 @@ type AnyRec$c = Record<string, unknown>;
|
|
|
600
664
|
* Reads `stack.data` (the `SeedSchema[]` fixtures). Safe on any shape — a stack
|
|
601
665
|
* with no `data` array yields no findings.
|
|
602
666
|
*/
|
|
603
|
-
declare function validateSeedReplaySafety(stack: AnyRec$
|
|
667
|
+
declare function validateSeedReplaySafety(stack: AnyRec$l): SeedReplaySafetyFinding[];
|
|
604
668
|
|
|
605
669
|
type SeedStateMachineSeverity = 'warning';
|
|
606
670
|
interface SeedStateMachineFinding {
|
|
@@ -614,7 +678,7 @@ interface SeedStateMachineFinding {
|
|
|
614
678
|
hint: string;
|
|
615
679
|
}
|
|
616
680
|
declare const SEED_VALUE_OUTSIDE_STATE_MACHINE = "seed-value-outside-state-machine";
|
|
617
|
-
type AnyRec$
|
|
681
|
+
type AnyRec$k = Record<string, unknown>;
|
|
618
682
|
/**
|
|
619
683
|
* Flag every seed record whose `state_machine`-governed field carries a value
|
|
620
684
|
* the machine does not declare (framework#3433 follow-up). Returns the findings
|
|
@@ -627,7 +691,7 @@ type AnyRec$b = Record<string, unknown>;
|
|
|
627
691
|
* unresolved `cel` Expression envelope, a number) is skipped: it cannot be
|
|
628
692
|
* statically compared to the declared-state set.
|
|
629
693
|
*/
|
|
630
|
-
declare function validateSeedStateMachine(stack: AnyRec$
|
|
694
|
+
declare function validateSeedStateMachine(stack: AnyRec$k): SeedStateMachineFinding[];
|
|
631
695
|
|
|
632
696
|
declare const SECURITY_OWD_UNSET = "security-owd-unset";
|
|
633
697
|
declare const SECURITY_OWD_ALIAS = "security-owd-alias";
|
|
@@ -654,7 +718,7 @@ interface SecurityFinding {
|
|
|
654
718
|
/** How to fix it. */
|
|
655
719
|
hint: string;
|
|
656
720
|
}
|
|
657
|
-
type AnyRec$
|
|
721
|
+
type AnyRec$j = Record<string, unknown>;
|
|
658
722
|
/**
|
|
659
723
|
* Validate the security posture of a stack. Returns findings (empty = clean).
|
|
660
724
|
* `error` findings gate the build in `os compile`; `info` is advisory.
|
|
@@ -662,7 +726,7 @@ type AnyRec$a = Record<string, unknown>;
|
|
|
662
726
|
* `opts.nowMs` injects the clock for the ADR-0091 authoring-time expiry rule
|
|
663
727
|
* (tests); production callers omit it.
|
|
664
728
|
*/
|
|
665
|
-
declare function validateSecurityPosture(stack: AnyRec$
|
|
729
|
+
declare function validateSecurityPosture(stack: AnyRec$j, opts?: {
|
|
666
730
|
nowMs?: number;
|
|
667
731
|
}): SecurityFinding[];
|
|
668
732
|
|
|
@@ -796,13 +860,13 @@ interface DashboardActionRefFinding {
|
|
|
796
860
|
/** How to fix it. */
|
|
797
861
|
hint: string;
|
|
798
862
|
}
|
|
799
|
-
type AnyRec$
|
|
863
|
+
type AnyRec$i = Record<string, unknown>;
|
|
800
864
|
/**
|
|
801
865
|
* Validate every dashboard header / widget action reference in a stack. Returns
|
|
802
866
|
* findings (empty = clean). `script`/`modal` dead targets are errors; `url`
|
|
803
867
|
* unresolved routes are warnings.
|
|
804
868
|
*/
|
|
805
|
-
declare function validateDashboardActionRefs(stack: AnyRec$
|
|
869
|
+
declare function validateDashboardActionRefs(stack: AnyRec$i): DashboardActionRefFinding[];
|
|
806
870
|
|
|
807
871
|
/**
|
|
808
872
|
* Build-time filter-placeholder diagnostics (issue #3574).
|
|
@@ -900,12 +964,247 @@ interface ObjectRefFinding {
|
|
|
900
964
|
/** How to fix it. */
|
|
901
965
|
hint: string;
|
|
902
966
|
}
|
|
903
|
-
type AnyRec$
|
|
967
|
+
type AnyRec$h = Record<string, unknown>;
|
|
904
968
|
/**
|
|
905
969
|
* Validate every object-name reference on the surfaces listed in the module
|
|
906
970
|
* header. Returns findings (empty = clean).
|
|
907
971
|
*/
|
|
908
|
-
declare function validateObjectReferences(stack: AnyRec$
|
|
972
|
+
declare function validateObjectReferences(stack: AnyRec$h): ObjectRefFinding[];
|
|
973
|
+
|
|
974
|
+
type ReferenceIntegritySeverity = 'error' | 'warning';
|
|
975
|
+
/**
|
|
976
|
+
* The shape every rule in the suite already returns. Declared here so callers
|
|
977
|
+
* can hold one type instead of a six-way union.
|
|
978
|
+
*/
|
|
979
|
+
interface ReferenceIntegrityFinding {
|
|
980
|
+
/** `error` = the reference is dead; `warning` = it may resolve elsewhere, or the miss is inert. */
|
|
981
|
+
severity: ReferenceIntegritySeverity;
|
|
982
|
+
/** Diagnostic rule id (stable; used by allowlists and docs). */
|
|
983
|
+
rule: string;
|
|
984
|
+
/** Human-readable location. */
|
|
985
|
+
where: string;
|
|
986
|
+
/** Config path. */
|
|
987
|
+
path: string;
|
|
988
|
+
/** What is wrong. */
|
|
989
|
+
message: string;
|
|
990
|
+
/** How to fix it. */
|
|
991
|
+
hint: string;
|
|
992
|
+
}
|
|
993
|
+
/** One member of the suite. `name` is the exported function's name — the id a wiring test can assert on. */
|
|
994
|
+
interface ReferenceIntegrityRule {
|
|
995
|
+
name: string;
|
|
996
|
+
run: (stack: Record<string, unknown>) => ReferenceIntegrityFinding[];
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* Every reference-integrity rule, in the order their findings are reported.
|
|
1000
|
+
*
|
|
1001
|
+
* ADDING A RULE: append it here and it runs on `validate`, `lint` and
|
|
1002
|
+
* `compile` at once. Do not re-wire the commands.
|
|
1003
|
+
*/
|
|
1004
|
+
declare const REFERENCE_INTEGRITY_RULES: readonly ReferenceIntegrityRule[];
|
|
1005
|
+
/**
|
|
1006
|
+
* Run every reference-integrity rule over a stack. Returns the concatenated
|
|
1007
|
+
* findings (empty = clean). Pure: no I/O, safe on both the schema-parsed stack
|
|
1008
|
+
* and the raw/normalized config the `lint` path carries.
|
|
1009
|
+
*/
|
|
1010
|
+
declare function validateReferenceIntegrity(stack: Record<string, unknown>): ReferenceIntegrityFinding[];
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* [ADR-0072 — reference resolvability] App-navigation targets that are not
|
|
1014
|
+
* object names: `page`, `report`, `dashboard`.
|
|
1015
|
+
*
|
|
1016
|
+
* ## The hole this closes is inside an EXISTING check, not a missing one
|
|
1017
|
+
*
|
|
1018
|
+
* `defineStack`'s `validateCrossReferences` already validates these three
|
|
1019
|
+
* (`stack.zod.ts`, the "Validate app navigation → object/dashboard/page/report
|
|
1020
|
+
* references" block). But each of the three is guarded on the collection being
|
|
1021
|
+
* non-empty:
|
|
1022
|
+
*
|
|
1023
|
+
* ```ts
|
|
1024
|
+
* if (nav.type === 'page' && typeof nav.pageName === 'string'
|
|
1025
|
+
* && pageNames.size > 0 && !pageNames.has(nav.pageName)) { … }
|
|
1026
|
+
* ```
|
|
1027
|
+
*
|
|
1028
|
+
* So a stack that declares **no `pages` at all** has its page-nav check
|
|
1029
|
+
* silently switched off, and `{ type: 'page', pageName: 'anything' }` sails
|
|
1030
|
+
* through. That is precisely the state a stack is in when the target was never
|
|
1031
|
+
* written — the most likely way to get here, not the least.
|
|
1032
|
+
*
|
|
1033
|
+
* Note the asymmetry the guard creates. The `object` arm of the same block has
|
|
1034
|
+
* no size gate: it errors unless the item carries `requiresObject`, an
|
|
1035
|
+
* EXPLICIT opt-in to "another package provides this". Objects therefore say so
|
|
1036
|
+
* out loud; pages, reports and dashboards get an implicit exemption that
|
|
1037
|
+
* depends on an unrelated property of the stack.
|
|
1038
|
+
*
|
|
1039
|
+
* This rule restores the coverage with the ADR-0072 severity posture rather
|
|
1040
|
+
* than by tightening the parse-time throw — a throw has no escape hatch for a
|
|
1041
|
+
* legitimately cross-package page, and ADR-0072 D1's rule is that one dead
|
|
1042
|
+
* finding costs more than a missed one.
|
|
1043
|
+
*
|
|
1044
|
+
* ## Severity: warning, and why it is not error
|
|
1045
|
+
*
|
|
1046
|
+
* `validate-object-references` can say ERROR for an unresolved *object*
|
|
1047
|
+
* because it resolves against a curated `PLATFORM_PROVIDED_OBJECT_NAMES`
|
|
1048
|
+
* registry — it knows which cross-package names are real. No such registry
|
|
1049
|
+
* exists for pages, reports or dashboards, so "unresolved" genuinely cannot be
|
|
1050
|
+
* distinguished from "provided by a package we cannot see from here".
|
|
1051
|
+
* Advisory is the honest ceiling. When `defineStack`'s own check is live (the
|
|
1052
|
+
* collection is non-empty) it still hard-fails first; this rule is what speaks
|
|
1053
|
+
* when that check has switched itself off.
|
|
1054
|
+
*
|
|
1055
|
+
* ## Deliberately NOT covered — each verified, not assumed
|
|
1056
|
+
*
|
|
1057
|
+
* - **`action`** (`actionDef.actionName`) — already owned by
|
|
1058
|
+
* `validate-action-name-refs`, which walks app navigation explicitly. Adding
|
|
1059
|
+
* it here would double-report the same finding.
|
|
1060
|
+
* - **`component`** (`componentRef`) — verified a NON-rule. An unregistered ref
|
|
1061
|
+
* does NOT fail silently: `ComponentNavView` renders a named diagnostic
|
|
1062
|
+
* ("Component not registered … Ensure the plugin that provides this surface
|
|
1063
|
+
* is installed and has called `registerAppComponent()`"), and the registry
|
|
1064
|
+
* exists precisely so plugin-provided surfaces may legitimately be absent.
|
|
1065
|
+
* Flagging it would break valid plugin nav and prescribe a fix for something
|
|
1066
|
+
* already reported better at runtime.
|
|
1067
|
+
* - **`url`** — external by definition; nothing to resolve against.
|
|
1068
|
+
*/
|
|
1069
|
+
|
|
1070
|
+
type NavTargetRefSeverity = 'error' | 'warning';
|
|
1071
|
+
type NavTargetRefFinding = ReferenceIntegrityFinding;
|
|
1072
|
+
/** Emitted when a nav item targets a page/report/dashboard the stack cannot resolve. */
|
|
1073
|
+
declare const NAV_TARGET_UNRESOLVED = "nav-target-unresolved";
|
|
1074
|
+
declare function validateNavTargetRefs(stack: unknown): NavTargetRefFinding[];
|
|
1075
|
+
|
|
1076
|
+
/**
|
|
1077
|
+
* [ADR-0061 — searchable set] `searchableFields` entries must name a field the
|
|
1078
|
+
* object actually has — and, on a list view, one the runtime will agree to scan.
|
|
1079
|
+
*
|
|
1080
|
+
* `searchableFields` is `z.array(z.string())` in both `object.zod.ts` and the
|
|
1081
|
+
* list-view schema, so nothing checks that an entry resolves to anything. Rename
|
|
1082
|
+
* a field and the old name stays behind: Zod-valid, shipped, and pointing at a
|
|
1083
|
+
* column that no longer exists.
|
|
1084
|
+
*
|
|
1085
|
+
* ── Why a stale entry is not merely inert ────────────────────────────────
|
|
1086
|
+
*
|
|
1087
|
+
* The engine tolerates it. `resolveSearchFields` (`@objectstack/objectql`)
|
|
1088
|
+
* filters the declaration down to fields that exist —
|
|
1089
|
+
* `searchableFields?.filter((f) => all[f])` — so a stale name is dropped
|
|
1090
|
+
* without a word. That tolerance is what makes the drift invisible, and it
|
|
1091
|
+
* fails in the direction nobody expects:
|
|
1092
|
+
*
|
|
1093
|
+
* - Some entries stale → `$search` quietly scans a NARROWER set than the
|
|
1094
|
+
* object declares. Records that should match do not, and the response is
|
|
1095
|
+
* indistinguishable from "no such record".
|
|
1096
|
+
* - EVERY entry stale → the filtered set is empty, so resolution falls
|
|
1097
|
+
* through to the AUTO-DEFAULT (name/title + short-text fields). A
|
|
1098
|
+
* declaration whose entire purpose is to CHOOSE the searchable set ends up
|
|
1099
|
+
* selecting a set the author never wrote — the same "asked narrower,
|
|
1100
|
+
* answered wider" inversion #4226 closed on the projection axis.
|
|
1101
|
+
*
|
|
1102
|
+
* And it does not stay quiet downstream. objectui's list search echoes
|
|
1103
|
+
* `schema.searchableFields` verbatim as the `$searchFields` override, so once
|
|
1104
|
+
* the REST read path validates that override against the object (#4254), a
|
|
1105
|
+
* stale declaration the engine had been silently skipping becomes a `400
|
|
1106
|
+
* INVALID_FIELD` on every list search for that object — a request-time break
|
|
1107
|
+
* whose cause is an authoring typo made long before.
|
|
1108
|
+
*
|
|
1109
|
+
* Hence `error`, not the advisory level the other field-existence rules use
|
|
1110
|
+
* (`page-field-unknown`, `form-field-unknown`, `semantic-role-field-unknown`
|
|
1111
|
+
* are all warnings). Those describe a consumer that SKIPS an unknown name and
|
|
1112
|
+
* renders the rest; this one describes a declaration that either selects the
|
|
1113
|
+
* wrong set or refuses the request outright. It is the same call
|
|
1114
|
+
* `validate-flow-template-paths` makes for a filter-position token: gating when
|
|
1115
|
+
* the miss widens the query rather than shrinking the page.
|
|
1116
|
+
*
|
|
1117
|
+
* ── What is checked ──────────────────────────────────────────────────────
|
|
1118
|
+
*
|
|
1119
|
+
* 1. EXISTENCE, on every surface (`searchable-field-unknown`): an entry that
|
|
1120
|
+
* resolves to no field at all is drift, whatever declared it.
|
|
1121
|
+
*
|
|
1122
|
+
* 2. RUNTIME ADMISSIBILITY, on view-level narrowings only
|
|
1123
|
+
* (`searchable-field-unsearchable`, #4830): a list view's
|
|
1124
|
+
* `searchableFields` is echoed verbatim by clients as the `$searchFields`
|
|
1125
|
+
* override, and the #4254 ingress gate
|
|
1126
|
+
* (`assertSearchFieldsAreSearchable`, `@objectstack/metadata-protocol`)
|
|
1127
|
+
* refuses any entry outside the object's server-resolved allowed set — so
|
|
1128
|
+
* ONE lookup-typed entry 400s EVERY toolbar search on that list, for every
|
|
1129
|
+
* role, and until #4830 `compile`/`validate` passed it in silence. The
|
|
1130
|
+
* allowed set here is computed by the very function the runtime gate and
|
|
1131
|
+
* the engine consult — {@link resolveSearchFieldResolution}
|
|
1132
|
+
* (`@objectstack/spec/data`) — never by a second copy of its type list, so
|
|
1133
|
+
* linter, gate and engine cannot drift apart (the same one-source move
|
|
1134
|
+
* #4254 made between gate and engine).
|
|
1135
|
+
*
|
|
1136
|
+
* The OBJECT's own `searchableFields` stays existence-only: the runtime's
|
|
1137
|
+
* declared branch filters by existence, never by type, so a json or lookup
|
|
1138
|
+
* column declared THERE is a choice the engine executes (a `$contains` over
|
|
1139
|
+
* the raw column), not a 400. Flagging it would reject metadata the runtime
|
|
1140
|
+
* accepts — the false finding that makes authors stop trusting the linter
|
|
1141
|
+
* (ADR-0072 D1).
|
|
1142
|
+
*
|
|
1143
|
+
* Three skips keep false positives near zero (ADR-0072 D1):
|
|
1144
|
+
*
|
|
1145
|
+
* 1. An object this stack does not define. It may come from another package,
|
|
1146
|
+
* and a field map we cannot see cannot be judged (the same skip the
|
|
1147
|
+
* page/flow/widget rules take).
|
|
1148
|
+
* 2. An object that declares no field map at all — external objects and
|
|
1149
|
+
* datasource-introspected schemas whose columns are resolved at runtime.
|
|
1150
|
+
* 3. Registry-injected system columns, which exist at runtime but never
|
|
1151
|
+
* appear in authored `fields` — the package-shared `SYSTEM_FIELDS`
|
|
1152
|
+
* (`system-fields.ts`), derived from the spec's own declarations rather
|
|
1153
|
+
* than hand-copied (#4330). The admissibility check also skips them:
|
|
1154
|
+
* their runtime field metadata (type, hidden) is registry-owned and not
|
|
1155
|
+
* visible here, and judging a column we cannot see risks the false
|
|
1156
|
+
* positive this list exists to avoid. (Cost asymmetry: a system column
|
|
1157
|
+
* the runtime would refuse — `created_by` in a view's narrowing — is a
|
|
1158
|
+
* missed finding, not a wrong one.)
|
|
1159
|
+
*
|
|
1160
|
+
* Dotted paths are NOT skipped here, unlike every sibling rule. Elsewhere
|
|
1161
|
+
* `owner_id.name` is left alone because the query engine resolves the traversal;
|
|
1162
|
+
* search does not — `resolveSearchFields` matches the field map by exact string,
|
|
1163
|
+
* so a dotted entry is dropped exactly like a typo. Skipping it would exempt the
|
|
1164
|
+
* one wrong spelling most likely to be borrowed from `select`/`sort`.
|
|
1165
|
+
*/
|
|
1166
|
+
|
|
1167
|
+
declare const SEARCHABLE_FIELD_UNKNOWN = "searchable-field-unknown";
|
|
1168
|
+
declare const SEARCHABLE_FIELD_UNSEARCHABLE = "searchable-field-unsearchable";
|
|
1169
|
+
type SearchableFieldSeverity = 'error' | 'warning';
|
|
1170
|
+
interface SearchableFieldFinding {
|
|
1171
|
+
/** Always `error` — a stale entry narrows, widens or refuses the search (see module note). */
|
|
1172
|
+
severity: SearchableFieldSeverity;
|
|
1173
|
+
/** Diagnostic rule id. */
|
|
1174
|
+
rule: string;
|
|
1175
|
+
/** Human-readable location, e.g. `object "crm_lead"`. */
|
|
1176
|
+
where: string;
|
|
1177
|
+
/** Config path, e.g. `objects[0].searchableFields[2]`. */
|
|
1178
|
+
path: string;
|
|
1179
|
+
/** What is wrong. */
|
|
1180
|
+
message: string;
|
|
1181
|
+
/** How to fix it. */
|
|
1182
|
+
hint: string;
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Which runtime judgment applies to the declaration being checked:
|
|
1186
|
+
*
|
|
1187
|
+
* - `'canonical'` — the object's own `searchableFields`. The runtime honors
|
|
1188
|
+
* any entry that exists (existence-filtered, never type-filtered), so only
|
|
1189
|
+
* existence is checked.
|
|
1190
|
+
* - `'narrowing'` — a list view's `searchableFields` (metadata or react
|
|
1191
|
+
* surface). Clients echo it as the `$searchFields` override, which the
|
|
1192
|
+
* #4254 ingress gate intersects with the object's allowed set — entries the
|
|
1193
|
+
* runtime would refuse are flagged (#4830).
|
|
1194
|
+
*/
|
|
1195
|
+
type SearchableFieldRole = 'canonical' | 'narrowing';
|
|
1196
|
+
type AnyRec$g = Record<string, unknown>;
|
|
1197
|
+
/**
|
|
1198
|
+
* Validate every `searchableFields` declaration in the stack — the object's own
|
|
1199
|
+
* (the canonical set, ADR-0061) and the list views that narrow it. Returns
|
|
1200
|
+
* findings (empty = clean).
|
|
1201
|
+
*
|
|
1202
|
+
* The react page surface (`<ListView searchableFields={…}>`) is deliberately
|
|
1203
|
+
* NOT walked here: its declaration lives inside JSX source, and
|
|
1204
|
+
* `validate-react-page-props` — the gate that already parses that source —
|
|
1205
|
+
* runs the same `checkSearchableFieldList` core on it (#4329).
|
|
1206
|
+
*/
|
|
1207
|
+
declare function validateSearchableFields(stack: AnyRec$g): SearchableFieldFinding[];
|
|
909
1208
|
|
|
910
1209
|
declare const ACTION_NAME_UNDEFINED = "action-name-undefined";
|
|
911
1210
|
type ActionNameRefSeverity = 'error' | 'warning';
|
|
@@ -923,12 +1222,84 @@ interface ActionNameRefFinding {
|
|
|
923
1222
|
/** How to fix it. */
|
|
924
1223
|
hint: string;
|
|
925
1224
|
}
|
|
926
|
-
type AnyRec$
|
|
1225
|
+
type AnyRec$f = Record<string, unknown>;
|
|
927
1226
|
/**
|
|
928
1227
|
* Validate every name-bound action reference in a stack. Returns findings
|
|
929
1228
|
* (empty = clean).
|
|
930
1229
|
*/
|
|
931
|
-
declare function validateActionNameRefs(stack: AnyRec$
|
|
1230
|
+
declare function validateActionNameRefs(stack: AnyRec$f): ActionNameRefFinding[];
|
|
1231
|
+
|
|
1232
|
+
/**
|
|
1233
|
+
* [ADR-0078 Phase 3 — Tier-A `action-locations`] An action nobody placed.
|
|
1234
|
+
*
|
|
1235
|
+
* `locations` is an action's placement declaration. An action that omits it —
|
|
1236
|
+
* and that no view names in `bulkActions` / `bulkActionDefs` / `rowActions` —
|
|
1237
|
+
* has no surface at all: it parses, it publishes, Setup lists it, and no user
|
|
1238
|
+
* can ever click it. ADR-0078 names this shape in its opening paragraph ("a
|
|
1239
|
+
* `summary` with no `summaryOperations`; **an `action` with no `locations`**;
|
|
1240
|
+
* … Each parses, 'renders', reports success — and does nothing") and Phase 3
|
|
1241
|
+
* asks for exactly this rule, one verified shape at a time.
|
|
1242
|
+
*
|
|
1243
|
+
* The renderer half is now unambiguous: objectui#3142 collapsed four
|
|
1244
|
+
* disagreeing renderers onto one predicate — an action renders at a location
|
|
1245
|
+
* only if it DECLARES that location. Before that, `action:bar` and the record
|
|
1246
|
+
* header showed an undeclared action *everywhere*, which is what made this
|
|
1247
|
+
* shape look alive; it is measurably inert as of objectui 17.1.
|
|
1248
|
+
*
|
|
1249
|
+
* ## What is NOT flagged, and why
|
|
1250
|
+
*
|
|
1251
|
+
* **`locations: []` — a deliberate headless action.** `content/docs/ui/
|
|
1252
|
+
* actions.mdx` ("Headless actions: declare it, then hide it") documents the
|
|
1253
|
+
* empty array as a first-class shape: the action stays callable over REST /
|
|
1254
|
+
* MCP / AI and keeps its capability gate, param contract and audit trail,
|
|
1255
|
+
* while claiming no UI surface. ADR-0110 D3 refuses an *undeclared* handler,
|
|
1256
|
+
* so a headless declaration is the only legal way to expose such an action —
|
|
1257
|
+
* flagging it would fight that ADR. The distinction this rule draws is
|
|
1258
|
+
* therefore between an author who said "nowhere, deliberately" (`[]`) and one
|
|
1259
|
+
* who never said anything at all (key absent).
|
|
1260
|
+
*
|
|
1261
|
+
* **Actions a view places by NAME.** Naming an action in a list view's
|
|
1262
|
+
* `bulkActions` or `bulkActionDefs` IS its placement — the selection bar is
|
|
1263
|
+
* driven by the view, never by `locations` (that is what the retired
|
|
1264
|
+
* `action.bulkEnabled` tombstone prescribes, and what objectui#3139's
|
|
1265
|
+
* aggregate bulk mode relies on: an action that only makes sense over a
|
|
1266
|
+
* selection has no single-record location by construction). `rowActions` is
|
|
1267
|
+
* exempted on the same zero-false-positive posture (ADR-0072 D1): it is the
|
|
1268
|
+
* same field pair on the same container, and an author who named an action
|
|
1269
|
+
* there has stated an intent — a name that resolves to nothing is already
|
|
1270
|
+
* `action-name-undefined`'s job, not this rule's.
|
|
1271
|
+
*
|
|
1272
|
+
* Scope note: this rule asks only "did anyone place this action?". It
|
|
1273
|
+
* deliberately does NOT check that a declared location is one a renderer
|
|
1274
|
+
* actually serves, nor that a view's named action belongs to that view's
|
|
1275
|
+
* object — distinct classes with their own rules. Cross-package placement (a
|
|
1276
|
+
* view in another installed package naming this action) is the one legitimate
|
|
1277
|
+
* miss, which is why this is a **warning**: like every other "declared but
|
|
1278
|
+
* does nothing" finding in this package (`validateSemanticRoles`,
|
|
1279
|
+
* `lintLivenessProperties`), it is high-signal and never fatal.
|
|
1280
|
+
*/
|
|
1281
|
+
declare const ACTION_NO_PLACEMENT = "action-no-placement";
|
|
1282
|
+
type ActionLocationsSeverity = 'error' | 'warning';
|
|
1283
|
+
interface ActionLocationsFinding {
|
|
1284
|
+
/** Always `warning` — cross-package placement is a legitimate miss. */
|
|
1285
|
+
severity: ActionLocationsSeverity;
|
|
1286
|
+
/** Diagnostic rule id. */
|
|
1287
|
+
rule: string;
|
|
1288
|
+
/** Human-readable location, e.g. `action "crm_convert_lead"`. */
|
|
1289
|
+
where: string;
|
|
1290
|
+
/** Config path, e.g. `actions[2]` or `objects[0].actions[1]`. */
|
|
1291
|
+
path: string;
|
|
1292
|
+
/** What is wrong. */
|
|
1293
|
+
message: string;
|
|
1294
|
+
/** How to fix it. */
|
|
1295
|
+
hint: string;
|
|
1296
|
+
}
|
|
1297
|
+
type AnyRec$e = Record<string, unknown>;
|
|
1298
|
+
/**
|
|
1299
|
+
* Flag every action that declares no placement and that no view places by
|
|
1300
|
+
* name. Returns findings (empty = clean).
|
|
1301
|
+
*/
|
|
1302
|
+
declare function validateActionLocations(stack: AnyRec$e): ActionLocationsFinding[];
|
|
932
1303
|
|
|
933
1304
|
/**
|
|
934
1305
|
* Shared page-component traversal for the lint rules that inspect
|
|
@@ -954,7 +1325,7 @@ declare function validateActionNameRefs(stack: AnyRec$7): ActionNameRefFinding[]
|
|
|
954
1325
|
* author never wrote, so those pages are skipped here and covered by
|
|
955
1326
|
* `validate-jsx-pages` / `validate-react-page-props` instead.
|
|
956
1327
|
*/
|
|
957
|
-
type AnyRec$
|
|
1328
|
+
type AnyRec$d = Record<string, unknown>;
|
|
958
1329
|
|
|
959
1330
|
/**
|
|
960
1331
|
* [ADR-0078 — completeness] Field-reference integrity for page components
|
|
@@ -993,11 +1364,28 @@ type AnyRec$6 = Record<string, unknown>;
|
|
|
993
1364
|
* `record:details` `sections[].fields[]` and `hideFields[]`, and the record
|
|
994
1365
|
* picker's `labelField`. Linting the schema's shape alone would find nothing on
|
|
995
1366
|
* the actual corpus.
|
|
1367
|
+
*
|
|
1368
|
+
* ── Shared with the react page surface ──────────────────────────────────
|
|
1369
|
+
*
|
|
1370
|
+
* A `kind:'react'` page authors the SAME components, one surface over, as JSX
|
|
1371
|
+
* props instead of a `properties` bag (`<RecordHighlights fields={…}>`). The
|
|
1372
|
+
* extraction and the check are therefore exported — `COMPONENT_FIELD_SPECS`,
|
|
1373
|
+
* {@link componentFieldRefs}, {@link relatedListFieldRefs},
|
|
1374
|
+
* {@link indexObjectFields}, {@link checkFieldRefs} — and
|
|
1375
|
+
* `validate-react-page-props` runs them on the parsed JSX (#4340). Same table,
|
|
1376
|
+
* same skips, same rule id: the two surfaces agree on what counts as a field by
|
|
1377
|
+
* construction rather than by two lists that happen to match, which is the
|
|
1378
|
+
* drift #4330 had just finished removing from the system-field lists.
|
|
996
1379
|
*/
|
|
997
1380
|
declare const PAGE_FIELD_UNKNOWN = "page-field-unknown";
|
|
998
1381
|
type PageFieldSeverity = 'error' | 'warning';
|
|
999
1382
|
interface PageFieldFinding {
|
|
1000
|
-
/**
|
|
1383
|
+
/**
|
|
1384
|
+
* `warning` on every surface this rule itself walks — page renderers skip an
|
|
1385
|
+
* unknown field rather than fail. The shared {@link checkFieldRefs} core also
|
|
1386
|
+
* serves the react page surface, where one batch of refs reaches a QUERY
|
|
1387
|
+
* rather than a renderer and gates instead; see {@link FieldRefConsequence}.
|
|
1388
|
+
*/
|
|
1001
1389
|
severity: PageFieldSeverity;
|
|
1002
1390
|
/** Diagnostic rule id. */
|
|
1003
1391
|
rule: string;
|
|
@@ -1011,7 +1399,7 @@ interface PageFieldFinding {
|
|
|
1011
1399
|
hint: string;
|
|
1012
1400
|
}
|
|
1013
1401
|
|
|
1014
|
-
declare function validatePageFieldBindings(stack: AnyRec$
|
|
1402
|
+
declare function validatePageFieldBindings(stack: AnyRec$d): PageFieldFinding[];
|
|
1015
1403
|
|
|
1016
1404
|
/**
|
|
1017
1405
|
* [ADR-0021 — semantic layer] Chart-binding integrity for the surfaces the
|
|
@@ -1068,7 +1456,7 @@ interface ChartBindingFinding {
|
|
|
1068
1456
|
hint: string;
|
|
1069
1457
|
}
|
|
1070
1458
|
|
|
1071
|
-
declare function validateChartBindings(stack: AnyRec$
|
|
1459
|
+
declare function validateChartBindings(stack: AnyRec$d): ChartBindingFinding[];
|
|
1072
1460
|
|
|
1073
1461
|
declare const NAV_OBJECT_UNGRANTED = "nav-object-ungranted";
|
|
1074
1462
|
type NavAccessSeverity = 'error' | 'warning';
|
|
@@ -1086,12 +1474,12 @@ interface NavAccessFinding {
|
|
|
1086
1474
|
/** How to fix it. */
|
|
1087
1475
|
hint: string;
|
|
1088
1476
|
}
|
|
1089
|
-
type AnyRec$
|
|
1477
|
+
type AnyRec$c = Record<string, unknown>;
|
|
1090
1478
|
/**
|
|
1091
1479
|
* Validate that every object a stack's navigation exposes is readable by at
|
|
1092
1480
|
* least one permission set the stack declares. Returns findings (empty = clean).
|
|
1093
1481
|
*/
|
|
1094
|
-
declare function validateNavAccess(stack: AnyRec$
|
|
1482
|
+
declare function validateNavAccess(stack: AnyRec$c): NavAccessFinding[];
|
|
1095
1483
|
|
|
1096
1484
|
declare const TRANSLATION_TARGET_UNKNOWN = "translation-target-unknown";
|
|
1097
1485
|
declare const TRANSLATION_OPTION_KEY_UNKNOWN = "translation-option-key-unknown";
|
|
@@ -1110,12 +1498,12 @@ interface TranslationRefFinding {
|
|
|
1110
1498
|
/** How to fix it. */
|
|
1111
1499
|
hint: string;
|
|
1112
1500
|
}
|
|
1113
|
-
type AnyRec$
|
|
1501
|
+
type AnyRec$b = Record<string, unknown>;
|
|
1114
1502
|
/**
|
|
1115
1503
|
* Validate every reference a translation bundle makes against the metadata it
|
|
1116
1504
|
* claims to translate. Returns findings (empty = clean).
|
|
1117
1505
|
*/
|
|
1118
|
-
declare function validateTranslationReferences(stack: AnyRec$
|
|
1506
|
+
declare function validateTranslationReferences(stack: AnyRec$b): TranslationRefFinding[];
|
|
1119
1507
|
|
|
1120
1508
|
/**
|
|
1121
1509
|
* [ADR-0064 §3] Skill ↔ agent surface affinity (issue #3820).
|
|
@@ -1160,12 +1548,12 @@ interface AiSurfaceAffinityFinding {
|
|
|
1160
1548
|
/** How to fix it. */
|
|
1161
1549
|
hint: string;
|
|
1162
1550
|
}
|
|
1163
|
-
type AnyRec$
|
|
1551
|
+
type AnyRec$a = Record<string, unknown>;
|
|
1164
1552
|
/**
|
|
1165
1553
|
* Validate every in-stack agent→skill binding against the ADR-0064 §3 surface
|
|
1166
1554
|
* affinity contract. Returns findings (empty = clean).
|
|
1167
1555
|
*/
|
|
1168
|
-
declare function validateAiSurfaceAffinity(stack: AnyRec$
|
|
1556
|
+
declare function validateAiSurfaceAffinity(stack: AnyRec$a): AiSurfaceAffinityFinding[];
|
|
1169
1557
|
|
|
1170
1558
|
declare const AI_SKILL_TOOL_UNRESOLVED = "ai-skill-tool-unresolved";
|
|
1171
1559
|
type AiToolRefSeverity = 'error' | 'warning';
|
|
@@ -1183,12 +1571,12 @@ interface AiToolRefFinding {
|
|
|
1183
1571
|
/** How to fix it. */
|
|
1184
1572
|
hint: string;
|
|
1185
1573
|
}
|
|
1186
|
-
type AnyRec$
|
|
1574
|
+
type AnyRec$9 = Record<string, unknown>;
|
|
1187
1575
|
/**
|
|
1188
1576
|
* Validate every `skill.tools[]` reference in a stack. Returns findings
|
|
1189
1577
|
* (empty = clean).
|
|
1190
1578
|
*/
|
|
1191
|
-
declare function validateAiToolReferences(stack: AnyRec$
|
|
1579
|
+
declare function validateAiToolReferences(stack: AnyRec$9): AiToolRefFinding[];
|
|
1192
1580
|
|
|
1193
1581
|
/**
|
|
1194
1582
|
* [ADR-0063 §2] `stack.agents` is a platform-internal slot (issue #3820).
|
|
@@ -1233,50 +1621,202 @@ interface AiAgentAuthoringFinding {
|
|
|
1233
1621
|
/** How to fix it. */
|
|
1234
1622
|
hint: string;
|
|
1235
1623
|
}
|
|
1236
|
-
type AnyRec$
|
|
1624
|
+
type AnyRec$8 = Record<string, unknown>;
|
|
1237
1625
|
/**
|
|
1238
1626
|
* Flag every agent declared in a stack. Returns findings (empty = clean,
|
|
1239
1627
|
* which is what every app package should be).
|
|
1240
1628
|
*/
|
|
1241
|
-
declare function validateAiAgentAuthoring(stack: AnyRec$
|
|
1629
|
+
declare function validateAiAgentAuthoring(stack: AnyRec$8): AiAgentAuthoringFinding[];
|
|
1242
1630
|
|
|
1243
|
-
type
|
|
1631
|
+
type HookBodyWriteSeverity = 'warning';
|
|
1632
|
+
interface HookBodyWriteFinding {
|
|
1633
|
+
/** v1 is advisory-only by contract — the type says so. */
|
|
1634
|
+
severity: HookBodyWriteSeverity;
|
|
1635
|
+
rule: string;
|
|
1636
|
+
/** Human-readable location, e.g. `hook "normalize_lead" › body`. */
|
|
1637
|
+
where: string;
|
|
1638
|
+
/** Config path, e.g. `hooks[0].body.source`. */
|
|
1639
|
+
path: string;
|
|
1640
|
+
message: string;
|
|
1641
|
+
hint: string;
|
|
1642
|
+
}
|
|
1643
|
+
declare const HOOK_BODY_WRITE_UNKNOWN_FIELD = "hook-body-write-unknown-field";
|
|
1644
|
+
/** One syntactic write shape the extractor recognizes. */
|
|
1645
|
+
interface HookBodyWritePattern {
|
|
1646
|
+
/** Stable pattern id, carried on every extracted write. */
|
|
1647
|
+
readonly id: string;
|
|
1648
|
+
/** Author-facing syntax summary (for docs/diagnostics, not matching). */
|
|
1649
|
+
readonly syntax: string;
|
|
1650
|
+
/** Reconciliation fixture: extracting `source` must yield exactly `writes`. */
|
|
1651
|
+
readonly example: {
|
|
1652
|
+
readonly source: string;
|
|
1653
|
+
readonly writes: ReadonlyArray<{
|
|
1654
|
+
field: string;
|
|
1655
|
+
object?: string;
|
|
1656
|
+
}>;
|
|
1657
|
+
};
|
|
1658
|
+
}
|
|
1659
|
+
declare const HOOK_BODY_WRITE_PATTERNS: readonly HookBodyWritePattern[];
|
|
1660
|
+
/** A ledger pattern a given rule does NOT consume, and why. */
|
|
1661
|
+
interface BodyWritePatternExclusion {
|
|
1662
|
+
/** The {@link HOOK_BODY_WRITE_PATTERNS} entry id being excluded. */
|
|
1663
|
+
readonly id: string;
|
|
1664
|
+
/** Why the shape does not mean the same thing on this rule's surface. */
|
|
1665
|
+
readonly reason: string;
|
|
1666
|
+
}
|
|
1244
1667
|
/**
|
|
1245
|
-
* The
|
|
1246
|
-
*
|
|
1668
|
+
* The ledger shapes THIS rule consumes.
|
|
1669
|
+
*
|
|
1670
|
+
* Declared rather than implied: before the ledger carried a shape the hook
|
|
1671
|
+
* surface does not have, every write with no `object` was necessarily a
|
|
1672
|
+
* `ctx.input` write, and the rule could branch on that alone. It no longer can
|
|
1673
|
+
* — a `record-property-assign` write also carries no object, and would have
|
|
1674
|
+
* been reported as "the hook writes 'stage' to its input", which is false.
|
|
1675
|
+
* Each consumer declaring its own subset is what stops the next added shape
|
|
1676
|
+
* from silently landing in a branch that was never written for it.
|
|
1247
1677
|
*/
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1678
|
+
declare const HOOK_BODY_WRITE_PATTERN_IDS: readonly string[];
|
|
1679
|
+
/** Ledger shapes this rule leaves alone, each with its reason. */
|
|
1680
|
+
declare const HOOK_BODY_WRITE_EXCLUSIONS: readonly BodyWritePatternExclusion[];
|
|
1681
|
+
type AnyRec$7 = Record<string, unknown>;
|
|
1682
|
+
/** One statically-extracted field write found in an L2 body. */
|
|
1683
|
+
interface ExtractedHookBodyWrite {
|
|
1684
|
+
/** Which {@link HOOK_BODY_WRITE_PATTERNS} entry matched. */
|
|
1685
|
+
patternId: string;
|
|
1686
|
+
/** Target object name; `undefined` = the hook's own target object(s). */
|
|
1687
|
+
object?: string;
|
|
1688
|
+
/** The `ctx.api` method for diagnostics (`insert`/`create`/`update`/`updateById`). */
|
|
1689
|
+
method?: string;
|
|
1690
|
+
field: string;
|
|
1691
|
+
}
|
|
1692
|
+
/** Everything one parse of an L2 body yields. */
|
|
1693
|
+
interface ExtractedHookBodyWriteSet {
|
|
1694
|
+
/** Every literal write the {@link HOOK_BODY_WRITE_PATTERNS} ledger declares. */
|
|
1695
|
+
writes: ExtractedHookBodyWrite[];
|
|
1696
|
+
/**
|
|
1697
|
+
* `ctx.record` is handed to something as a VALUE somewhere in the body — an
|
|
1698
|
+
* argument, an assignment RHS, a spread, a return — rather than only having
|
|
1699
|
+
* its properties read and written, or being truthiness/type tested.
|
|
1700
|
+
*
|
|
1701
|
+
* The action rule needs this to tell a dead snapshot write from a live one:
|
|
1702
|
+
* `ctx.record.stage = 'won'; await ctx.api.object('d').update(ctx.record)`
|
|
1703
|
+
* builds a payload and persists it, so the assignment is not a no-op. When
|
|
1704
|
+
* this is true, no record write in the body can be judged, and none is
|
|
1705
|
+
* reported. (One-level aliasing — `const r = ctx.record` — reads as an
|
|
1706
|
+
* escape too, which is the safe direction: it suppresses findings.)
|
|
1707
|
+
*/
|
|
1708
|
+
ctxRecordEscapes: boolean;
|
|
1709
|
+
}
|
|
1710
|
+
/**
|
|
1711
|
+
* Extract every literal field write the pattern ledger declares from an L2
|
|
1712
|
+
* body's source. Parse-only (the source is never executed), error-tolerant
|
|
1713
|
+
* (a body with syntax errors simply yields fewer matches), and lazy: the
|
|
1714
|
+
* TypeScript compiler is not loaded when no pattern can possibly match.
|
|
1715
|
+
*
|
|
1716
|
+
* Thin projection of {@link extractHookBodyWriteSet} — use that one when the
|
|
1717
|
+
* `ctx.record` liveness signal matters, so the body is parsed once, not twice.
|
|
1718
|
+
*/
|
|
1719
|
+
declare function extractHookBodyWrites(source: string): ExtractedHookBodyWrite[];
|
|
1720
|
+
/** {@link extractHookBodyWrites} plus the `ctx.record` liveness signal, one parse. */
|
|
1721
|
+
declare function extractHookBodyWriteSet(source: string): ExtractedHookBodyWriteSet;
|
|
1722
|
+
/**
|
|
1723
|
+
* Validate L2 hook-body writes against target-object field declarations.
|
|
1724
|
+
* Pure `(stack) => Finding[]` (ADR-0019); safe on pre- or post-parse stacks.
|
|
1725
|
+
*/
|
|
1726
|
+
declare function validateHookBodyWrites(stack: AnyRec$7): HookBodyWriteFinding[];
|
|
1727
|
+
|
|
1728
|
+
type ActionBodyWriteSeverity = 'warning';
|
|
1729
|
+
interface ActionBodyWriteFinding {
|
|
1730
|
+
/** Advisory-only by contract, exactly like the hook rule — the type says so. */
|
|
1731
|
+
severity: ActionBodyWriteSeverity;
|
|
1252
1732
|
rule: string;
|
|
1253
|
-
/** Human-readable location. */
|
|
1733
|
+
/** Human-readable location, e.g. `action "close_deal" › body`. */
|
|
1254
1734
|
where: string;
|
|
1255
|
-
/** Config path. */
|
|
1735
|
+
/** Config path, e.g. `actions[0].body.source`. */
|
|
1256
1736
|
path: string;
|
|
1257
|
-
/** What is wrong. */
|
|
1258
1737
|
message: string;
|
|
1259
|
-
/** How to fix it. */
|
|
1260
1738
|
hint: string;
|
|
1261
1739
|
}
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
}
|
|
1740
|
+
declare const ACTION_BODY_WRITE_UNKNOWN_FIELD = "action-body-write-unknown-field";
|
|
1741
|
+
declare const ACTION_RECORD_WRITE_DISCARDED = "action-record-write-discarded";
|
|
1742
|
+
/** @deprecated alias — the exclusion shape is shared with the hook rule. */
|
|
1743
|
+
type ActionBodyWriteExclusion = BodyWritePatternExclusion;
|
|
1267
1744
|
/**
|
|
1268
|
-
*
|
|
1745
|
+
* Ledger shapes the UNKNOWN-FIELD check consumes — resolved against the named
|
|
1746
|
+
* object's declared fields.
|
|
1269
1747
|
*
|
|
1270
|
-
*
|
|
1271
|
-
*
|
|
1748
|
+
* Include-list, not exclude-list, on purpose: an unclassified new pattern is
|
|
1749
|
+
* then inert here (a missed finding) rather than live against a context it was
|
|
1750
|
+
* never reasoned about (a false one) — the same asymmetry the extractor's
|
|
1751
|
+
* silent bails follow.
|
|
1272
1752
|
*/
|
|
1273
|
-
declare const
|
|
1753
|
+
declare const ACTION_BODY_WRITE_PATTERN_IDS: readonly string[];
|
|
1274
1754
|
/**
|
|
1275
|
-
*
|
|
1276
|
-
*
|
|
1277
|
-
* and the raw/normalized config the `lint` path carries.
|
|
1755
|
+
* Ledger shapes the DISCARDED-RECORD-WRITE check consumes — never resolved
|
|
1756
|
+
* against anything, because no field name can make a discarded write land.
|
|
1278
1757
|
*/
|
|
1279
|
-
declare
|
|
1758
|
+
declare const ACTION_RECORD_WRITE_PATTERN_IDS: readonly string[];
|
|
1759
|
+
/** Shared-ledger patterns neither check consumes, each with its reason. */
|
|
1760
|
+
declare const ACTION_BODY_WRITE_EXCLUSIONS: readonly BodyWritePatternExclusion[];
|
|
1761
|
+
/**
|
|
1762
|
+
* The subset of the shared ledger the unknown-field check sees — the published
|
|
1763
|
+
* answer to "which writes does the action lint resolve against fields?".
|
|
1764
|
+
*/
|
|
1765
|
+
declare const ACTION_BODY_WRITE_PATTERNS: readonly HookBodyWritePattern[];
|
|
1766
|
+
/** The subset the discarded-record-write check sees. */
|
|
1767
|
+
declare const ACTION_RECORD_WRITE_PATTERNS: readonly HookBodyWritePattern[];
|
|
1768
|
+
type AnyRec$6 = Record<string, unknown>;
|
|
1769
|
+
/**
|
|
1770
|
+
* Validate L2 action-body writes against target-object field declarations.
|
|
1771
|
+
* Pure `(stack) => Finding[]` (ADR-0019); safe on pre- or post-parse stacks.
|
|
1772
|
+
*/
|
|
1773
|
+
declare function validateActionBodyWrites(stack: AnyRec$6): ActionBodyWriteFinding[];
|
|
1774
|
+
|
|
1775
|
+
type FlowNodeWriteSeverity = 'error';
|
|
1776
|
+
interface FlowNodeWriteFinding {
|
|
1777
|
+
/** Always `error` — a literal key against a literal object is a certainty (see module note). */
|
|
1778
|
+
severity: FlowNodeWriteSeverity;
|
|
1779
|
+
rule: string;
|
|
1780
|
+
/** Human-readable location, e.g. `flow "close_deal" › node "Mark won"`. */
|
|
1781
|
+
where: string;
|
|
1782
|
+
/** Config path, e.g. `flows[0].nodes[3].config.fields.stagee`. */
|
|
1783
|
+
path: string;
|
|
1784
|
+
message: string;
|
|
1785
|
+
hint: string;
|
|
1786
|
+
}
|
|
1787
|
+
declare const FLOW_NODE_WRITE_UNKNOWN_FIELD = "flow-node-write-unknown-field";
|
|
1788
|
+
/** Flow node types whose `config.fields` keys this rule resolves. */
|
|
1789
|
+
declare const FLOW_WRITE_NODE_TYPES: readonly string[];
|
|
1790
|
+
/** A `fields`-bearing node type this rule does NOT cover yet, and why. */
|
|
1791
|
+
interface FlowWriteNodeDeferral {
|
|
1792
|
+
/** The `FlowNode.type` left uncovered. */
|
|
1793
|
+
readonly type: string;
|
|
1794
|
+
/** Why it is not covered, in terms a reviewer can act on. */
|
|
1795
|
+
readonly reason: string;
|
|
1796
|
+
}
|
|
1797
|
+
/**
|
|
1798
|
+
* `fields`-bearing CRUD node types deliberately left uncovered.
|
|
1799
|
+
*
|
|
1800
|
+
* **Empty, and that is the point.** #4369 shipped `update_record` alone and
|
|
1801
|
+
* parked `create_record` here with its reason — a gating rule earning its
|
|
1802
|
+
* severity one measured surface at a time — rather than leaving the other half
|
|
1803
|
+
* as silence. #4371 measured the INSERT path (`table deal has no column named
|
|
1804
|
+
* stagee`, and the row never created at all), found it strictly worse than the
|
|
1805
|
+
* UPDATE one, and moved it across.
|
|
1806
|
+
*
|
|
1807
|
+
* The slot stays because the partition test derives the full `fields`-write-map
|
|
1808
|
+
* set from the spec's own config schemas: a node type that grows one later
|
|
1809
|
+
* belongs to neither list and fails that test until someone puts it in one.
|
|
1810
|
+
* Deleting this array would turn that forced decision back into a default.
|
|
1811
|
+
*/
|
|
1812
|
+
declare const FLOW_WRITE_NODE_TYPES_DEFERRED: readonly FlowWriteNodeDeferral[];
|
|
1813
|
+
type AnyRec$5 = Record<string, unknown>;
|
|
1814
|
+
/**
|
|
1815
|
+
* Validate flow write-node `fields` keys against the target object's declared
|
|
1816
|
+
* fields. Pure `(stack) => Finding[]` (ADR-0019); safe on pre- or post-parse
|
|
1817
|
+
* stacks.
|
|
1818
|
+
*/
|
|
1819
|
+
declare function validateFlowNodeWrites(stack: AnyRec$5): FlowNodeWriteFinding[];
|
|
1280
1820
|
|
|
1281
1821
|
/**
|
|
1282
1822
|
* [ADR-0090 D6] Access-matrix snapshot — authoring-time companion to the
|
|
@@ -1293,13 +1833,211 @@ declare function validateReferenceIntegrity(stack: Record<string, unknown>): Ref
|
|
|
1293
1833
|
* AI may draft grants freely; it cannot silently change who can do what.
|
|
1294
1834
|
*/
|
|
1295
1835
|
|
|
1296
|
-
type AnyRec = Record<string, unknown>;
|
|
1836
|
+
type AnyRec$4 = Record<string, unknown>;
|
|
1297
1837
|
/** Build the sorted access matrix for a normalized stack. */
|
|
1298
|
-
declare function buildAccessMatrix(stack: AnyRec): AccessMatrix;
|
|
1838
|
+
declare function buildAccessMatrix(stack: AnyRec$4): AccessMatrix;
|
|
1299
1839
|
/**
|
|
1300
1840
|
* Semantic diff between two matrices — human-review lines, empty = identical.
|
|
1301
1841
|
* Ordered: removals, additions, then per-entry bit/scope changes.
|
|
1302
1842
|
*/
|
|
1303
1843
|
declare function diffAccessMatrix(before: AccessMatrix, after: AccessMatrix): string[];
|
|
1304
1844
|
|
|
1305
|
-
|
|
1845
|
+
/**
|
|
1846
|
+
* Build-time lint for flow authoring ANTI-PATTERNS — metadata that is valid
|
|
1847
|
+
* (passes schema + expression checks) but is semantically a footgun at runtime.
|
|
1848
|
+
* Most are emitted as WARNINGS: they guide the author (very often an AI
|
|
1849
|
+
* generating templates) toward the robust pattern without failing the build on
|
|
1850
|
+
* a technically-legal construct.
|
|
1851
|
+
*
|
|
1852
|
+
* A finding carrying `severity: 'error'` FAILS the build. The bar is: **no
|
|
1853
|
+
* reading of the author's metadata does what it says, deterministically, on
|
|
1854
|
+
* every run.** Warning about such a shape is just a slower way of finding out.
|
|
1855
|
+
* That covers two kinds, and only these:
|
|
1856
|
+
*
|
|
1857
|
+
* - **The runtime refuses.** {@link FLOW_RUNAS_UNSCOPED} — a user-less trigger
|
|
1858
|
+
* with `runAs:'user'` has no identity to scope to, so the data operation is
|
|
1859
|
+
* refused outright (#3760).
|
|
1860
|
+
* - **The declaration is inert and the route silently differs from what is
|
|
1861
|
+
* written.** {@link FLOW_BRANCH_LABEL_UNMATCHED} — a decision computes a
|
|
1862
|
+
* branch no out-edge carries, so the branch is discarded and every out-edge
|
|
1863
|
+
* is considered instead. {@link FLOW_DEFAULT_EDGE_WITH_CONDITION} — an edge
|
|
1864
|
+
* that is both the default and conditional; the condition wins and the
|
|
1865
|
+
* marker routes nothing. Neither *fails*; both are wrong every time, and
|
|
1866
|
+
* silently, which is worse (#4414).
|
|
1867
|
+
*
|
|
1868
|
+
* The bar is deliberately about *provability*, not severity of consequence. A
|
|
1869
|
+
* shape with a legitimate reading stays a warning even when it is usually a
|
|
1870
|
+
* mistake — {@link FLOW_DECISION_UNCONDITIONAL_BRANCH} is normally a guard that
|
|
1871
|
+
* does not guard, but a decision with one guarded and one unconditional out-edge
|
|
1872
|
+
* is a legal "maybe notify, always continue" fan-out, and
|
|
1873
|
+
* {@link FLOW_MULTIPLE_DEFAULT_EDGES} can genuinely mean "when nothing matched,
|
|
1874
|
+
* do both". Failing a customer's build on a shape we cannot prove wrong is a
|
|
1875
|
+
* worse trade than letting the warning be ignored.
|
|
1876
|
+
*
|
|
1877
|
+
* #1874 — time-relative rules via record-change date-EQUALITY. A start-node
|
|
1878
|
+
* trigger condition like `end_date == daysFromNow(60)` on a `record-*` trigger
|
|
1879
|
+
* only fires if the record happens to be written on that exact day; the robust
|
|
1880
|
+
* shape is a daily SCHEDULE trigger + a range query. We flag the equality form
|
|
1881
|
+
* specifically (range operators `>=`/`<=` are not flagged — they're the building
|
|
1882
|
+
* block of the correct pattern), keeping false positives near zero.
|
|
1883
|
+
*/
|
|
1884
|
+
interface FlowLintFinding {
|
|
1885
|
+
where: string;
|
|
1886
|
+
message: string;
|
|
1887
|
+
hint: string;
|
|
1888
|
+
rule: string;
|
|
1889
|
+
/**
|
|
1890
|
+
* `'error'` FAILS the build; `'warning'` (the default when absent) prints and
|
|
1891
|
+
* continues. Most rules here flag a technically-legal footgun and stay
|
|
1892
|
+
* advisory. A rule is only promoted to `'error'` when the shape it flags is a
|
|
1893
|
+
* *guaranteed* runtime failure — then a warning would just be a slower way of
|
|
1894
|
+
* finding out (#3760).
|
|
1895
|
+
*
|
|
1896
|
+
* `os build` and `os validate` both filter on this field, so promoting a rule
|
|
1897
|
+
* gates both surfaces at once — neither can report clean while the other
|
|
1898
|
+
* rejects the same stack (#3782).
|
|
1899
|
+
*/
|
|
1900
|
+
severity?: 'error' | 'warning';
|
|
1901
|
+
}
|
|
1902
|
+
type AnyRec$3 = Record<string, unknown>;
|
|
1903
|
+
declare const FLOW_TIME_RELATIVE_ANTIPATTERN = "flow-time-relative-antipattern";
|
|
1904
|
+
declare const FLOW_DATE_EQUALITY_FILTER = "flow-date-equality-filter";
|
|
1905
|
+
declare const FLOW_PHANTOM_AGGREGATION = "flow-phantom-aggregation";
|
|
1906
|
+
declare const FLOW_DOUBLE_BRACE_INTERP = "flow-double-brace-interpolation";
|
|
1907
|
+
declare const FLOW_BARE_DOLLAR_REF = "flow-bare-dollar-reference";
|
|
1908
|
+
declare const FLOW_APPROVAL_REVISE_DEAD_END = "flow-approval-revise-dead-end";
|
|
1909
|
+
declare const FLOW_APPROVAL_REVISE_UNMARKED_BACKEDGE = "flow-approval-revise-unmarked-backedge";
|
|
1910
|
+
declare const FLOW_APPROVAL_REVISE_DISABLED = "flow-approval-revise-disabled";
|
|
1911
|
+
/**
|
|
1912
|
+
* #3760 — renamed from `flow-schedule-runas-unscoped`. The old id named the
|
|
1913
|
+
* *schedule*, which was never the boundary: the rule is about a trigger that
|
|
1914
|
+
* resolves NO USER, and a schedule is only the most obvious such trigger.
|
|
1915
|
+
*/
|
|
1916
|
+
declare const FLOW_RUNAS_UNSCOPED = "flow-runas-unscoped";
|
|
1917
|
+
declare const FLOW_ERROR_LABEL_NOT_FAULT = "flow-error-label-not-fault";
|
|
1918
|
+
/** #4414 — the four ways a decision's declared branching fails to route. */
|
|
1919
|
+
declare const FLOW_BRANCH_LABEL_UNMATCHED = "flow-branch-label-unmatched";
|
|
1920
|
+
declare const FLOW_DECISION_UNCONDITIONAL_BRANCH = "flow-decision-unconditional-branch";
|
|
1921
|
+
declare const FLOW_DEFAULT_EDGE_WITH_CONDITION = "flow-default-edge-with-condition";
|
|
1922
|
+
declare const FLOW_MULTIPLE_DEFAULT_EDGES = "flow-multiple-default-edges";
|
|
1923
|
+
/** #4414 — `config.condition` on a node whose executor never reads it. */
|
|
1924
|
+
declare const FLOW_INERT_NODE_CONDITION = "flow-inert-node-condition";
|
|
1925
|
+
/**
|
|
1926
|
+
* Lint every flow's start node for known authoring anti-patterns. Returns a
|
|
1927
|
+
* (possibly empty) list of advisory findings — never throws, never fails a build.
|
|
1928
|
+
*/
|
|
1929
|
+
declare function lintFlowPatterns(stack: AnyRec$3): FlowLintFinding[];
|
|
1930
|
+
|
|
1931
|
+
interface LivenessLintFinding {
|
|
1932
|
+
where: string;
|
|
1933
|
+
message: string;
|
|
1934
|
+
hint: string;
|
|
1935
|
+
rule: string;
|
|
1936
|
+
}
|
|
1937
|
+
declare const LIVENESS_DEAD_PROPERTY = "liveness-dead-property";
|
|
1938
|
+
declare const LIVENESS_EXPERIMENTAL_PROPERTY = "liveness-experimental-property";
|
|
1939
|
+
type AnyRec$2 = Record<string, unknown>;
|
|
1940
|
+
/**
|
|
1941
|
+
* Lint the compiled stack for authored properties the liveness ledger flags as
|
|
1942
|
+
* misleading. Advisory only — returns findings, never throws. Covers every
|
|
1943
|
+
* governed metadata type: objects (incl. `enable.*`) and their fields walk
|
|
1944
|
+
* bespoke nesting; the remaining types are flat stack collections. Container
|
|
1945
|
+
* properties fan out over arrays (each flow node, each dataset measure). The
|
|
1946
|
+
* mechanism stays ledger-driven — coverage grows by marking more entries
|
|
1947
|
+
* `authorWarn` rather than touching this code.
|
|
1948
|
+
*/
|
|
1949
|
+
declare function lintLivenessProperties(stack: AnyRec$2): LivenessLintFinding[];
|
|
1950
|
+
|
|
1951
|
+
interface AutonumberLintFinding {
|
|
1952
|
+
where: string;
|
|
1953
|
+
message: string;
|
|
1954
|
+
hint: string;
|
|
1955
|
+
rule: string;
|
|
1956
|
+
severity: 'error' | 'warning';
|
|
1957
|
+
}
|
|
1958
|
+
type AnyRec$1 = Record<string, unknown>;
|
|
1959
|
+
declare const AUTONUMBER_UNKNOWN_FIELD = "autonumber-references-unknown-field";
|
|
1960
|
+
declare const AUTONUMBER_OPTIONAL_FIELD = "autonumber-references-optional-field";
|
|
1961
|
+
declare const AUTONUMBER_SELF_REFERENCE = "autonumber-references-self";
|
|
1962
|
+
declare const AUTONUMBER_LITERAL_TOKEN = "autonumber-unrecognized-token";
|
|
1963
|
+
/**
|
|
1964
|
+
* Lint every `autonumber` field's format for unresolvable / fragile `{field}`
|
|
1965
|
+
* interpolation. Returns a (possibly empty) list of findings; never throws.
|
|
1966
|
+
*/
|
|
1967
|
+
declare function lintAutonumberFormats(stack: AnyRec$1): AutonumberLintFinding[];
|
|
1968
|
+
|
|
1969
|
+
interface ViewRefFinding {
|
|
1970
|
+
where: string;
|
|
1971
|
+
message: string;
|
|
1972
|
+
hint: string;
|
|
1973
|
+
rule: string;
|
|
1974
|
+
severity: 'error' | 'warning';
|
|
1975
|
+
}
|
|
1976
|
+
type AnyRec = Record<string, any>;
|
|
1977
|
+
declare const VIEW_KEY_COLLISION = "view-key-collision";
|
|
1978
|
+
declare const VIEW_REF_FORM_TARGET_MISSING = "view-ref-form-target-missing";
|
|
1979
|
+
declare const VIEW_REF_FORM_TARGET_KIND = "view-ref-form-target-kind";
|
|
1980
|
+
declare function lintViewRefs(stack: AnyRec): ViewRefFinding[];
|
|
1981
|
+
|
|
1982
|
+
/**
|
|
1983
|
+
* Data-model best-practice lint rules.
|
|
1984
|
+
*
|
|
1985
|
+
* These rules encode the relationship / master-detail / roll-up conventions the
|
|
1986
|
+
* platform ships (see the objectstack-data and objectstack-ui skills, ADR-0035).
|
|
1987
|
+
* They run over the normalized object set and flag anti-patterns that an
|
|
1988
|
+
* author — human OR an AI generator — commonly produces. They are intentionally
|
|
1989
|
+
* heuristic: structural problems are `error`, likely-wrong choices are
|
|
1990
|
+
* `warning`, and "you probably want this" nudges are `suggestion`. None of them
|
|
1991
|
+
* block on a judgement call.
|
|
1992
|
+
*
|
|
1993
|
+
* The same rules double as the automated rubric for the metadata-generation
|
|
1994
|
+
* eval (see `score.ts`): a generated stack scores well exactly when it is
|
|
1995
|
+
* schema-valid AND lint-clean here.
|
|
1996
|
+
*/
|
|
1997
|
+
type Severity = 'error' | 'warning' | 'suggestion';
|
|
1998
|
+
interface LintIssue {
|
|
1999
|
+
severity: Severity;
|
|
2000
|
+
rule: string;
|
|
2001
|
+
message: string;
|
|
2002
|
+
path: string;
|
|
2003
|
+
fix?: string;
|
|
2004
|
+
}
|
|
2005
|
+
declare const UNIQUE_DOUBLE_DECLARATION = "unique/double-declaration";
|
|
2006
|
+
/**
|
|
2007
|
+
* R10 — the same column carries BOTH a field-level `unique: true` and an
|
|
2008
|
+
* object-level single-column unique index (#3991).
|
|
2009
|
+
*
|
|
2010
|
+
* The two spellings are deliberately different (see `IndexSchema`): field-level
|
|
2011
|
+
* `unique: true` is tenant-scoped since #3696 — it materializes as
|
|
2012
|
+
* `(organization_id, col)`, unique *within* the tenant — while a declared index
|
|
2013
|
+
* is materialized over exactly the columns listed, i.e. platform-wide. Both are
|
|
2014
|
+
* legitimate on their own; together on one column they are never right:
|
|
2015
|
+
*
|
|
2016
|
+
* - On a tenant-scoped object they CONTRADICT. The stricter one wins
|
|
2017
|
+
* physically, so the global index enforces uniqueness and the tenant
|
|
2018
|
+
* composite becomes a constraint nothing can ever trip. One of the two
|
|
2019
|
+
* intents the author wrote is silently discarded.
|
|
2020
|
+
* - On a tenancy-less object they are exactly REDUNDANT — both describe the
|
|
2021
|
+
* same single-column unique index, under the same generated name.
|
|
2022
|
+
*
|
|
2023
|
+
* Tenancy is deliberately NOT inferred here: `organization_id` is injected by
|
|
2024
|
+
* the kernel at registration rather than authored, so an authoring-time guess
|
|
2025
|
+
* would be wrong half the time. The combination is worth flagging either way,
|
|
2026
|
+
* and the message names both readings so the author picks the one they meant.
|
|
2027
|
+
*
|
|
2028
|
+
* A field declared `unique: 'global'` is exempt: it already says
|
|
2029
|
+
* platform-wide, so the declared index restates the same intent rather than
|
|
2030
|
+
* contradicting it (still redundant, but not a silent loss of meaning).
|
|
2031
|
+
*
|
|
2032
|
+
* Advisory. The resulting stack is well-defined — the cost is an intent that
|
|
2033
|
+
* never takes effect, not a broken artifact — so this never fails a build.
|
|
2034
|
+
*/
|
|
2035
|
+
declare function lintUniqueDeclarations(objects: any[]): LintIssue[];
|
|
2036
|
+
/**
|
|
2037
|
+
* Lint the relationship / data-modeling conventions across the full object set.
|
|
2038
|
+
* Pure and deterministic — safe to call from both the `lint` command and the
|
|
2039
|
+
* metadata-generation scorer.
|
|
2040
|
+
*/
|
|
2041
|
+
declare function lintDataModel(objects: any[]): LintIssue[];
|
|
2042
|
+
|
|
2043
|
+
export { ACTION_BODY_WRITE_EXCLUSIONS, ACTION_BODY_WRITE_PATTERNS, ACTION_BODY_WRITE_PATTERN_IDS, ACTION_BODY_WRITE_UNKNOWN_FIELD, ACTION_NAME_UNDEFINED, ACTION_NO_PLACEMENT, ACTION_RECORD_WRITE_DISCARDED, ACTION_RECORD_WRITE_PATTERNS, ACTION_RECORD_WRITE_PATTERN_IDS, AGENT_AUTHORING_WITHDRAWN, AI_SKILL_SURFACE_MISMATCH, AI_SKILL_TOOL_UNRESOLVED, APPROVAL_APPROVERS_MAY_RESOLVE_EMPTY, APPROVAL_APPROVER_CROSS_ORG_UNSUPPORTED, APPROVAL_APPROVER_NOT_MEMBERSHIP_TIER, APPROVAL_APPROVER_TYPE_DEPRECATED, APPROVAL_APPROVER_TYPE_UNKNOWN, APPROVAL_DECISION_OUTPUTS_RESERVED, APPROVAL_ESCALATION_REASSIGN_NO_TARGET, APPROVAL_EXPRESSION_INVALID, APPROVAL_EXPRESSION_NO_EMPTY_POLICY, AUTONUMBER_LITERAL_TOKEN, AUTONUMBER_OPTIONAL_FIELD, AUTONUMBER_SELF_REFERENCE, AUTONUMBER_UNKNOWN_FIELD, type ActionBodyWriteExclusion, type ActionBodyWriteFinding, type ActionBodyWriteSeverity, type ActionLocationsFinding, type ActionLocationsSeverity, type ActionNameRefFinding, type ActionNameRefSeverity, type AiAgentAuthoringFinding, type AiAgentAuthoringSeverity, type AiSurfaceAffinityFinding, type AiSurfaceAffinitySeverity, type AiToolRefFinding, type AiToolRefSeverity, type ApprovalApproverFinding, type ApprovalApproverSeverity, type AutonumberLintFinding, type BodyWritePatternExclusion, CAPABILITY_REFERENCE_UNKNOWN, CHART_AXIS_NOT_SELECTED, CHART_CONFIG_MISSING, CHART_DATASET_UNKNOWN, CHART_DIMENSION_UNKNOWN, CHART_FIELD_UNKNOWN, CHART_MEASURE_UNKNOWN, type CapabilityRefFinding, type CapabilityRefSeverity, type ChartBindingFinding, type ChartBindingSeverity, DASHBOARD_ACTION_ROUTE_UNRESOLVED, DASHBOARD_ACTION_TARGET_UNDEFINED, DASHBOARD_FILTER_FIELD_UNKNOWN, type DashboardActionRefFinding, type DashboardActionRefSeverity, type ExprIssue, type ExtractedHookBodyWrite, type ExtractedHookBodyWriteSet, FIELD_GROUP_EMPTY, FIELD_GROUP_UNDECLARED, FILTER_TOKEN_UNKNOWN, FLOW_APPROVAL_REVISE_DEAD_END, FLOW_APPROVAL_REVISE_DISABLED, FLOW_APPROVAL_REVISE_UNMARKED_BACKEDGE, FLOW_BARE_DOLLAR_REF, FLOW_BRANCH_LABEL_UNMATCHED, FLOW_DATE_EQUALITY_FILTER, FLOW_DECISION_UNCONDITIONAL_BRANCH, FLOW_DEFAULT_EDGE_WITH_CONDITION, FLOW_DOUBLE_BRACE_INTERP, FLOW_DRAFT_STATUS_AMBIGUOUS, FLOW_ERROR_LABEL_NOT_FAULT, FLOW_INERT_NODE_CONDITION, FLOW_MULTIPLE_DEFAULT_EDGES, FLOW_NODE_WRITE_UNKNOWN_FIELD, FLOW_PHANTOM_AGGREGATION, FLOW_RUNAS_UNSCOPED, FLOW_TEMPLATE_LOOKUP_TRAVERSAL, FLOW_TEMPLATE_UNKNOWN_FIELD, FLOW_TIME_RELATIVE_ANTIPATTERN, FLOW_TRIGGER_UNKNOWN_OBJECT, FLOW_UPDATE_READONLY_FIELD, FLOW_UPDATE_READONLY_WHEN_FIELD, FLOW_WRITE_NODE_TYPES, FLOW_WRITE_NODE_TYPES_DEFERRED, FORM_COLSPAN_ABSOLUTE, FORM_FIELD_UNKNOWN, type FilterTokenFinding, type FilterTokenSeverity, type FlowLintFinding, type FlowNodeWriteFinding, type FlowNodeWriteSeverity, type FlowTemplatePathFinding, type FlowTemplatePathSeverity, type FlowTriggerReadinessFinding, type FlowTriggerReadinessSeverity, type FlowWriteNodeDeferral, type FormLayoutFinding, type FormLayoutSeverity, type FunctionalCompletenessFinding, type FunctionalCompletenessSeverity, HOOK_BODY_WRITE_EXCLUSIONS, HOOK_BODY_WRITE_PATTERNS, HOOK_BODY_WRITE_PATTERN_IDS, HOOK_BODY_WRITE_UNKNOWN_FIELD, type HookBodyWriteFinding, type HookBodyWritePattern, type HookBodyWriteSeverity, type JsxPageFinding, type JsxPageSeverity, LIST_VIEW_FILTERS_IN_VIEWS_MODE, LIVENESS_DEAD_PROPERTY, LIVENESS_EXPERIMENTAL_PROPERTY, type LintIssue, type ListViewModeFinding, type ListViewModeSeverity, type LivenessLintFinding, MEASURE_AGGREGATE_INCOHERENT, NAV_OBJECT_UNGRANTED, NAV_TARGET_UNRESOLVED, NULL_GUARD_HINT, type NavAccessFinding, type NavAccessSeverity, type NavTargetRefFinding, type NavTargetRefSeverity, type NullGuardFinding, type NullGuardOptions, OBJECT_REFERENCE_UNKNOWN, OBJECT_REFERENCE_UNREGISTERED_PLATFORM, ORG_AXIS_CROSS_ORG_BU_GRANT, ORG_AXIS_PERMISSION_INHERITANCE, type ObjectRefFinding, type ObjectRefSeverity, type OrgAxisFinding, type OrgAxisSeverity, PAGE_FIELD_UNKNOWN, PAGE_SOURCE_CLASSNAME, type PageFieldFinding, type PageFieldSeverity, REACT_BLOCK_NEEDS_RECORD_CONTEXT, REACT_CHART_AGGREGATE_INVALID, REACT_CHART_AXIS_UNKNOWN, REACT_CHART_FIELD_UNKNOWN, REFERENCE_INTEGRITY_RULES, type ReactPageFinding, type ReactPageSeverity, type ReactPropFinding, type ReactPropSeverity, type ReadonlyFlowWriteFinding, type ReadonlyFlowWriteSeverity, type RecordTitleFinding, type RecordTitleSeverity, type ReferenceIntegrityFinding, type ReferenceIntegrityRule, type ReferenceIntegritySeverity, SEARCHABLE_FIELD_UNKNOWN, SEARCHABLE_FIELD_UNSEARCHABLE, SECURITY_ANCHOR_HIGH_PRIVILEGE, SECURITY_BOOK_AUDIENCE_UNKNOWN_SET, SECURITY_DELEGATION_MISSING_REASON, SECURITY_EXTERNAL_WIDER, SECURITY_GRANT_EXPIRED_AT_AUTHORING, SECURITY_MASTER_DETAIL_UNGRANTED, SECURITY_OWD_ALIAS, SECURITY_OWD_UNSET, SECURITY_PRIVATE_NO_READSCOPE, SECURITY_ROLE_WORD, SECURITY_WILDCARD_VAMA, SEED_INSERT_MODE_DUPLICATES_ON_REPLAY, SEED_VALUE_OUTSIDE_STATE_MACHINE, SEMANTIC_ROLE_FIELD_UNKNOWN, STYLE_CLASSNAME_TAILWIND, STYLE_NODE_MISSING_ID, STYLE_RESPONSIVE_NO_BASE, STYLE_UNKNOWN_CSS_PROPERTY, STYLE_UNKNOWN_TOKEN, type SearchableFieldFinding, type SearchableFieldRole, type SearchableFieldSeverity, type SecurityFinding, type SecuritySeverity, type SeedReplaySafetyFinding, type SeedReplaySafetySeverity, type SeedStateMachineFinding, type SeedStateMachineSeverity, type SemanticRoleFinding, type SemanticRoleSeverity, type Severity, type SourceStyleFinding, type SourceStyleSeverity, type StyleFinding, type StyleSeverity, TABLE_COUNT_ONLY, TITLE_FORMAT_RETIRED, TITLE_UNRESOLVABLE, TRANSLATION_OPTION_KEY_UNKNOWN, TRANSLATION_TARGET_UNKNOWN, type TranslationRefFinding, type TranslationRefSeverity, UNIQUE_DOUBLE_DECLARATION, VIEW_CONTAINER_SHAPE, VIEW_KEY_COLLISION, VIEW_REF_FORM_TARGET_KIND, VIEW_REF_FORM_TARGET_MISSING, VISIBILITY_ALIAS_DEPRECATED, VISIBILITY_ROOT_MISLAYERED, type ViewContainerFinding, type ViewContainerSeverity, type ViewRefFinding, type VisibilityFinding, type VisibilityLayer, type VisibilityOptions, type VisibilitySeverity, WIDGET_DATASET_UNKNOWN, WIDGET_DIMENSION_UNKNOWN, WIDGET_MEASURE_UNKNOWN, type WidgetBindingFinding, type WidgetBindingSeverity, buildAccessMatrix, diffAccessMatrix, extractHookBodyWriteSet, extractHookBodyWrites, findUnguardedNullableOperands, lintAutonumberFormats, lintDataModel, lintFlowPatterns, lintLivenessProperties, lintUniqueDeclarations, lintViewRefs, nullGuardMessage, validateActionBodyWrites, validateActionLocations, validateActionNameRefs, validateAiAgentAuthoring, validateAiSurfaceAffinity, validateAiToolReferences, validateApprovalApprovers, validateCapabilityReferences, validateChartBindings, validateDashboardActionRefs, validateFilterTokens, validateFlowNodeWrites, validateFlowTemplatePaths, validateFlowTriggerReadiness, validateFormLayout, validateFunctionalCompleteness, validateHookBodyWrites, validateJsxPages, validateListViewMode, validateNavAccess, validateNavTargetRefs, validateObjectReferences, validateOrgAxisRedLines, validatePageFieldBindings, validatePageSourceStyling, validateReactPageProps, validateReactPages, validateReadonlyFlowWrites, validateRecordTitle, validateReferenceIntegrity, validateResponsiveStyles, validateSearchableFields, validateSecurityPosture, validateSeedReplaySafety, validateSeedStateMachine, validateSemanticRoles, validateStackExpressions, validateTranslationReferences, validateViewContainers, validateVisibilityPredicates, validateWidgetBindings };
|