@zeropress/theme-validator
v0.5.3
Published
Shared ZeroPress theme validation core
Readme
@zeropress/theme-validator
Shared validation core for ZeroPress theme manifests and directory-backed file maps.
This package is the single source of truth for runtime theme validation used by:
- @zeropress/theme
backend_api_v2themes.zeropress.org-api
It implements the current runtime v0.5 validation rules defined in ZeroPress Theme Runtime Spec v0.5.
Install
npm install @zeropress/theme-validatorExports
import {
DEFAULT_RUNTIME,
validateNamespace,
validateSlug,
validateThemeManifest,
validateThemeFiles,
} from '@zeropress/theme-validator';Schema exports:
import runtimeSchemaUrl from '@zeropress/theme-validator/theme.v0.5.runtime.schema.json';Published schema files are shipped from the package schemas/ directory, and package subpath exports are versioned.
API
validateNamespace(value) / validateSlug(value)
Shared identifier helpers for scaffolding and submission flows.
validateNamespace(value)returns the normalized namespace string or throwsvalidateSlug(value)returns the validated slug string or throws
validateThemeManifest(themeJson)
Validates manifest-only input without requiring theme files.
This is intended for:
- scaffolding tools
- manifest-only prechecks
- tests that need runtime contract checks without packaging
validateThemeFiles(fileMap, options?)
Validates an already-loaded virtual file map.
Accepted inputs:
Map<string, string | Uint8Array | ArrayBuffer>Record<string, string | Uint8Array | ArrayBuffer>
This is intended for:
- directory-based validation
- worker-side already-loaded uploads after unzip
- tests and internal adapters
Directory callers can also pass pathEntries for path traversal and symlink validation:
const result = await validateThemeFiles(files, {
pathEntries: [
{
path: 'partials/header.html',
isSymlink: false,
},
{
path: 'escape-link',
isSymlink: true,
resolvedPath: '/real/target',
rootRealPath: '/theme/root',
},
],
});Result Shape
validateThemeFiles() returns:
{
ok: true,
errors: [],
warnings: [],
manifest: {
name: 'My Theme',
namespace: 'my-studio',
slug: 'my-theme',
version: '1.0.0',
license: 'MIT',
runtime: '0.5',
description: 'Optional',
menuSlots: {
primary: {
title: 'Primary Menu',
},
},
widgetAreas: {
sidebar: {
title: 'Sidebar Widgets',
},
},
siteMeta: {
issue: {
title: 'Issue',
type: 'string',
},
},
collectionSlots: {
'cover-story': {
title: 'Cover Story',
},
},
},
checkedFiles: 6
}Issue objects use this shape:
{
code: 'MISSING_REQUIRED_FILE',
path: 'assets/style.css',
message: "Required file 'assets/style.css' is missing",
severity: 'error'
}Validation Profile
Errors
theme.jsonmissing or invalid- Missing required templates:
layout.html,index.html,post.html,page.html - Missing
assets/style.css - Invalid semver in
theme.json.version - Missing or invalid
theme.json.namespace - Missing or invalid
theme.json.slug - Missing or invalid
theme.json.license - Missing or invalid
theme.json.runtime theme.json.namelonger than 80 characterstheme.json.authorlonger than 80 characterstheme.json.descriptionlonger than 280 characters- Unknown root fields in
theme.json - Invalid
theme.json.menuSlots - Invalid
theme.json.widgetAreas - Invalid
theme.json.siteMeta - Invalid
theme.json.collectionSlots - Invalid menu slot ids
- Invalid menu slot definitions or unknown slot properties
- Invalid widget area ids
- Invalid widget area definitions or unknown widget area properties
- Removed
theme.json.settings layout.htmlmissing or duplicating{{slot:content}}- Unknown slot names
- Nested slot expressions
- Mustache block syntax
<script>insidelayout.html- Path traversal or symlink escape
Warnings
archive.html,category.html,tag.htmlmissing
Requirements
- Node.js >= 18.18.0
- ESM only
Related
License
MIT
