@bernierllc/validators-json-structure
v1.2.0
Published
Primitive validator for JSON structure validation - parseability, encoding, schema hooks
Readme
@bernierllc/validators-json-structure
Primitive validator for JSON structure validation - parseability, encoding correctness, and schema hooks.
Installation
npm install @bernierllc/validators-json-structureFeatures
- JSON Syntax Validation - Validates that JSON is well-formed and parseable
- Duplicate Key Detection - Detects duplicate keys that can lead to data loss
- Trailing Comma Detection - Identifies trailing commas (not valid in strict JSON)
- Number Format Validation - Validates number formats (no leading zeros, no Infinity/NaN)
- Escape Sequence Validation - Validates that escape sequences are valid JSON escape sequences
- UTF-8 Encoding Validation - Validates proper UTF-8 encoding and detects UTF-8 BOM
Usage
Basic Validation
import { validateJsonStructure } from '@bernierllc/validators-json-structure';
const json = '{"name": "test", "value": 123}';
const problems = await validateJsonStructure(json);
if (problems.length === 0) {
console.log('Valid JSON structure');
} else {
problems.forEach(problem => {
console.log(`${problem.severity}: ${problem.message}`);
});
}With Custom Options
import { validateJsonStructure } from '@bernierllc/validators-json-structure';
const json = '{"id": 1, "id": 2}'; // Duplicate keys
const problems = await validateJsonStructure(json, {
checkDuplicateKeys: true,
checkTrailingCommas: true,
checkNumberFormat: true,
checkEscapeSequences: true,
checkEncoding: true,
maxDepth: 100
});
// Returns problems for duplicate keys
console.log(problems);Simple JSON Validation
import { isValidJson } from '@bernierllc/validators-json-structure';
if (isValidJson('{"name": "test"}')) {
console.log('Valid JSON');
}Safe JSON Parsing
import { parseJsonSafe } from '@bernierllc/validators-json-structure';
const result = parseJsonSafe('{"name": "test"}');
if (result.success) {
console.log('Parsed data:', result.data);
} else {
console.error('Parse error:', result.error);
}Using Individual Rules
import {
jsonSyntaxRule,
duplicateKeysRule,
trailingCommaRule,
numberFormatRule,
escapeSequencesRule,
encodingRule
} from '@bernierllc/validators-json-structure';
import { createRuleContext } from '@bernierllc/validators-core';
// Use individual rules for fine-grained control
const problems = [];
const context = createRuleContext(
'json-structure/syntax',
{ checkDuplicateKeys: true },
utils,
{},
(p) => problems.push(p)
);
const validator = duplicateKeysRule.create(context);
await validator('{"id": 1, "id": 2}');
console.log(problems); // Array of validation problemsAPI Reference
validateJsonStructure(json, options?, utils?)
Validates JSON structure against all enabled rules.
Parameters:
json(string): The JSON string to validateoptions(object, optional): Validation optionsmaxDepth(number, default: 100): Maximum depth of nested objects/arrayscheckDuplicateKeys(boolean, default: true): Check for duplicate keyscheckTrailingCommas(boolean, default: true): Check for trailing commascheckNumberFormat(boolean, default: true): Validate number formatscheckEscapeSequences(boolean, default: true): Validate escape sequencescheckEncoding(boolean, default: true): Validate UTF-8 encoding
utils(SharedUtils, optional): Shared utilities from validators-utils
Returns: Promise<Problem[]> - Array of validation problems
isValidJson(json)
Checks if a string is valid JSON.
Parameters:
json(string): The JSON string to validate
Returns: boolean - true if valid, false otherwise
parseJsonSafe<T>(json)
Parses JSON with detailed error information.
Parameters:
json(string): The JSON string to parse
Returns: Object with:
success(boolean): Whether parsing succeededdata(T, optional): Parsed data if successfulerror(string, optional): Error message if failed
Validation Rules
json-structure/syntax
Validates that JSON is well-formed and parseable.
Detects:
- Malformed JSON syntax
- Unclosed strings
- Missing commas
- Invalid property names
- Empty input
Example Problems:
// ❌ Invalid - unclosed string
{"name": "test}
// ❌ Invalid - missing comma
{"name": "test" "value": 123}
// ❌ Invalid - unquoted property name
{name: "test"}json-structure/duplicate-keys
Detects duplicate keys in JSON objects which can lead to data loss.
Detects:
- Duplicate keys at any nesting level
- Multiple occurrences of the same key
Example Problems:
// ❌ Invalid - duplicate "id" key
{"id": 1, "name": "test", "id": 2}
// ❌ Invalid - duplicate "name" in nested object
{"user": {"name": "first", "age": 30, "name": "second"}}json-structure/trailing-comma
Detects trailing commas which are not valid in strict JSON.
Detects:
- Trailing commas in objects
- Trailing commas in arrays
Fixable: Yes
Example Problems:
// ❌ Invalid - trailing comma in object
{"name": "test", "value": 123,}
// ❌ Invalid - trailing comma in array
{"items": [1, 2, 3,]}json-structure/number-format
Validates number formats according to JSON specification.
Detects:
- Numbers with leading zeros (e.g.,
0123) Infinity(not valid JSON)NaN(not valid JSON)
Example Problems:
// ❌ Invalid - leading zero
{"value": 0123}
// ❌ Invalid - Infinity
{"value": Infinity}
// ❌ Invalid - NaN
{"result": NaN}
// ✅ Valid
{"value": 123, "decimal": 0.5}json-structure/escape-sequences
Validates that escape sequences are valid JSON escape sequences.
Valid Escape Sequences:
\"- Quotation mark\\- Backslash\/- Forward slash\b- Backspace\f- Form feed\n- Newline\r- Carriage return\t- Tab\uXXXX- Unicode escape (4 hex digits)
Example Problems:
// ❌ Invalid - \x is not a valid JSON escape
{"text": "Invalid \x escape"}
// ❌ Invalid - incomplete unicode sequence
{"text": "Bad \u12 unicode"}
// ✅ Valid
{"text": "Line 1\nLine 2\tTabbed"}
{"emoji": "\u2764\uFE0F"}json-structure/encoding
Validates that JSON is properly UTF-8 encoded.
Detects:
- UTF-8 BOM (Byte Order Mark) - not recommended for JSON
- Invalid UTF-8 sequences
- Unpaired surrogates
Example Problems:
// ⚠️ Warning - UTF-8 BOM detected
\uFEFF{"text": "test"}
// ✅ Valid - proper unicode characters
{"text": "Hello, 世界! 🌍"}
{"emoji": "✨🎉🚀"}Problem Structure
Each validation problem includes:
interface Problem {
ruleId: string; // e.g., "json-structure/syntax"
message: string; // Human-readable description
severity: 'error' | 'warn' | 'info' | 'off';
domain: 'parsing'; // Validation domain
location?: { // Optional location information
line?: number;
column?: number;
};
suggestion?: string; // How to fix the issue
fixable?: boolean; // Whether issue is auto-fixable
evidence?: { // Supporting evidence
snippet?: string; // Code snippet
context?: Record<string, unknown>;
};
tags?: string[]; // Additional categorization
}Examples
Validating API Request Data
import { validateJsonStructure } from '@bernierllc/validators-json-structure';
async function validateApiRequest(requestBody: string) {
const problems = await validateJsonStructure(requestBody);
const errors = problems.filter(p => p.severity === 'error');
if (errors.length > 0) {
throw new Error(`Invalid JSON: ${errors.map(e => e.message).join(', ')}`);
}
return JSON.parse(requestBody);
}Configuration File Validation
import { validateJsonStructure, parseJsonSafe } from '@bernierllc/validators-json-structure';
import * as fs from 'fs';
async function loadConfig(filePath: string) {
const content = fs.readFileSync(filePath, 'utf-8');
// Validate structure
const problems = await validateJsonStructure(content);
if (problems.length > 0) {
console.warn('Configuration issues:');
problems.forEach(p => {
console.warn(` ${p.severity}: ${p.message}`);
if (p.location) {
console.warn(` at line ${p.location.line}, column ${p.location.column}`);
}
});
}
// Parse safely
const result = parseJsonSafe(content);
if (!result.success) {
throw new Error(`Cannot parse config: ${result.error}`);
}
return result.data;
}Custom Validation Profile
import { validateJsonStructure } from '@bernierllc/validators-json-structure';
// Strict validation for production
async function validateProduction(json: string) {
return validateJsonStructure(json, {
checkDuplicateKeys: true,
checkTrailingCommas: true,
checkNumberFormat: true,
checkEscapeSequences: true,
checkEncoding: true,
maxDepth: 50 // Limit nesting depth
});
}
// Lenient validation for development
async function validateDevelopment(json: string) {
return validateJsonStructure(json, {
checkDuplicateKeys: true,
checkTrailingCommas: false, // Allow in development
checkNumberFormat: true,
checkEscapeSequences: true,
checkEncoding: false
});
}Integration with Validators Ecosystem
This package follows the BernierLLC Validators Principles:
- Pure Validation Functions - Returns structured problems, never throws
- Atomic Primitives - Each rule has single responsibility
- Tool-Agnostic - Works in CLI, web apps, CI/CD, IDE plugins
- Evidence-Rich Results - Provides actionable debugging information
- Composable - Can be combined with other validators
Used By
@bernierllc/validators-api- API validation@bernierllc/validators-config- Configuration file validation- Custom domain validators requiring JSON structure validation
Integration Status
- Logger: not-applicable - Primitive validator, logging handled by consumer
- Docs-Suite: ready - Full TypeDoc API documentation
- NeverHub: not-applicable - Primitive validator, no service discovery needed
Performance
- Sub-100ms validation for typical JSON files (< 1MB)
- Parallel execution of independent rules
- Memory efficient - Streams through input without full AST
Testing
This package includes comprehensive test coverage:
npm test # Run tests in watch mode
npm run test:run # Run tests once
npm run test:coverage # Run tests with coverage reportCoverage Requirements:
- Branches: 90%+
- Functions: 90%+
- Lines: 90%+
- Statements: 90%+
See Also
- @bernierllc/validators-core - Core validator types and utilities
- @bernierllc/validators-runner - Execute validators with policies
- @bernierllc/validators-reporters - Format validation results
License
Copyright (c) 2025 Bernier LLC. All rights reserved.
