Contributing / PR Guide

June 2, 2026 · View on GitHub

Repository Setup

This repository uses git submodules. Clone with:

git clone --recursive https://github.com/zaggino/z-schema.git
cd z-schema
npm install

If already cloned without --recursive:

git submodule update --init --recursive

Commit Messages

All commits must follow Conventional Commits.

Format: <type>[optional scope]: <description>

Common types:

TypeWhen to use
featA new feature
fixA bug fix
docsDocumentation-only changes
refactorCode change that neither fixes a bug nor adds a feature
perfPerformance improvement
testAdding or updating tests
choreBuild process, CI, tooling, dependency updates

Examples:

feat: add maxRecursionDepth option
fix: prevent global_cache mutation in fromCache
refactor(schema-cache): cache global clone in instance cache
docs: add conventional commits guide
feat!: remove deprecated constructor (BREAKING CHANGE)

Append ! after the type/scope for breaking changes, or include a BREAKING CHANGE: footer in the commit body.

Branch & PR Workflow

  1. Create a feature branch from main (the active development branch):
    git checkout -b feature/my-change main
    
  2. Make your changes following the code conventions.
  3. Run the full check suite before pushing:
    npm run check
    npm run build
    npm run build:tests
    npm test
    
  4. Push and open a PR against the main branch.

Making Changes

Adding a New Feature

  1. Implement the feature in the appropriate src/ file.
  2. Export any new public types/values through src/index.ts.
  3. Write tests in test/spec/ using the correct suffix (.spec.ts for both environments, .node-spec.ts for node-only, .browser-spec.ts for browser-only).
  4. If the feature relates to a JSON Schema keyword from the test suite, remove the relevant entries from excludedFiles / excludedTests in test/spec/json-schema-test-suite.common.ts and confirm tests pass.
  5. Update documentation in docs/ if the feature affects the public API.

Adding a New Error Code

  1. Add the error to the Errors object in src/errors.ts using UPPER_SNAKE_CASE and template placeholders ({0}, {1}).
  2. Use report.addError(code, params) in the relevant validation logic.
  3. Add tests that verify the error code is produced.

Adding a New Format Validator

  1. Add the validator function in src/format-validators.ts.
  2. Register it in the inbuiltValidators record.
  3. Add tests in test/spec/format-validators.spec.ts.

Adding a New Utility

  1. Create a new file in src/utils/ — each file should be single-purpose.
  2. Import it where needed using .js extension (ESM convention).
  3. Do not export utilities from src/index.ts unless they are part of the public API.

Modifying Options

  1. Add the option to the ZSchemaOptions interface in src/z-schema-options.ts.
  2. Add a default value to the defaultOptions object in the same file.
  3. If the option affects strictMode, add it to the strictMode block in normalizeOptions.
  4. Document the option in docs/options.md.
  5. Add tests.

Code Quality Checks

CheckCommandNotes
Checknpm run checkultracite check — oxlint (type-aware) + oxfmt format check
Fixnpm run fixultracite fix — oxlint --fix + oxfmt --write
Buildnpm run buildtsdown bundling (ESM + CJS + UMD + types)
Test type-checknpm run build:testsType-check test files without running them
Tests (all)npm testVitest — node + browser projects
Tests (node)npm run test:nodeNode-only tests with output
Tests (browser)npm run test:browserBrowser tests (Chromium, Firefox, WebKit)
Coveragenpm run test:coverageIstanbul coverage for src/

Pre-commit & Pre-push Hooks

Git hooks are managed by lefthook (lefthook.yml), installed automatically via the prepare npm script (lefthook install).

  • Pre-commit: auto-runs oxlint --fix on staged JS/TS files and oxfmt --write on all staged files, re-staging any changes.
  • Pre-push: runs npm run build && npm run build:tests to catch build/type errors.

File Organization Rules

  • All public exports go through src/index.ts.
  • Internal types (e.g., JsonSchemaInternal, compiler metadata) stay unexported.
  • Tests go in test/spec/ with appropriate suffix.
  • Test fixtures go in test/fixtures/.
  • Pure utility functions go in src/utils/ (one file per concern).
  • Use import type for type-only imports.
  • Use .js extension in src/ imports (ESM), .ts extension in test/ imports (enabled by allowImportingTsExtensions).

Common Pitfalls

  • Never use new ZSchema() — always use ZSchema.create().
  • ValidateError.details (not .errors) is the array of error objects.
  • Default version is draft2020-12. Specify version: 'draft-04', 'draft-06', 'draft-07', 'draft2019-09', 'draft2020-12' or none explicitly if needed.
  • Import extensions: src/ uses .js, test/ uses .ts.
  • Schemas in src/schemas/ are generated by scripts/copy-schemas.mts at build time — do not edit them manually.
  • json-schema-spec/ is a git submodule — do not commit changes to it directly.

Coverage Artifact Auto-Updates in PRs

For pull requests, CI may auto-commit coverage artifacts (docs/test-coverage.md and README.md) when they change.

  • Auto-commit runs only for same-repository pull requests.
  • Auto-commit is skipped for fork pull requests.
  • Auto-commit is skipped when the actor is github-actions[bot].
  • Only coverage artifact files are staged for this CI-authored commit.
  • Coverage artifact update logic is serialized per PR branch with cancel-in-progress behavior to avoid commit races.