CRUDUI PHP API

ForbiddenScan
in package

FinalYes

Recursive forbidden meta-key scan (SPEC §6) — the runtime half of the global rejection that the meta-schema's `propertyNames` enforces statically.

Byte-for-byte port of validator-ts/src/forbidden-scan.ts.

R1: the types/parser PRESERVE every key (round-trip), so blocking forbidden meta keys is the VALIDATION layer's job, not the model's. The direct audit found that the Go/Rust typed models only rejected forbidden keys at the top level and one level under open buckets — a deeply nested meta key (validate.required.if, options.x.display_switch, …) leaked through. This scan closes that leak: it walks the COMPOSED single spec (after $ref/$patch expansion and x-strip) to ARBITRARY depth and rejects a forbidden key found at ANY depth — including one level under a slot/bucket body.

Placement (SPEC §2 pipeline): this runs in the spec LOAD path, immediately after compose expansion and before validation entry. A hit is therefore a LOAD failure (ComposeLoadError, code FORBIDDEN_META_KEY) — the spec never comes into existence — never a valid:false validation result.

Forbidden set (SPEC §6): the enumerated FORBIDDEN_META_KEYS (condition-only / retired / magic-symbol meta keys) PLUS the x{key} comment family (any x-prefixed key). $ref/$patch are NOT forbidden — compose already consumed them, so they do not survive to here; x{key} IS strip-eligible, so any x{key} that survives to this scan is rejected (the strip belongs to the meta-schema; survival means it was not stripped).

Table of Contents

Constants

FORBIDDEN_SET  : array<string, true> = ['display_switch' => true, 'display_target' =>...
The enumerated forbidden meta keys (SPEC §6), identical to the JS reference FORBIDDEN_META_KEYS: condition-only meta keys, the retired seqtokey/__13hex__, the magic '_' default symbol, the $-composition-overlay keys, and the xclass/xstyle comment literals (the broader x{key} family is matched by pattern, not enumerated). Stored as a value->true map for O(1) membership.

Methods

scan()  : void
Recursively scan a composed single spec for any forbidden meta key at any depth. Throws ComposeLoadError('FORBIDDEN_META_KEY') on the first hit, with the dotted path to the offending key in the message and trace.
isForbiddenKey()  : bool
Whether $key is globally forbidden (enumerated literal OR x{key}).
isXCommentKey()  : bool
Whether $key is an x{key} comment key: a lowercase 'x' followed by at least one more character (xclass, xstyle, xnote, …). The bare key 'x' is not treated as a comment. The authoritative strip belongs to the meta-schema; this is the runtime backstop that rejects an x{key} that survived.
walk()  : void

Constants

FORBIDDEN_SET

The enumerated forbidden meta keys (SPEC §6), identical to the JS reference FORBIDDEN_META_KEYS: condition-only meta keys, the retired seqtokey/__13hex__, the magic '_' default symbol, the $-composition-overlay keys, and the xclass/xstyle comment literals (the broader x{key} family is matched by pattern, not enumerated). Stored as a value->true map for O(1) membership.

private array<string, true> FORBIDDEN_SET = ['display_switch' => true, 'display_target' => true, 'if' => true, 'when' => true, 'show_if' => true, '_' => true, 'seqtokey' => true, '__13hex__' => true, '$after' => true, '$before' => true, '$merge' => true, '$remove' => true, 'xclass' => true, 'xstyle' => true]

Methods

scan()

Recursively scan a composed single spec for any forbidden meta key at any depth. Throws ComposeLoadError('FORBIDDEN_META_KEY') on the first hit, with the dotted path to the offending key in the message and trace.

public static scan(mixed $spec[, array<int, string> $rootPath = [] ]) : void

The scan descends into every object value AND every array element (a forbidden key nested inside an array of sub-specs is caught too). Map keys are checked before descending into their values, so the reported path points at the shallowest offending key.

Parameters
$spec : mixed

the composed (composition-free, x-stripped) single spec to scan

$rootPath : array<int, string> = []

path prefix for the error trace (default [])

Tags
throws
ComposeLoadError

code FORBIDDEN_META_KEY when a forbidden key is present at any depth

isForbiddenKey()

Whether $key is globally forbidden (enumerated literal OR x{key}).

private static isForbiddenKey(string $key) : bool
Parameters
$key : string
Return values
bool

isXCommentKey()

Whether $key is an x{key} comment key: a lowercase 'x' followed by at least one more character (xclass, xstyle, xnote, …). The bare key 'x' is not treated as a comment. The authoritative strip belongs to the meta-schema; this is the runtime backstop that rejects an x{key} that survived.

private static isXCommentKey(string $key) : bool
Parameters
$key : string
Return values
bool

walk()

private static walk(mixed $node, array<int, string> $path) : void
Parameters
$node : mixed
$path : array<int, string>
On this page

Search results