What validateItems reports
@evanion/widget 0.1.0 and its patch releases up to 0.1.3, the version on npm. Values on this page were produced by running the source at f9b1d93, a later commit than the 0.1.0 tag, and are not re-executed.
Even with a strictly typed renderer, you still need a way to validate the data arriving from your CMS. A single typo in a widget type or a missing required prop can lead to a “broken” page where parts of the UI simply vanish.
validateItems(items, known) allows you to scan a whole payload in one pass, identifying every fault—including those nested deep within other widgets—without throwing exceptions.
The Problem: Structural Faults in CMS Data
CMS data is inherently untyped. When your frontend receives a JSON payload, a few common errors can cause the UI to fail silently:
- Unknown Types: A content editor types
listtinginstead oflisting. - Missing Props: A required field like
titleis left blank. - Malformed Structure: An item is a string instead of an object, or
childrenis not a list. - Identity Collisions: Two widgets in the same section share the same
id.
If these aren’t caught, your renderer will simply skip the items it cannot draw and draw the rest with whatever data they carry, leaving mysterious gaps in your page.
Solution: Deep-Payload Scanning
validateItems performs a depth-first walk of your widget tree. It reports an item’s own problems first, then recursively validates its children before moving to the next sibling.
Consider a payload with three distinct faults: a missing props object, a duplicate ID, and a typo in a widget type.
import { } from '@evanion/widget';
const = [
{ : 'wingspan', : 'listing' },
{ : 'wingspan', : 'listing', : { : 'Wingspan' } },
{
: 'tonight',
: 'shelf',
: {},
: [{ : 'hive', : 'listting', : { : 'Hive' } }],
},
];
const = (, ['listing', 'shelf']).(
({ , }) => ({ , }),
);
; // -> [{ index: 0, message: 'props is not an object' }, { index: 1, message: 'duplicate sibling id' }, { index: 0, message: 'unknown widget type' }]In this case, the engine identifies the missing props on the first item and the duplicate ID on the second. Finally, it descends into the tonight shelf and finds that its child, Hive’s listing, has an unknown type.
Because it walks the tree depth-first, Hive’s problem is reported last, and its index is 0 because it is the first child of the shelf, not the third item in the overall payload.
Anatomy of a WidgetProblem
Every fault found by the library is returned as a WidgetProblem object:
| Field | Description |
|---|---|
index | The item’s position among its siblings. Returns -1 if the payload is not a list. |
id | The item’s id string, or - if the ID is missing. |
type | The item’s type string, or - if the type is missing. |
message | A human-readable error string from VALIDATION_MESSAGES. |
Standardized Error Messages for Automation
To make it easier to translate or group errors, @evanion/widget exports VALIDATION_MESSAGES. Instead of comparing raw strings, you should compare the message against these constants.
| Constant | Message | Cause |
|---|---|---|
NOT_A_LIST | items is not a list | The payload is not an array. |
NOT_AN_OBJECT | item is not an object | An entry is a primitive (string, number, etc.) instead of an object. |
INVALID_ID | item id is not a string | The id field is missing or is not a string. |
INVALID_TYPE | item type is not a string | The type field is missing or is not a string. |
UNKNOWN_TYPE | unknown widget type | The type is not present in the known list. |
INVALID_PROPS | props is not an object | The props field is missing, or is not an object. |
INVALID_CHILDREN | children is not a list | The children field is present but is not an array. |
DUPLICATE_ID | duplicate sibling id | Two items in the same sibling list share the same id. |
MISSING_FIELD | missing field <name> | A field marked as required is absent or contains only whitespace. |
Common Pitfall: Placing data at the top level of the item (e.g., { id: '1', type: 'listing', title: 'Game' }). This will trigger an INVALID_PROPS error because the renderer only looks for data inside the props object.
Enforcing Required Fields in CMS Data
Beyond checking if a widget type is known, you can enforce that certain props are present and not blank (where “blank” means undefined, null, or a string of only whitespace).
You do this by passing a required map as the third argument to validateItems:
import { } from '@evanion/widget';
const = (
[{ : 'wingspan', : 'listing', : { : ' ' } }],
['listing'],
{ : ['title'] },
);
; // -> [{ index: 0, id: 'wingspan', type: 'listing', message: 'missing field title' }]In the example above, even though title is a string, it is blank. validateItems reports it as missing field title, so your gate can stop the page before your renderer draws a listing without a name.
Note that required checks only happen for known types. If a widget’s type is unknown, it is reported as an UNKNOWN_TYPE fault, and its required props are ignored.
Syncing Validation with Your Renderer
You can pass the same registry your renderer uses as the known argument to validateItems. This ensures that your validation logic and your rendering logic always agree on which types exist.
If you are running a validation check in a CI environment where you cannot import your React components, you can simply pass a plain array of type names.
import { , } from '@evanion/widget';
// Whatever your renderer resolves a type to. The core reads the keys and never
// calls a value, so a stand-in is enough to show what the keys do.
const = () => null;
const = () => null;
const = ({ : , : });
const = (
[{ : 'wingspan', : 'listing', : { : 'Wingspan' } }],
,
);
; // -> []By using defineWidgets, you get the best of both worlds: a typed registry for your code editor and a plain list of strings for validateItems.
Next steps: Layout and Rendering
Now that you can identify faults in your content, you can learn how the renderer actually handles the valid items. Order and nesting explains how the library handles layout, nesting, and placement.