CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-yaml

JavaScript parser and stringifier for YAML documents with complete YAML 1.1 and 1.2 support

Overview
Eval results
Files

error-handling.mddocs/

Error Handling

Comprehensive error reporting system with position information, warning messages, and configurable logging. The YAML library provides detailed error tracking for robust YAML processing and debugging capabilities.

Capabilities

Error Classes

The library provides three main error classes for different types of issues encountered during YAML processing.

/**
 * Base error class for all YAML-related errors
 */
class YAMLError extends Error {
  /** Error name identifier */
  name: 'YAMLError';
  
  /** Error code identifier */
  code: ErrorCode;
  
  /** Human-readable error message */
  message: string;
  
  /** Optional position information [start, end] */
  pos?: [number, number];
  
  constructor(pos: [number, number] | null, code: ErrorCode, message: string);
}

/**
 * Parse-time errors with position information  
 */
class YAMLParseError extends YAMLError {
  /** Error name identifier */
  name: 'YAMLParseError';
  
  /** Position in source [start, end] */
  pos: [number, number];
  
  /** Line and column position */
  linePos?: { line: number; col: number };
  
  constructor(pos: [number, number], code: ErrorCode, message: string);
}

/**
 * Warning messages for non-fatal issues
 */
class YAMLWarning extends YAMLError {
  /** Warning name identifier */
  name: 'YAMLWarning';
  
  constructor(pos: [number, number] | null, code: ErrorCode, message: string);
}

Error Codes

Comprehensive set of error codes covering all possible YAML parsing issues.

type ErrorCode = 
  | 'BAD_ALIAS'           // Invalid alias reference
  | 'BAD_DIRECTIVE'       // Invalid document directive
  | 'BAD_DQ_ESCAPE'       // Invalid escape sequence in double-quoted string
  | 'BAD_INDENT'          // Incorrect indentation
  | 'BAD_PROP_ORDER'      // Properties in wrong order
  | 'BAD_SCALAR_START'    // Invalid scalar start character
  | 'BLOCK_AS_IMPLICIT_KEY' // Block scalar used as implicit key
  | 'BLOCK_IN_FLOW'       // Block scalar in flow context
  | 'DUPLICATE_KEY'       // Duplicate key in mapping
  | 'IMPOSSIBLE'          // Internal parser error
  | 'KEY_OVER_1024_CHARS' // Key exceeds maximum length
  | 'MISSING_CHAR'        // Expected character missing
  | 'MULTILINE_IMPLICIT_KEY' // Multiline implicit key
  | 'MULTIPLE_ANCHORS'    // Multiple anchors on single node
  | 'MULTIPLE_DOCS'       // Multiple documents in single-doc context
  | 'MULTIPLE_TAGS'       // Multiple tags on single node
  | 'TAB_AS_INDENT'       // Tab character used for indentation
  | 'TAG_RESOLVE_FAILED'  // Tag resolution failed
  | 'UNEXPECTED_TOKEN';   // Unexpected token encountered

Usage Examples:

import { parse, parseDocument, YAMLParseError, YAMLWarning } from "yaml";

// Handle parse errors
try {
  const data = parse(`
    invalid: [unclosed array
    another: key
  `);
} catch (error) {
  if (error instanceof YAMLParseError) {
    console.log('Parse Error Details:');
    console.log('- Code:', error.code);
    console.log('- Message:', error.message);
    console.log('- Position:', error.pos);
    console.log('- Line/Col:', error.linePos);
  }
}

// Document-level error handling
const doc = parseDocument(`
key1: value1
key1: duplicate_value  # DUPLICATE_KEY warning
invalid_alias: *nonexistent  # BAD_ALIAS error
`);

// Check for errors
if (doc.errors.length > 0) {
  console.log('Document Errors:');
  doc.errors.forEach((error, index) => {
    console.log(`${index + 1}. ${error.code}: ${error.message}`);
    if (error.pos) {
      console.log(`   Position: ${error.pos[0]}-${error.pos[1]}`);
    }
  });
}

// Check for warnings  
if (doc.warnings.length > 0) {
  console.log('Document Warnings:');
  doc.warnings.forEach((warning, index) => {
    console.log(`${index + 1}. ${warning.code}: ${warning.message}`);
  });
}

Error Position Information

Errors include detailed position information for precise error location.

interface LinePos {
  /** Line number (1-based) */
  line: number;
  /** Column number (1-based) */
  col: number;
}

type Range = [start: number, valueEnd: number, nodeEnd: number];

Usage Examples:

import { parseDocument, prettifyError } from "yaml";

const source = `
name: John Doe
age: thirty  # Invalid number
email: invalid-email  # Missing @ symbol
items:
  - item1
  - item2
    - nested_error  # Invalid nesting
`;

const doc = parseDocument(source, { prettyErrors: true });

// Display errors with context
doc.errors.forEach(error => {
  console.log('\n--- Error Details ---');
  console.log('Code:', error.code);
  console.log('Message:', error.message);
  
  if (error.pos) {
    console.log('Character range:', error.pos);
    
    // Extract error context
    const start = Math.max(0, error.pos[0] - 20);
    const end = Math.min(source.length, error.pos[1] + 20);
    const context = source.substring(start, end);
    
    console.log('Context:', JSON.stringify(context));
  }
  
  if (error instanceof YAMLParseError && error.linePos) {
    console.log(`Line ${error.linePos.line}, Column ${error.linePos.col}`);
  }
});

Error Formatting

Pretty error formatting with source context for better debugging experience.

/**
 * Add source context to error messages
 * @param source - Original YAML source string
 * @param lineCounter - Line position tracker
 * @returns Function to format errors with context
 */
