npm package: @10up/block-renderer-validator
Description: Validation for WordPress block trees - schema, nesting, and token validation
Latest version: 0.2.0

# @10up/block-renderer-validator

Validate JSON block trees against schemas, nesting rules, and theme tokens. This package ensures block trees are valid before rendering.

## Installation

```bash
npm install @10up/block-renderer-validator
# or
pnpm add @10up/block-renderer-validator
```

## Overview

This package provides comprehensive validation for block trees:

1. **Schema Validation** - Validates block props against Zod schemas from block definitions
2. **Nesting Validation** - Checks parent/ancestor/allowedBlocks constraints
3. **Token Validation** - Verifies theme token references (colors, spacing, etc.)
4. **Pattern Validation** - Confirms pattern slugs exist in the registry

## Usage

### Full Tree Validation

The main entry point - validates a tree with all available validators:

```typescript
import { validateTree } from '@10up/block-renderer-validator';

const tree = {
  root: 'para-1',
  elements: {
    'para-1': {
      key: 'para-1',
      type: 'core/paragraph',
      props: {
        content: 'Hello',
        style: { color: { background: 'var:preset|color|primary' } }
      }
    }
  }
};

const result = validateTree(tree, {
  catalog: blockCatalog,     // Block definitions for schema/nesting
  tokens: themeTokens,       // Theme tokens for color/spacing validation
  patterns: patternRegistry  // Pattern definitions
});

if (result.valid) {
  console.log('Tree is valid');
} else {
  console.log('Errors:', result.errors);
  // ['Unknown color token: primary', 'Invalid block type: core/unknown']
}
```

### Validation Options

```typescript
interface ValidateTreeOptions {
  /** Block catalog for schema and nesting validation */
  catalog?: BlockCatalog;
  /** Theme tokens for token validation */
  tokens?: ThemeTokens;
  /** Pattern registry for pattern validation */
  patterns?: PatternRegistry;
  /** Whether to validate schemas (default: true if catalog provided) */
  validateSchemas?: boolean;
  /** Whether to validate nesting rules (default: true if catalog provided) */
  validateNesting?: boolean;
  /** Whether to validate theme tokens (default: true if tokens provided) */
  validateTokens?: boolean;
  /** Whether to validate pattern references (default: true if patterns provided) */
  validatePatterns?: boolean;
}
```

### Create Reusable Validator

```typescript
import { createTreeValidator } from '@10up/block-renderer-validator';

const validator = createTreeValidator({
  catalog: blockCatalog,
  tokens: themeTokens,
  patterns: patternRegistry,
});

// Use the pre-configured validator
const result1 = validator(tree1);
const result2 = validator(tree2);
```

## Schema Validation

Validate block props against their Zod schemas:

```typescript
import { validateBlockProps, validateTreeSchemas } from '@10up/block-renderer-validator';

// Validate a single element's props
const result = validateBlockProps(element.props, blockDefinition.schema);
if (!result.valid) {
  console.log(result.errors);
  // ['content: Expected string, received number']
}

// Validate all elements in a tree
const treeResult = validateTreeSchemas(tree, catalog);
```

### Create Block Validator

Create a validator for a specific block:

```typescript
import { createBlockValidator } from '@10up/block-renderer-validator';

const validateParagraph = createBlockValidator(paragraphDefinition);
const result = validateParagraph({ content: 'Hello', dropCap: true });
```

### Get Valid Attributes

Filter props to only include valid attributes:

```typescript
import { getValidAttributes } from '@10up/block-renderer-validator';

const cleanProps = getValidAttributes(props, blockDefinition.schema);
// Returns only props that match the schema
```

## Nesting Validation

Validate block nesting rules:

```typescript
import { validateTreeNesting } from '@10up/block-renderer-validator';

const result = validateTreeNesting(tree, catalog);
if (!result.valid) {
  console.log(result.errors);
  // ['core/column must be inside core/columns']
}
```

### Individual Nesting Validators

```typescript
import {
  validateParent,
  validateAncestor,
  validateChildren,
  validateMultiple,
} from '@10up/block-renderer-validator';

// Check if element has valid parent
validateParent(element, parentElement, blockDefinition);

// Check if element has valid ancestor chain
validateAncestor(element, ancestorChain, blockDefinition);

// Check if children are valid for this block
validateChildren(element, childElements, blockDefinition);

// Check if multiple instances are allowed
validateMultiple(elements, blockDefinition);
```

## Token Validation

Validate theme token references in block props:

```typescript
import { validateTreeTokens, validateElementTokens } from '@10up/block-renderer-validator';

// Validate all tokens in a tree
const result = validateTreeTokens(tree, themeTokens);
if (!result.valid) {
  console.log(result.errors);
  // ['Unknown color token: invalid-color']
}

// Validate a single element's tokens
const elementResult = validateElementTokens(element, themeTokens);
```

