@objectstack/lint 14.8.0 → 15.0.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 +28 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -7
- package/dist/index.d.ts +29 -7
- package/dist/index.js +28 -11
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -359,11 +359,16 @@ declare function validateFormLayout(stack: AnyRec$5): FormLayoutFinding[];
|
|
|
359
359
|
*
|
|
360
360
|
* - `visibility-alias-deprecated` — a `visibleOn` / `visibility` key in authored
|
|
361
361
|
* source. Autofix intent: rename the key to `visibleWhen` (same value).
|
|
362
|
-
* - `visibility-root-mislayered` — a
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
*
|
|
362
|
+
* - `visibility-root-mislayered` — a visibility predicate whose binding root does
|
|
363
|
+
* not match its layer (ADR-0089 D3, §Context). The check is **bidirectional**:
|
|
364
|
+
* - **runtime** view/page surfaces (`*.view.ts` / `*.page.ts`) bind
|
|
365
|
+
* `record` + `current_user` (pages also expose `page.<var>`), so a `data.`-rooted
|
|
366
|
+
* predicate here is a wrong-layer paste that silently never matches; and
|
|
367
|
+
* - **metadata-editing** forms (`*.form.ts` — the row under edit) bind `data`, so
|
|
368
|
+
* a `record.`-rooted predicate there is the same bug in the other direction.
|
|
369
|
+
* The layer is supplied by the caller (`opts.layer`, default `'runtime'`): the
|
|
370
|
+
* app-lint path (`os validate` / `compile`) always lints runtime surfaces, while a
|
|
371
|
+
* file-aware caller linting a `*.form.ts` passes `layer: 'metadata'`.
|
|
367
372
|
*
|
|
368
373
|
* Scope: `views` (form `sections` / legacy `groups`, and their `fields`) and
|
|
369
374
|
* `pages` (`regions[].components[]`). Data-field `visibleWhen` is already covered
|
|
@@ -372,6 +377,17 @@ declare function validateFormLayout(stack: AnyRec$5): FormLayoutFinding[];
|
|
|
372
377
|
declare const VISIBILITY_ALIAS_DEPRECATED = "visibility-alias-deprecated";
|
|
373
378
|
declare const VISIBILITY_ROOT_MISLAYERED = "visibility-root-mislayered";
|
|
374
379
|
type VisibilitySeverity = 'error' | 'warning';
|
|
380
|
+
/**
|
|
381
|
+
* Which binding environment the linted surface belongs to (ADR-0089 §Context):
|
|
382
|
+
* - `runtime` — `*.view.ts` / `*.page.ts`; binds `record` + `current_user` (+ `page`).
|
|
383
|
+
* - `metadata` — `*.form.ts` metadata-editing forms; binds `data` (the row under edit).
|
|
384
|
+
*/
|
|
385
|
+
type VisibilityLayer = 'runtime' | 'metadata';
|
|
386
|
+
/** Options for {@link validateVisibilityPredicates}. */
|
|
387
|
+
interface VisibilityOptions {
|
|
388
|
+
/** Binding layer of the surface being linted. Defaults to `'runtime'`. */
|
|
389
|
+
layer?: VisibilityLayer;
|
|
390
|
+
}
|
|
375
391
|
interface VisibilityFinding {
|
|
376
392
|
/** Always `warning` today — both rules are advisory (see module note). */
|
|
377
393
|
severity: VisibilitySeverity;
|
|
@@ -394,8 +410,14 @@ type AnyRec$4 = Record<string, unknown>;
|
|
|
394
410
|
* `visibleOn` / `visibility` aliases before the schema folds them into
|
|
395
411
|
* `visibleWhen`. Returns findings (empty = clean); all advisory (`warning`) —
|
|
396
412
|
* the caller must never fail the build on these alone.
|
|
413
|
+
*
|
|
414
|
+
* The binding-root check is layer-directional (ADR-0089 D3): pass
|
|
415
|
+
* `opts.layer = 'metadata'` when linting a `*.form.ts` metadata-editing form (so a
|
|
416
|
+
* `record.`-rooted predicate is flagged), or leave it at the `'runtime'` default for
|
|
417
|
+
* `*.view.ts` / `*.page.ts` surfaces (so a `data.`-rooted predicate is flagged). The
|
|
418
|
+
* alias-deprecated check is layer-agnostic.
|
|
397
419
|
*/
|
|
398
|
-
declare function validateVisibilityPredicates(stack: AnyRec$4): VisibilityFinding[];
|
|
420
|
+
declare function validateVisibilityPredicates(stack: AnyRec$4, opts?: VisibilityOptions): VisibilityFinding[];
|
|
399
421
|
|
|
400
422
|
declare const CAPABILITY_REFERENCE_UNKNOWN = "capability-reference-unknown";
|
|
401
423
|
type CapabilityRefSeverity = 'error' | 'warning';
|
|
@@ -505,4 +527,4 @@ declare function buildAccessMatrix(stack: AnyRec): AccessMatrix;
|
|
|
505
527
|
*/
|
|
506
528
|
declare function diffAccessMatrix(before: AccessMatrix, after: AccessMatrix): string[];
|
|
507
529
|
|
|
508
|
-
export { APPROVAL_APPROVER_TYPE_UNKNOWN, APPROVAL_ESCALATION_REASSIGN_NO_TARGET, APPROVAL_ROLE_NOT_MEMBERSHIP_TIER, type ApprovalApproverFinding, type ApprovalApproverSeverity, CAPABILITY_REFERENCE_UNKNOWN, CHART_CONFIG_MISSING, CHART_FIELD_UNKNOWN, type CapabilityRefFinding, type CapabilityRefSeverity, type ExprIssue, FIELD_GROUP_EMPTY, FIELD_GROUP_UNDECLARED, FORM_COLSPAN_ABSOLUTE, FORM_FIELD_UNKNOWN, type FormLayoutFinding, type FormLayoutSeverity, type JsxPageFinding, type JsxPageSeverity, LIST_VIEW_FILTERS_IN_VIEWS_MODE, type ListViewModeFinding, type ListViewModeSeverity, MEASURE_AGGREGATE_INCOHERENT, PAGE_SOURCE_CLASSNAME, type ReactPageFinding, type ReactPageSeverity, type ReactPropFinding, type ReactPropSeverity, type RecordTitleFinding, type RecordTitleSeverity, 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, SEMANTIC_ROLE_FIELD_UNKNOWN, STYLE_CLASSNAME_TAILWIND, STYLE_NODE_MISSING_ID, STYLE_RESPONSIVE_NO_BASE, STYLE_UNKNOWN_CSS_PROPERTY, STYLE_UNKNOWN_TOKEN, type SecurityFinding, type SecuritySeverity, type SemanticRoleFinding, type SemanticRoleSeverity, type SourceStyleFinding, type SourceStyleSeverity, type StyleFinding, type StyleSeverity, TABLE_COUNT_ONLY, TITLE_FORMAT_RETIRED, TITLE_UNRESOLVABLE, VISIBILITY_ALIAS_DEPRECATED, VISIBILITY_ROOT_MISLAYERED, type VisibilityFinding, type VisibilitySeverity, WIDGET_DATASET_UNKNOWN, WIDGET_DIMENSION_UNKNOWN, WIDGET_MEASURE_UNKNOWN, type WidgetBindingFinding, type WidgetBindingSeverity, buildAccessMatrix, diffAccessMatrix, validateApprovalApprovers, validateCapabilityReferences, validateFormLayout, validateJsxPages, validateListViewMode, validatePageSourceStyling, validateReactPageProps, validateReactPages, validateRecordTitle, validateResponsiveStyles, validateSecurityPosture, validateSemanticRoles, validateStackExpressions, validateVisibilityPredicates, validateWidgetBindings };
|
|
530
|
+
export { APPROVAL_APPROVER_TYPE_UNKNOWN, APPROVAL_ESCALATION_REASSIGN_NO_TARGET, APPROVAL_ROLE_NOT_MEMBERSHIP_TIER, type ApprovalApproverFinding, type ApprovalApproverSeverity, CAPABILITY_REFERENCE_UNKNOWN, CHART_CONFIG_MISSING, CHART_FIELD_UNKNOWN, type CapabilityRefFinding, type CapabilityRefSeverity, type ExprIssue, FIELD_GROUP_EMPTY, FIELD_GROUP_UNDECLARED, FORM_COLSPAN_ABSOLUTE, FORM_FIELD_UNKNOWN, type FormLayoutFinding, type FormLayoutSeverity, type JsxPageFinding, type JsxPageSeverity, LIST_VIEW_FILTERS_IN_VIEWS_MODE, type ListViewModeFinding, type ListViewModeSeverity, MEASURE_AGGREGATE_INCOHERENT, PAGE_SOURCE_CLASSNAME, type ReactPageFinding, type ReactPageSeverity, type ReactPropFinding, type ReactPropSeverity, type RecordTitleFinding, type RecordTitleSeverity, 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, SEMANTIC_ROLE_FIELD_UNKNOWN, STYLE_CLASSNAME_TAILWIND, STYLE_NODE_MISSING_ID, STYLE_RESPONSIVE_NO_BASE, STYLE_UNKNOWN_CSS_PROPERTY, STYLE_UNKNOWN_TOKEN, type SecurityFinding, type SecuritySeverity, type SemanticRoleFinding, type SemanticRoleSeverity, type SourceStyleFinding, type SourceStyleSeverity, type StyleFinding, type StyleSeverity, TABLE_COUNT_ONLY, TITLE_FORMAT_RETIRED, TITLE_UNRESOLVABLE, VISIBILITY_ALIAS_DEPRECATED, VISIBILITY_ROOT_MISLAYERED, type VisibilityFinding, type VisibilityLayer, type VisibilityOptions, type VisibilitySeverity, WIDGET_DATASET_UNKNOWN, WIDGET_DIMENSION_UNKNOWN, WIDGET_MEASURE_UNKNOWN, type WidgetBindingFinding, type WidgetBindingSeverity, buildAccessMatrix, diffAccessMatrix, validateApprovalApprovers, validateCapabilityReferences, validateFormLayout, validateJsxPages, validateListViewMode, validatePageSourceStyling, validateReactPageProps, validateReactPages, validateRecordTitle, validateResponsiveStyles, validateSecurityPosture, validateSemanticRoles, validateStackExpressions, validateVisibilityPredicates, validateWidgetBindings };
|
package/dist/index.d.ts
CHANGED
|
@@ -359,11 +359,16 @@ declare function validateFormLayout(stack: AnyRec$5): FormLayoutFinding[];
|
|
|
359
359
|
*
|
|
360
360
|
* - `visibility-alias-deprecated` — a `visibleOn` / `visibility` key in authored
|
|
361
361
|
* source. Autofix intent: rename the key to `visibleWhen` (same value).
|
|
362
|
-
* - `visibility-root-mislayered` — a
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
*
|
|
362
|
+
* - `visibility-root-mislayered` — a visibility predicate whose binding root does
|
|
363
|
+
* not match its layer (ADR-0089 D3, §Context). The check is **bidirectional**:
|
|
364
|
+
* - **runtime** view/page surfaces (`*.view.ts` / `*.page.ts`) bind
|
|
365
|
+
* `record` + `current_user` (pages also expose `page.<var>`), so a `data.`-rooted
|
|
366
|
+
* predicate here is a wrong-layer paste that silently never matches; and
|
|
367
|
+
* - **metadata-editing** forms (`*.form.ts` — the row under edit) bind `data`, so
|
|
368
|
+
* a `record.`-rooted predicate there is the same bug in the other direction.
|
|
369
|
+
* The layer is supplied by the caller (`opts.layer`, default `'runtime'`): the
|
|
370
|
+
* app-lint path (`os validate` / `compile`) always lints runtime surfaces, while a
|
|
371
|
+
* file-aware caller linting a `*.form.ts` passes `layer: 'metadata'`.
|
|
367
372
|
*
|
|
368
373
|
* Scope: `views` (form `sections` / legacy `groups`, and their `fields`) and
|
|
369
374
|
* `pages` (`regions[].components[]`). Data-field `visibleWhen` is already covered
|
|
@@ -372,6 +377,17 @@ declare function validateFormLayout(stack: AnyRec$5): FormLayoutFinding[];
|
|
|
372
377
|
declare const VISIBILITY_ALIAS_DEPRECATED = "visibility-alias-deprecated";
|
|
373
378
|
declare const VISIBILITY_ROOT_MISLAYERED = "visibility-root-mislayered";
|
|
374
379
|
type VisibilitySeverity = 'error' | 'warning';
|
|
380
|
+
/**
|
|
381
|
+
* Which binding environment the linted surface belongs to (ADR-0089 §Context):
|
|
382
|
+
* - `runtime` — `*.view.ts` / `*.page.ts`; binds `record` + `current_user` (+ `page`).
|
|
383
|
+
* - `metadata` — `*.form.ts` metadata-editing forms; binds `data` (the row under edit).
|
|
384
|
+
*/
|
|
385
|
+
type VisibilityLayer = 'runtime' | 'metadata';
|
|
386
|
+
/** Options for {@link validateVisibilityPredicates}. */
|
|
387
|
+
interface VisibilityOptions {
|
|
388
|
+
/** Binding layer of the surface being linted. Defaults to `'runtime'`. */
|
|
389
|
+
layer?: VisibilityLayer;
|
|
390
|
+
}
|
|
375
391
|
interface VisibilityFinding {
|
|
376
392
|
/** Always `warning` today — both rules are advisory (see module note). */
|
|
377
393
|
severity: VisibilitySeverity;
|
|
@@ -394,8 +410,14 @@ type AnyRec$4 = Record<string, unknown>;
|
|
|
394
410
|
* `visibleOn` / `visibility` aliases before the schema folds them into
|
|
395
411
|
* `visibleWhen`. Returns findings (empty = clean); all advisory (`warning`) —
|
|
396
412
|
* the caller must never fail the build on these alone.
|
|
413
|
+
*
|
|
414
|
+
* The binding-root check is layer-directional (ADR-0089 D3): pass
|
|
415
|
+
* `opts.layer = 'metadata'` when linting a `*.form.ts` metadata-editing form (so a
|
|
416
|
+
* `record.`-rooted predicate is flagged), or leave it at the `'runtime'` default for
|
|
417
|
+
* `*.view.ts` / `*.page.ts` surfaces (so a `data.`-rooted predicate is flagged). The
|
|
418
|
+
* alias-deprecated check is layer-agnostic.
|
|
397
419
|
*/
|
|
398
|
-
declare function validateVisibilityPredicates(stack: AnyRec$4): VisibilityFinding[];
|
|
420
|
+
declare function validateVisibilityPredicates(stack: AnyRec$4, opts?: VisibilityOptions): VisibilityFinding[];
|
|
399
421
|
|
|
400
422
|
declare const CAPABILITY_REFERENCE_UNKNOWN = "capability-reference-unknown";
|
|
401
423
|
type CapabilityRefSeverity = 'error' | 'warning';
|
|
@@ -505,4 +527,4 @@ declare function buildAccessMatrix(stack: AnyRec): AccessMatrix;
|
|
|
505
527
|
*/
|
|
506
528
|
declare function diffAccessMatrix(before: AccessMatrix, after: AccessMatrix): string[];
|
|
507
529
|
|
|
508
|
-
export { APPROVAL_APPROVER_TYPE_UNKNOWN, APPROVAL_ESCALATION_REASSIGN_NO_TARGET, APPROVAL_ROLE_NOT_MEMBERSHIP_TIER, type ApprovalApproverFinding, type ApprovalApproverSeverity, CAPABILITY_REFERENCE_UNKNOWN, CHART_CONFIG_MISSING, CHART_FIELD_UNKNOWN, type CapabilityRefFinding, type CapabilityRefSeverity, type ExprIssue, FIELD_GROUP_EMPTY, FIELD_GROUP_UNDECLARED, FORM_COLSPAN_ABSOLUTE, FORM_FIELD_UNKNOWN, type FormLayoutFinding, type FormLayoutSeverity, type JsxPageFinding, type JsxPageSeverity, LIST_VIEW_FILTERS_IN_VIEWS_MODE, type ListViewModeFinding, type ListViewModeSeverity, MEASURE_AGGREGATE_INCOHERENT, PAGE_SOURCE_CLASSNAME, type ReactPageFinding, type ReactPageSeverity, type ReactPropFinding, type ReactPropSeverity, type RecordTitleFinding, type RecordTitleSeverity, 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, SEMANTIC_ROLE_FIELD_UNKNOWN, STYLE_CLASSNAME_TAILWIND, STYLE_NODE_MISSING_ID, STYLE_RESPONSIVE_NO_BASE, STYLE_UNKNOWN_CSS_PROPERTY, STYLE_UNKNOWN_TOKEN, type SecurityFinding, type SecuritySeverity, type SemanticRoleFinding, type SemanticRoleSeverity, type SourceStyleFinding, type SourceStyleSeverity, type StyleFinding, type StyleSeverity, TABLE_COUNT_ONLY, TITLE_FORMAT_RETIRED, TITLE_UNRESOLVABLE, VISIBILITY_ALIAS_DEPRECATED, VISIBILITY_ROOT_MISLAYERED, type VisibilityFinding, type VisibilitySeverity, WIDGET_DATASET_UNKNOWN, WIDGET_DIMENSION_UNKNOWN, WIDGET_MEASURE_UNKNOWN, type WidgetBindingFinding, type WidgetBindingSeverity, buildAccessMatrix, diffAccessMatrix, validateApprovalApprovers, validateCapabilityReferences, validateFormLayout, validateJsxPages, validateListViewMode, validatePageSourceStyling, validateReactPageProps, validateReactPages, validateRecordTitle, validateResponsiveStyles, validateSecurityPosture, validateSemanticRoles, validateStackExpressions, validateVisibilityPredicates, validateWidgetBindings };
|
|
530
|
+
export { APPROVAL_APPROVER_TYPE_UNKNOWN, APPROVAL_ESCALATION_REASSIGN_NO_TARGET, APPROVAL_ROLE_NOT_MEMBERSHIP_TIER, type ApprovalApproverFinding, type ApprovalApproverSeverity, CAPABILITY_REFERENCE_UNKNOWN, CHART_CONFIG_MISSING, CHART_FIELD_UNKNOWN, type CapabilityRefFinding, type CapabilityRefSeverity, type ExprIssue, FIELD_GROUP_EMPTY, FIELD_GROUP_UNDECLARED, FORM_COLSPAN_ABSOLUTE, FORM_FIELD_UNKNOWN, type FormLayoutFinding, type FormLayoutSeverity, type JsxPageFinding, type JsxPageSeverity, LIST_VIEW_FILTERS_IN_VIEWS_MODE, type ListViewModeFinding, type ListViewModeSeverity, MEASURE_AGGREGATE_INCOHERENT, PAGE_SOURCE_CLASSNAME, type ReactPageFinding, type ReactPageSeverity, type ReactPropFinding, type ReactPropSeverity, type RecordTitleFinding, type RecordTitleSeverity, 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, SEMANTIC_ROLE_FIELD_UNKNOWN, STYLE_CLASSNAME_TAILWIND, STYLE_NODE_MISSING_ID, STYLE_RESPONSIVE_NO_BASE, STYLE_UNKNOWN_CSS_PROPERTY, STYLE_UNKNOWN_TOKEN, type SecurityFinding, type SecuritySeverity, type SemanticRoleFinding, type SemanticRoleSeverity, type SourceStyleFinding, type SourceStyleSeverity, type StyleFinding, type StyleSeverity, TABLE_COUNT_ONLY, TITLE_FORMAT_RETIRED, TITLE_UNRESOLVABLE, VISIBILITY_ALIAS_DEPRECATED, VISIBILITY_ROOT_MISLAYERED, type VisibilityFinding, type VisibilityLayer, type VisibilityOptions, type VisibilitySeverity, WIDGET_DATASET_UNKNOWN, WIDGET_DIMENSION_UNKNOWN, WIDGET_MEASURE_UNKNOWN, type WidgetBindingFinding, type WidgetBindingSeverity, buildAccessMatrix, diffAccessMatrix, validateApprovalApprovers, validateCapabilityReferences, validateFormLayout, validateJsxPages, validateListViewMode, validatePageSourceStyling, validateReactPageProps, validateReactPages, validateRecordTitle, validateResponsiveStyles, validateSecurityPosture, validateSemanticRoles, validateStackExpressions, validateVisibilityPredicates, validateWidgetBindings };
|
package/dist/index.js
CHANGED
|
@@ -1212,10 +1212,22 @@ function predicateSource(v) {
|
|
|
1212
1212
|
}
|
|
1213
1213
|
return void 0;
|
|
1214
1214
|
}
|
|
1215
|
-
function
|
|
1216
|
-
return
|
|
1215
|
+
function usesRoot(source, root) {
|
|
1216
|
+
return new RegExp(`(^|[^.\\w$])${root}\\.\\w`).test(source);
|
|
1217
1217
|
}
|
|
1218
|
-
|
|
1218
|
+
var MISLAYER_BY_LAYER = {
|
|
1219
|
+
runtime: {
|
|
1220
|
+
forbiddenRoot: "data",
|
|
1221
|
+
message: "visibility predicate is rooted at `data.` \u2014 that is the metadata-editing-form root (a `*.form.ts` row under edit), not a runtime surface. A runtime view/page predicate that binds `data.` never matches and the element renders unconditionally (ADR-0089).",
|
|
1222
|
+
hint: "Runtime record surfaces bind `record` + `current_user` (pages also expose `page.<var>`). Use e.g. `record.status == 'open'` instead of `data.status == 'open'`."
|
|
1223
|
+
},
|
|
1224
|
+
metadata: {
|
|
1225
|
+
forbiddenRoot: "record",
|
|
1226
|
+
message: "visibility predicate is rooted at `record.` \u2014 that is the runtime record-surface root (a `*.view.ts` / `*.page.ts` live record), not a metadata-editing form. A `*.form.ts` predicate that binds `record.` never matches and the element renders unconditionally (ADR-0089).",
|
|
1227
|
+
hint: "Metadata-editing forms bind `data` (the row under edit). Use e.g. `data.type == 'grid'` instead of `record.type == 'grid'`."
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
1230
|
+
function checkElement(el, where, path, layer, findings) {
|
|
1219
1231
|
for (const alias of ALIASES) {
|
|
1220
1232
|
if (el[alias] !== void 0) {
|
|
1221
1233
|
findings.push({
|
|
@@ -1230,21 +1242,23 @@ function checkElement(el, where, path, findings) {
|
|
|
1230
1242
|
}
|
|
1231
1243
|
const raw = el[CANONICAL] ?? el.visibleOn ?? el.visibility;
|
|
1232
1244
|
const source = predicateSource(raw);
|
|
1233
|
-
|
|
1245
|
+
const rule = MISLAYER_BY_LAYER[layer];
|
|
1246
|
+
if (source && usesRoot(source, rule.forbiddenRoot)) {
|
|
1234
1247
|
findings.push({
|
|
1235
1248
|
severity: "warning",
|
|
1236
1249
|
rule: VISIBILITY_ROOT_MISLAYERED,
|
|
1237
1250
|
where,
|
|
1238
1251
|
path,
|
|
1239
|
-
message:
|
|
1240
|
-
hint:
|
|
1252
|
+
message: rule.message,
|
|
1253
|
+
hint: rule.hint
|
|
1241
1254
|
});
|
|
1242
1255
|
}
|
|
1243
1256
|
}
|
|
1244
1257
|
function isFieldObject(entry) {
|
|
1245
1258
|
return !!entry && typeof entry === "object" && !Array.isArray(entry);
|
|
1246
1259
|
}
|
|
1247
|
-
function validateVisibilityPredicates(stack) {
|
|
1260
|
+
function validateVisibilityPredicates(stack, opts = {}) {
|
|
1261
|
+
const layer = opts.layer ?? "runtime";
|
|
1248
1262
|
const findings = [];
|
|
1249
1263
|
const views = asArray12(stack.views);
|
|
1250
1264
|
for (let i = 0; i < views.length; i++) {
|
|
@@ -1258,12 +1272,12 @@ function validateVisibilityPredicates(stack) {
|
|
|
1258
1272
|
const sec = sections[s];
|
|
1259
1273
|
if (!sec || typeof sec !== "object") continue;
|
|
1260
1274
|
const secPath = `views[${i}].${bucket}[${s}]`;
|
|
1261
|
-
checkElement(sec, where, secPath, findings);
|
|
1275
|
+
checkElement(sec, where, secPath, layer, findings);
|
|
1262
1276
|
const secFields = Array.isArray(sec.fields) ? sec.fields : [];
|
|
1263
1277
|
for (let f = 0; f < secFields.length; f++) {
|
|
1264
1278
|
const entry = secFields[f];
|
|
1265
1279
|
if (isFieldObject(entry)) {
|
|
1266
|
-
checkElement(entry, where, `${secPath}.fields[${f}]`, findings);
|
|
1280
|
+
checkElement(entry, where, `${secPath}.fields[${f}]`, layer, findings);
|
|
1267
1281
|
}
|
|
1268
1282
|
}
|
|
1269
1283
|
}
|
|
@@ -1282,7 +1296,7 @@ function validateVisibilityPredicates(stack) {
|
|
|
1282
1296
|
for (let c = 0; c < components.length; c++) {
|
|
1283
1297
|
const comp = components[c];
|
|
1284
1298
|
if (comp && typeof comp === "object") {
|
|
1285
|
-
checkElement(comp, where, `pages[${i}].regions[${r}].components[${c}]`, findings);
|
|
1299
|
+
checkElement(comp, where, `pages[${i}].regions[${r}].components[${c}]`, layer, findings);
|
|
1286
1300
|
}
|
|
1287
1301
|
}
|
|
1288
1302
|
}
|
|
@@ -1318,6 +1332,9 @@ function validateCapabilityReferences(stack) {
|
|
|
1318
1332
|
const findings = [];
|
|
1319
1333
|
if (!stack || typeof stack !== "object") return findings;
|
|
1320
1334
|
const known = new Set(PLATFORM_CAPABILITY_NAMES);
|
|
1335
|
+
for (const cap of asArray13(stack.capabilities)) {
|
|
1336
|
+
if (typeof cap.name === "string" && cap.name.length > 0) known.add(cap.name);
|
|
1337
|
+
}
|
|
1321
1338
|
for (const ps of asArray13(stack.permissions)) {
|
|
1322
1339
|
for (const cap of asCapArray(ps.systemPermissions)) known.add(cap);
|
|
1323
1340
|
}
|
|
@@ -1328,7 +1345,7 @@ function validateCapabilityReferences(stack) {
|
|
|
1328
1345
|
if (typeof name === "string" && name.length > 0) known.add(name);
|
|
1329
1346
|
}
|
|
1330
1347
|
}
|
|
1331
|
-
const hint = "Fix the capability name, declare it on a permission set\u2019s systemPermissions, ship a sys_capability seed row, or ignore this if the capability is provided by another installed package (references fail closed at runtime).";
|
|
1348
|
+
const hint = "Fix the capability name, define it with defineCapability (stack.capabilities), declare it on a permission set\u2019s systemPermissions, ship a sys_capability seed row, or ignore this if the capability is provided by another installed package (references fail closed at runtime).";
|
|
1332
1349
|
const flag = (cap, where, path) => {
|
|
1333
1350
|
if (known.has(cap)) return;
|
|
1334
1351
|
findings.push({
|