function prettifyError(source: string, lineCounter: LineCounter): (error: YAMLError) => void;

class LineCounter {
  /**
   * Add new line to position tracking
   * @param offset - Character offset of new line
   */
  addNewLine(offset: number): void;
  
  /**
   * Get line and column position for character offset
   * @param pos - Character position
   * @returns Line and column numbers
   */
  linePos(pos: number): LinePos;
}

Usage Examples:

import { parseDocument, prettifyError, LineCounter } from "yaml";

const source = `
config:
  database:
    host: localhost
    port: "invalid_port"  # Should be number
    credentials:
      username: admin
      password: # Missing value
`;

// Parse with pretty errors enabled
const doc = parseDocument(source, { 
  prettyErrors: true,
  lineCounter: true 
});

// Errors are automatically prettified when prettyErrors: true
doc.errors.forEach(error => {
  console.log(error.message); // Includes formatted context
});

// Manual error prettification
const lineCounter = new LineCounter();
const prettyFormatter = prettifyError(source, lineCounter);

// Simulate parsing with line counter
source.split('\n').forEach((line, index) => {
  lineCounter.addNewLine(line.length + 1); // +1 for newline char
});

// Apply formatting to errors
doc.errors.forEach(prettyFormatter);

Logging System

Configurable logging for controlling error and warning output.

type LogLevelId = 'silent' | 'error' | 'warn' | 'debug';

/**
 * Debug-level logging function
 * @param logLevel - Current log level setting
 * @param messages - Messages to log
 */
function debug(logLevel: LogLevelId, ...messages: any[]): void;

/**
 * Warning-level logging function  
 * @param logLevel - Current log level setting
 * @param messages - Messages to log
 */
function warn(logLevel: LogLevelId, ...messages: any[]): void;

Usage Examples:

import { parseDocument, debug, warn } from "yaml";

// Configure logging levels
const quietDoc = parseDocument('key: value', { 
  logLevel: 'silent' // Suppress all output
});

const verboseDoc = parseDocument('key: value', { 
  logLevel: 'debug' // Show all messages
});

// Manual logging
warn('warn', 'This is a warning message');
debug('debug', 'This is a debug message', { additional: 'data' });

// Document with custom warning handling
const doc = parseDocument(`
key1: value1
key1: duplicate  # Will generate warning
`);

// Process warnings manually
doc.warnings.forEach(warning => {
  if (warning.code === 'DUPLICATE_KEY') {
    console.log('Found duplicate key:', warning.message);
  }
});

Error Recovery

The library continues parsing even when errors are encountered, providing maximum information about document issues.

import { parseDocument, parse } from "yaml";

// Malformed YAML with multiple errors
const malformedYaml = `
key1: value1
key2: [unclosed, array
key3: 
  nested: value
  key2: duplicate
invalid_anchor_ref: *missing
key4: "unclosed string
`;

// parseDocument continues despite errors
const doc = parseDocument(malformedYaml);

console.log('Parsed content:', doc.toJS()); // Returns what could be parsed
console.log('Error count:', doc.errors.length);
console.log('Warning count:', doc.warnings.length);

// parse() throws on first error
try {
  const data = parse(malformedYaml);
} catch (error) {
  console.log('Parse failed:', error.message);
}

// Graceful error handling with fallback
function safeParseYaml(source: string, fallback: any = {}) {
  try {
    return parse(source);
  } catch (error) {
    console.warn('YAML parse failed, using fallback:', error.message);
    return fallback;
  }
}

const config = safeParseYaml(malformedYaml, { defaultConfig: true });

Custom Error Handling

import { parseDocument, YAMLError, YAMLParseError, YAMLWarning } from "yaml";

class YAMLProcessor {
  private errors: YAMLError[] = [];
  private warnings: YAMLWarning[] = [];
  
  processDocument(source: string) {
    const doc = parseDocument(source, { logLevel: 'silent' });
    
    // Collect all issues
    this.errors.push(...doc.errors);
    this.warnings.push(...doc.warnings);
    
    // Custom error categorization
    const criticalErrors = this.errors.filter(e => 
      ['BAD_DIRECTIVE', 'IMPOSSIBLE'].includes(e.code)
    );
    
    const minorErrors = this.errors.filter(e => 
      ['DUPLICATE_KEY', 'TAB_AS_INDENT'].includes(e.code)
    );
    
    // Report based on severity
    if (criticalErrors.length > 0) {
      throw new Error(`Critical YAML errors: ${criticalErrors.length}`);
    }
    
    if (minorErrors.length > 0) {
      console.warn(`Minor YAML issues: ${minorErrors.length}`);
    }
    
    return doc;
  }
  
  getErrorReport() {
    return {
      totalErrors: this.errors.length,
      totalWarnings: this.warnings.length,
      errorsByCode: this.groupByCode(this.errors),
      warningsByCode: this.groupByCode(this.warnings)
    };
  }
  
  private groupByCode(issues: YAMLError[]) {
    return issues.reduce((acc, issue) => {
      acc[issue.code] = (acc[issue.code] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);
  }
}

// Usage
const processor = new YAMLProcessor();
try {
  const doc = processor.processDocument(malformedYaml);
  console.log('Processing completed with warnings');
} catch (error) {
  console.error('Processing failed:', error.message);
}

console.log('Error report:', processor.getErrorReport());

Install with Tessl CLI

npx tessl i tessl/npm-yaml

docs

ast-nodes.md

document-processing.md

error-handling.md

index.md

parse-stringify.md

parser-infrastructure.md

schema-configuration.md

tree-traversal.md

type-guards.md

utilities.md

tile.json