### Specific Token Validators

```typescript
import {
  validateColorTokens,
  validateTypographyTokens,
  validateSpacingTokens,
} from '@10up/block-renderer-validator';

// Validate specific token types
validateColorTokens(props, themeTokens);
validateTypographyTokens(props, themeTokens);
validateSpacingTokens(props, themeTokens);
```

## Pattern Validation

Validate pattern block references:

```typescript
import {
  validatePatternReference,
  validateTreePatterns,
  isPatternReference,
  getPatternReferences,
} from '@10up/block-renderer-validator';

// Check if an element is a pattern reference
if (isPatternReference(element)) {
  const result = validatePatternReference(element, patternRegistry);
  if (!result.valid) {
    console.log(result.errors);
    // ['Unknown pattern: theme/nonexistent-pattern']
  }
}

// Validate all patterns in a tree
const treeResult = validateTreePatterns(tree, patternRegistry);

// Get all pattern references from a tree
const patternRefs = getPatternReferences(tree);
// ['theme/hero-section', 'theme/footer']
```

## Template Validation

Validate BlockTemplate format (PHP-style nested arrays):

```typescript
import {
  validateTemplate,
  validateTemplateStructure,
  validateTemplateBlockTypes,
  validateTemplateNesting,
} from '@10up/block-renderer-validator';

const template = [
  ['core/group', { layout: { type: 'constrained' } }, [
    ['core/heading', { content: 'Title', level: 2 }],
    ['core/paragraph', { content: 'Content' }],
  ]],
];

// Full template validation
const result = validateTemplate(template, {
  catalog: blockCatalog,
});

if (!result.valid) {
  console.log('Errors:', result.errors);
}

// Validate just structure (correct array format)
const structureResult = validateTemplateStructure(template);

// Validate block types exist
const typesResult = validateTemplateBlockTypes(template, catalog);

// Validate nesting rules
const nestingResult = validateTemplateNesting(template, catalog);
```

### Template Validation Options

```typescript
interface ValidateTemplateOptions {
  /** Block catalog for type and nesting validation */
  catalog?: BlockCatalog;
  /** Whether to validate that block types exist (default: true if catalog provided) */
  validateBlockTypes?: boolean;
  /** Whether to validate nesting rules (default: true if catalog provided) */
  validateNesting?: boolean;
}
```

## Complete Exports

### Main Functions

| Function | Description |
|----------|-------------|
| `validateTree(tree, options)` | Full tree validation with all validators |
| `createTreeValidator(options)` | Create reusable validator function |

### Schema Validation

| Function | Description |
|----------|-------------|
| `validateBlockProps(props, schema)` | Validate props against Zod schema |
| `validateTreeSchemas(tree, catalog)` | Validate all elements in tree |
| `createBlockValidator(definition)` | Create validator for specific block |
| `getValidAttributes(props, schema)` | Filter to valid attributes only |

### Nesting Validation

| Function | Description |
|----------|-------------|
| `validateTreeNesting(tree, catalog)` | Validate all nesting rules in tree |
| `validateParent(element, parent, def)` | Check valid parent constraint |
| `validateAncestor(element, ancestors, def)` | Check valid ancestor constraint |
| `validateChildren(element, children, def)` | Check valid children constraint |
| `validateMultiple(elements, def)` | Check multiple instance constraint |

### Token Validation

| Function | Description |
|----------|-------------|
| `validateTreeTokens(tree, tokens)` | Validate all tokens in tree |
| `validateElementTokens(element, tokens)` | Validate single element tokens |
| `validateColorTokens(props, tokens)` | Validate color token references |
| `validateTypographyTokens(props, tokens)` | Validate typography tokens |
| `validateSpacingTokens(props, tokens)` | Validate spacing tokens |

### Pattern Validation

| Function | Description |
|----------|-------------|
| `validateTreePatterns(tree, patterns)` | Validate all pattern refs in tree |
| `validatePatternReference(element, patterns)` | Validate single pattern ref |
| `isPatternReference(element)` | Check if element is a pattern |
| `getPatternReferences(tree)` | Get all pattern slugs from tree |

### Template Validation

| Function | Description |
|----------|-------------|
| `validateTemplate(template, options)` | Full template validation |
| `validateTemplateStructure(template)` | Validate template array structure |
| `validateTemplateBlockTypes(template, catalog)` | Validate block types exist |
| `validateTemplateNesting(template, catalog)` | Validate nesting rules |

### Types

| Type | Description |
|------|-------------|
| `ValidateTreeOptions` | Options for validateTree |
| `ValidateTemplateOptions` | Options for validateTemplate |
| `TemplateValidationResult` | Result from template validation |

## License

MIT