xmcloud-consistency-check
v0.1.0
Published
Static consistency checks between JSS component code, Sitecore rendering definitions, and datasource templates for XM Cloud projects.
Maintainers
Readme
xmcloud-consistency-check
Static consistency checks for Sitecore XM Cloud JSS projects — catches drift between component code, rendering definitions, and datasource templates before it reaches a content author.
The problem
A JSS component on XM Cloud is really a three-way contract:
- The component code (
Hero.tsx) readsfields.Titleandparams.Variant. - The rendering definition (a serialized Sitecore item) declares which parameters exist and which template the datasource should use.
- The datasource template (also a serialized Sitecore item) declares the actual field names and types.
Nothing enforces that these three stay in sync. A template field gets renamed, a rendering parameter is removed from the definition but a stale reference is left in code, or a component is deleted but its rendering registration isn't — and none of it fails a build. It fails at runtime, usually as a blank or broken component in Sitecore Pages, and it's a content author, not a developer, who finds it.
| | Before | After |
|---|---|---|
| When drift is caught | At runtime, in Pages, by a content author | In CI, on the pull request that introduced it |
| What you're told | "The Hero component is blank on the homepage" | Component "Hero" references field "Subtitle" which does not exist on template "Hero" (available fields: Title, Image, CTA) |
| Live Sitecore connection required | N/A | No — reads the serialized .yml items already committed to the repo |
| Adoption | N/A | Incremental — --warn-only and --ignore so it isn't all-or-nothing |
xmcloud-consistency-check statically analyzes the serialized template and
rendering .yml files that Sitecore CLI already writes to disk, alongside
your JSS component source, and cross-checks all three. It's fast enough to
run on every commit because it never talks to a live XM Cloud instance.
Install
npm i -D xmcloud-consistency-checkRequires Node.js >= 18.17.
Quick start
npx xmcloud-consistency-check runThis will:
- Locate serialized template items (default glob
items/**/*.yml) and parse each template's field names and types. - Locate serialized rendering items (same glob) and parse each rendering's declared parameters and datasource template.
- Locate JSS components (default glob
src/components/**/*.tsx) and statically analyzefields.*/params.*accesses. - Match each component to a rendering (by file-name convention, an explicit
comment, or a mapping file — see below) and report:
- Field & parameter drift — a component reads a field or parameter that doesn't exist on the matched template/rendering.
- Orphans — a component with no matching rendering item, or a rendering item with no matching component file.
- Exit non-zero if anything was found, so it fails a PR check by default.
Non-interactive / CI mode
npx xmcloud-consistency-check run --jsonCommands
run
xmcloud-consistency-check run [options]
-d, --dir <path> project directory (default: cwd)
-c, --config <path> path to xmcloud-consistency.config.json/.js
--warn-only report findings without failing (exit code 0)
--json emit a machine-readable JSON report
--ignore <pattern> additional ignore pattern (glob or exact finding id); repeatableHow components are matched to renderings
Matching is tried in this order:
- An explicit comment in the component file:
// @sitecore-rendering: HeroBanner const Hero = ({ fields }: HeroProps) => /* ... */; - A
mappingentry (inline in config, or in a separatemappingFile) — for components that don't follow the naming convention and aren't worth annotating individually:{ "HeroBanner": "Hero" } - The default naming convention — the component file name (without
extension) matches the rendering item's name, e.g.
Hero.tsx↔ a rendering item namedHero.
A component that matches nothing under any of the three is reported as an orphan component; a rendering that no component claims is reported as an orphan rendering.
Config file
xmcloud-consistency.config.json (or .js/.mjs/.cjs exporting the same
shape as its default export), resolved from the current directory unless
--config points elsewhere:
{
// Glob(s) for serialized template + rendering item YAML.
"itemsGlob": ["items/**/*.yml"],
// Glob(s) for JSS component source.
"componentsGlob": ["src/components/**/*.tsx"],
// Explicit component -> rendering name overrides.
"mapping": { "HeroBanner": "Hero" },
// Same shape as `mapping`, loaded from a separate file and merged in
// (inline `mapping` entries win on conflict).
"mappingFile": "./sitecore-rendering-map.json",
// Findings to suppress — glob or exact match against a finding's stable
// id, e.g. "Hero:field:Subtitle" or "Card:orphan-component".
"ignore": ["LegacyGrid:field:*"],
// Downgrade all findings to warnings (exit code 0). Same as --warn-only.
"warnOnly": false
}GitHub Actions example
name: xmcloud-consistency-check
on: pull_request
jobs:
consistency:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
- run: npm ci
- run: npx xmcloud-consistency-check runFor inline PR annotations, run with --json and pipe the drift/orphans
arrays into ::error file=...,line=...::message workflow commands, or adapt
a problem matcher
against the human-readable output — each finding line is <path>[:<line>]
followed by an indented message line.
Trying it against a real project
If you point this at a freshly cloned starter (e.g.
xmcloud-foundation-head)
before ever connecting it to a real XM Cloud/CM instance, you'll likely see
every component reported as an orphan and a warning at the top of the
report instead of a template/rendering count. That's expected, not a bug:
starter repos ship JSS component source but not the corresponding serialized
template/rendering items — those only land on disk after you run something
like dotnet sitecore ser pull against a connected instance and commit the
result. This tool needs that serialization step to have already happened;
run it against a project further along in its lifecycle (or your own,
already-serialized repo) to see real drift/orphan detection.
Known limitations (v1)
This tool uses static analysis with reasonable heuristics, not a live Sitecore connection or full type-checking. Specifically:
- Dynamic field/param access isn't checked.
fields[someVariable]orparams[key]can't be resolved statically and is skipped rather than guessed at (reported internally as "dynamic access" but not flagged as a finding either way). - Renamed destructures aren't tracked.
const { fields: f } = propsand thenf.Titlewon't be seen — the analyzer looks for accesses on identifiers literally namedfields/params, matching standard JSS component conventions. Optional chaining (props?.fields?.Title,params?.Variant) is supported and matches real-world component code, which uses it pervasively. - No template inheritance. Only fields declared directly on the matched template are considered; fields inherited from a base template aren't merged in.
- Renderings are matched by path convention
(
/sitecore/layout/renderings/**), not by rendering base-template id, since that id varies across JSS/XM Cloud versions. Templates are matched by Sitecore's built-inTemplate/Template field/Template sectionkernel ids, which are stable across all instances. - Datasource/Parameters Template resolution relies on a
Datasource Template/Parameters Templatefield on the rendering item (matched by itsHint), falling back to name convention (template name === rendering name) if absent. If neither resolves, field/param checks are skipped for that rendering rather than flagging every access as unknown.
Roadmap
- Optional live-instance validation (fetch definitions via the Sitecore Management/GraphQL API instead of, or in addition to, serialized YAML).
- Auto-fix / codemod support for the mechanical cases (renamed field with an unambiguous single candidate).
- Template inheritance resolution (merge base template fields).
Development
npm install
npm run build # tsup -> dist/
npm run typecheck
npm test # vitest: unit + fixture-driven integration testsTest fixtures live under tests/fixtures/sample-project — a small serialized
Sitecore project covering a clean match, a field mismatch, a missing
rendering parameter, an orphaned component, and an orphaned rendering.
