Skip to the content.

Library Reference

Complete API documentation for creating and managing .chalk libraries. This guide covers the redesigned, simplified API for defining libraries, elements, attribute types (including enumerations), and document classes.

Table of Contents

Overview

A .chalk library defines the structure and behaviour of your .chalk documents. Libraries contain:

Key Features

Definition Merging

One of the most powerful features of the .chalk library API is definition merging. When you call .element(), .type(), .enum(), or .document() multiple times with the same identifier, the definitions are merged rather than replaced.

How Merging Works

Element Merging Examples

// Base definition
lib.element({
  id: 'section',
  body: 'all',
  attributes: [
    { id: 'title', type: 'string' }
  ]
});

// Add detail policy and new attribute
lib.element({
  id: 'section',
  detail: 'literal',  // Adds detail policy
  attributes: [
    { id: 'id', type: 'string' }  // Adds new attribute
  ]
});

// Result: section has body='all', detail='literal', and both title and id attributes

Override Specific Attribute Properties

// Initial definition
lib.element({
  id: 'item',
  attributes: [
    { id: 'name', type: 'string', required: true },
    { id: 'count', type: 'number', default: 1 }
  ]
});

// Modify the name attribute
lib.element({
  id: 'item',
  attributes: [
    { id: 'name', type: 'string', required: false, aliases: ['title'] }
    // count attribute is preserved from first definition
  ]
});

// Result: name is now optional with an alias, count is unchanged

Overriding Primitives

// Add custom attributes to the built-in paragraph element
lib.element({
  id: 'paragraph',
  attributes: [
    { id: 'align', type: 'string', default: 'left' }
  ]
});

// Replace the built-in h1 parser
lib.element({
  id: 'h1',
  parser: (input) => {
    // Custom parsing logic
    return { ok: true, data: input.toUpperCase() };
  },
  parserPriority: 25  // Higher priority than default
});

// Result: paragraph has the new align attribute plus all primitive behaviour
// h1 uses the custom parser but keeps its body='literal' and other properties

Type Merging

lib.type({
  id: 'email',
  documentClasses: ['article']
});

lib.type({
  id: 'email',
  parse: (input) => {
    if (!input.includes('@')) return { error: 'Invalid email' };
    return { value: input.toLowerCase() };
  }
});

// Result: email type has both the parser and documentClasses

Enum Merging

lib.enum({
  id: 'status',
  values: ['draft', 'published'],
  documentClasses: ['article']
});

lib.enum({
  id: 'status',
  values: ['draft', 'published', 'archived']  // Override values
});

// Result: status has the new values but keeps documentClasses

Document Class Merging

lib.document({
  name: 'article',
  body: 'all',
  attributes: [
    { id: 'title', type: 'string', required: true }
  ]
});

lib.document({
  name: 'article',
  attributes: [
    { id: 'author', type: 'string', required: true }
  ]
});

// Result: article has body='all' and both title and author attributes

Multiple Chains

lib
  .element({
    id: 'widget',
    body: null,
    attributes: [{ id: 'a', type: 'string' }]
  })
  .element({
    id: 'widget',
    detail: 'literal',
    attributes: [{ id: 'b', type: 'string' }]
  })
  .element({
    id: 'widget',
    body: 'all',  // Override body
    attributes: [{ id: 'c', type: 'string' }]
  });

// Result: widget has body='all', detail='literal', and attributes a, b, and c

Best Practices

  1. Use merging for progressive refinement - Define base behaviour first, then add specifics
  2. Override primitives sparingly - Only when you need to fundamentally change behaviour
  3. Group related definitions - Keep merging calls close together in your code
  4. Document your intentions - Use comments when merging changes non-obvious behaviour

Creating a Library

chalk.library()

Creates a new library instance. Takes no parameters - document classes and other definitions are added via method chaining.

Signature:

chalk.library(): Library

Example:

import chalk from '@jackhgns/dotchalk';

// Create a library
const lib = chalk.library();

Defining Document Classes

lib.document(spec)

Defines a document class in the library. You can define multiple document classes, each with their own schema, attributes, body policy, and formatting configuration.

Signature:

lib.document(spec: {
  name: string;              // Required: document class name
  body?: ContentPolicy;      // Optional: what content is allowed in document body
  attributes?: AttributeSpec[];  // Optional: array of header attribute definitions
  config?: {                 // Optional: document-specific configuration
    formatting?: {
      bold?: boolean;        // Enable **bold** syntax (default: true)
      italic?: boolean;      // Enable *italic* syntax (default: true)
      code?: boolean;        // Enable `code` syntax (default: true)
      latex?: boolean;       // Enable $math$ syntax (default: true)
      links?: boolean;       // Enable [text](url) syntax (default: true)
    };
  };
}): Library

Parameters:

Examples:

// Simple document class
lib.document({
  name: 'article',
  body: 'all',
  attributes: [
    { id: 'title', type: 'string', required: true },
    { id: 'author', type: 'string' }
  ]
});

// Multiple document classes in one library
lib
  .document({
    name: 'tutorial',
    body: ['section', 'code', 'paragraph'],
    attributes: [
      { id: 'title', type: 'string', required: true },
      { id: 'difficulty', type: 'string' }
    ]
  })
  .document({
    name: 'blogPost',
    body: 'all',
    attributes: [
      { id: 'title', type: 'string', required: true },
      { id: 'author', type: 'string' },
      { id: 'published', type: 'boolean', default: false }
    ]
  });

// With custom formatting configuration
lib.document({
  name: 'mathPaper',
  body: 'all',
  attributes: [
    { id: 'title', type: 'string', required: true },
    { id: 'abstract', type: 'string' }
  ],
  config: {
    formatting: {
      latex: true,  // Enable LaTeX for math papers
      bold: true,
      italic: true,
      code: true,
      links: false  // Disable link syntax
    }
  }
});

Defining Elements

lib.element(spec)

Defines a new element in the library. Elements are the building blocks of documents and can be scoped to specific document classes.

Signature:

lib.element(spec: {
  id: string;                   // Required: element identifier
  aliases?: string[];           // Optional: alternative names
  body?: ContentPolicy;         // Optional: what content allowed in body
  detail?: ContentPolicy;       // Optional: what content allowed in detail
  attributes?: AttributeSpec[]; // Optional: array of attribute definitions
  parser?: (input: string) => Result<ElementContent>;  // Optional: custom parser
  parserPriority?: number;      // Optional: parser priority (higher = tried first, default: 0)
  documentClasses?: string[];   // Optional: scope to specific document classes
}): Library

Parameters:

Examples:

// Basic element with attributes
lib.element({
  id: 'section',
  aliases: ['sec'],
  body: ['paragraph', 'h1', 'h2'],
  attributes: [
    { id: 'title', type: 'string', required: true },
    { id: 'id', type: 'string' }
  ]
});

// Element with period-based namespacing
lib.element({
  id: 'ui.button',
  body: 'literal',
  attributes: [
    { id: 'variant', type: 'string', default: 'primary' }
  ]
});

// Deeply nested namespacing
lib.element({
  id: 'component.card.fancy',
  body: 'all',
  detail: 'literal',
  attributes: [
    { id: 'color', type: 'string' }
  ]
});
});

// Element with body and detail
lib.element({
  id: 'spoiler',
  body: ['paragraph'],   // Visible content
  detail: ['paragraph'], // Hidden content
  attributes: [
    { id: 'revealed', type: 'boolean', default: false }
  ]
});

// Scoped to specific document classes
lib.element({
  id: 'abstract',
  body: 'literal',
  attributes: [
    { id: 'wordCount', type: 'string' }
  ],
  documentClasses: ['article', 'mathPaper']  // Only in these document classes
});

// Element with custom parser
lib.element({
  id: 'link',
  aliases: ['lnk'],
  body: 'literal',
  attributes: [
    { id: 'url', type: 'string', required: true },
    { id: 'target', type: 'string' }
  ],
  parser: (input) => {
    // Custom parser for [text](url) syntax
    const match = input.match(/^\[(.+?)\]\((.+?)\)$/);
    if (!match) {
      return { ok: false, error: 'Invalid link syntax. Expected [text](url)' };
    }
    return { ok: true, data: match[1] };  // Return link text as body
  }
});

Defining Inline Elements

lib.inlineElement(spec)

Defines a new inline element in the library. Inline elements work within text content (paragraphs, headings, etc.) to provide formatting and semantic markup. They can use full syntax (!id{body}(attributes)) or optional shorthand notation.

Signature:

lib.inlineElement(spec: {
  id: string;                   // Required: inline element identifier
  aliases?: string[];           // Optional: alternative names
  body?: InlinePolicy;          // Optional: what inline content allowed in body
  attributes?: AttributeSpec[]; // Optional: array of attribute definitions
  shorthand?: string;           // Optional: shorthand delimiter (e.g., '===')
  documentClasses?: string[];   // Optional: scope to specific document classes
}): Library

Parameters:

Examples:

import chalk from '@jackhgns/dotchalk';

// Basic inline element with attributes
lib.inlineElement({
  id: 'highlight',
  body: chalk.inline('all'), // Allow nested inline elements
  attributes: [
    { id: 'color', type: 'string', default: 'yellow' }
  ]
});

// Usage: !highlight{important text}(color: pink)

// With custom shorthand
lib.inlineElement({
  id: 'highlight',
  body: chalk.inline('all'),
  shorthand: '===' // Custom delimiter
});

// Usage: ===highlighted text===

// No nesting allowed - literal text only
lib.inlineElement({
  id: 'abbr',
  body: chalk.inline(null), // No inline formatting
  attributes: [
    { id: 'title', type: 'string', required: true }
  ]
});

// Usage: !abbr{HTML}(title: HyperText Markup Language)

// Restricted nesting
lib.inlineElement({
  id: 'tooltip',
  body: chalk.inline(['bold', 'italic']), // Only bold and italic inside
  attributes: [
    { id: 'text', type: 'string', required: true }
  ]
});

// Scoped to specific document classes
lib.inlineElement({
  id: 'citation',
  body: chalk.inline(null),
  attributes: [
    { id: 'source', type: 'string', required: true }
  ],
  documentClasses: ['article', 'research']
});

Notes:

Defining Types

lib.type(spec)

Defines a custom attribute type with validation and parsing logic. Types can be scoped to specific document classes.

Attribute types are used to validate and transform attribute values. Both .type() and .enum() define attribute types—the difference is that .enum() provides a convenient shorthand for types that restrict values to a fixed set of strings, whilst .type() allows custom parsing logic for more complex validation.

Signature:

lib.type(spec: {
  id: string;                   // Required: type identifier
  parse?: (input: string) => any | { value: any; error?: string };  // Optional: parser
  documentClasses?: string[];   // Optional: scope to specific document classes
}): Library

Parameters:

Examples:

// Global type - available in all document classes
lib.type({
  id: 'email',
  parse: (input) => {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(input)) {
      return { error: 'Invalid email format' };
    }
    return { value: input.toLowerCase() };
  }
});

// Scoped type - only in specific document classes
lib.type({
  id: 'percentage',
  parse: (input) => {
    const num = parseFloat(input);
    if (num < 0 || num > 100) {
      return { error: 'Must be between 0 and 100' };
    }
    return { value: num };
  },
  documentClasses: ['mathPaper', 'article']
});

// Simple type without validation
lib.type({
  id: 'url'  // Accepts any string
});

Defining Enums

lib.enum(spec)

Defines an enumeration attribute type with a fixed set of allowed string values. Enums are a specialised category of attribute types that restrict values to a predefined list, providing compile-time validation. Like custom types, enums can be scoped to specific document classes and are referenced by their identifier in attribute definitions.

Enums are functionally equivalent to types with validation logic, but provide a cleaner syntax for the common case of restricting to a fixed set of values.

Signature:

lib.enum(spec: {
  id: string;                 // Required: enum identifier
  values: string[];           // Required: array of allowed values
  documentClasses?: string[]; // Optional: scope to specific document classes
}): Library

Parameters:

Examples:

// Global enum - available in all document classes
lib.enum({
  id: 'status',
  values: ['draft', 'published', 'archived']
});

// Scoped enum - only in specific document classes
lib.enum({
  id: 'difficulty',
  values: ['beginner', 'intermediate', 'advanced'],
  documentClasses: ['tutorial']
});

// Multiple enums
lib
  .enum({
    id: 'priority',
    values: ['low', 'medium', 'high', 'critical']
  })
  .enum({
    id: 'category',
    values: ['tech', 'design', 'business']
  });

Library Configuration

lib.config(options)

Updates the global configuration for the library. Settings specified here serve as defaults that can be overridden at the document class level.

Signature:

lib.config(options: {
  formatting?: {
    bold?: boolean;      // Enable **bold** syntax
    italic?: boolean;    // Enable *italic* syntax
    code?: boolean;      // Enable `code` syntax
    latex?: boolean;     // Enable $math$ syntax
    links?: boolean;     // Enable [text](url) syntax
  };
}): Library

Parameters:

Examples:

// Disable LaTeX and links globally
library.config({ 
  formatting: { 
    latex: false,
    links: false 
  } 
});

// Enable only basic formatting
library.config({
  formatting: {
    bold: true,
    italic: true,
    code: false,
    latex: false,
    links: false
  }
});

Document Classes and Scoping

Elements and attribute types (both custom types and enums) can be scoped to specific document classes using the documentClasses property. This allows you to create specialised definitions that only apply to certain document types.

Global Definitions

When documentClasses is omitted, the definition is available in all document classes:

lib.element({
  id: 'paragraph',
  body: 'literal',
  attributes: []
});
// Available in all document classes

Scoped Definitions

When documentClasses is specified, the definition is only available in those document classes:

lib.element({
  id: 'theorem',
  body: ['paragraph'],
  attributes: [
    { id: 'number', type: 'string' }
  ],
  documentClasses: ['mathPaper']  // Only in mathPaper documents
});

lib.type({
  id: 'difficulty',
  parse: (input) => {
    const valid = ['beginner', 'intermediate', 'advanced'];
    if (!valid.includes(input)) {
      return { error: 'Invalid difficulty level' };
    }
    return { value: input };
  },
  documentClasses: ['tutorial', 'course']  // Only in these document classes
});

Example: Multi-Document Library

const lib = chalk.library()
  // Define document classes
  .document({
    name: 'tutorial',
    body: 'all',
    attributes: [
      { id: 'title', type: 'string', required: true },
      { id: 'difficulty', type: 'string' }
    ]
  })
  .document({
    name: 'mathPaper',
    body: 'all',
    attributes: [
      { id: 'title', type: 'string', required: true },
      { id: 'abstract', type: 'string' }
    ],
    config: { formatting: { latex: true } }
  })
  
  // Scoped enum (tutorial only)
  .enum({
    id: 'difficulty',
    values: ['beginner', 'intermediate', 'advanced'],
    documentClasses: ['tutorial']
  })
  
  // Scoped element (tutorial only)
  .element({
    id: 'step',
    body: ['paragraph', 'code'],
    attributes: [
      { id: 'number', type: 'string' }
    ],
    documentClasses: ['tutorial']
  })
  
  // Scoped element (mathPaper only)
  .element({
    id: 'theorem',
    body: ['paragraph'],
    attributes: [
      { id: 'name', type: 'string' }
    ],
    documentClasses: ['mathPaper']
  })
  
  // Global element (all document classes)
  .element({
    id: 'note',
    body: 'literal',
    attributes: []
  });

// Compile as tutorial (has step, note, but NOT theorem)
const tutorialResult = chalk.compile(source, lib, 'tutorial');

// Compile as mathPaper (has theorem, note, but NOT step)
const paperResult = chalk.compile(source, lib, 'mathPaper');

Attribute Specifications

Attributes are defined using an array of attribute specification objects. This provides a clean, consistent format for all attribute definitions.

The type property references an attribute type identifier—this can be a built-in primitive type (like 'string', 'number', 'boolean'), a custom type defined with .type(), or an enumeration defined with .enum(). Both .type() and .enum() create attribute types that can be referenced by their id in attribute specifications.

AttributeSpec Format

interface AttributeSpec {
  id: string;           // Required: attribute identifier/name
  type?: string;        // Optional: attribute type (default: 'string')
  required?: boolean;   // Optional: whether attribute must be provided (default: false)
  default?: any;        // Optional: default value if not provided
  aliases?: string[];   // Optional: alternative names for this attribute
  description?: string; // Optional: human-readable description
}

Examples

// Basic attributes
lib.element({
  id: 'section',
  attributes: [
    { id: 'title', type: 'string', required: true },
    { id: 'id', type: 'string' }
  ]
});

// With defaults
lib.element({
  id: 'button',
  attributes: [
    { id: 'label', type: 'string', required: true },
    { id: 'type', type: 'string', default: 'primary' },
    { id: 'disabled', type: 'boolean', default: false }
  ]
});

// With aliases
lib.element({
  id: 'code',
  attributes: [
    { id: 'language', type: 'programmingLang' },
    { id: 'programming language', type: 'programmingLang' },  // Multi-word identifier
    { id: 'interactive', type: 'boolean', default: false },
    { id: 'is interactive', type: 'boolean' }  // Alias with spaces
  ]
});

// Document header attributes
lib.document({
  name: 'article',
  attributes: [
    { id: 'title', type: 'string', required: true },
    { id: 'author', type: 'string', required: true },
    { id: 'published', type: 'boolean', default: false },
    { id: 'published status', type: 'string' }  // Multi-word identifier
  ]
});

Multi-Word Identifiers

Attribute identifiers can contain spaces for improved readability:

lib.element({
  id: 'article',
  attributes: [
    { id: 'published status', type: 'string' },
    { id: 'is featured', type: 'boolean', default: false },
    { id: 'content type', type: 'string', default: 'article' }
  ]
});

Custom Parsers

For detailed information about creating custom parsers and controlling parser priority, see the Custom Parsers reference page.

Custom parsers allow you to define non-standard syntax for elements. You can control the order in which parsers are tried using the parserPriority property (default: 5, headings: 20, paragraphs: 0).

Quick Example:

lib.element({
  id: 'link',
  body: 'literal',
  attributes: [{ id: 'url', type: 'string' }],
  parserPriority: 15,  // Medium priority
  parser: (input) => {
    const match = input.match(/^\[(.+?)\]\((.+?)\)$/);
    if (!match) return { ok: false, error: 'Expected [text](url)' };
    return { ok: true, data: /* ... */ };
  }
});

See: Custom Parsers Reference for complete documentation on parser priority, best practices, and examples.

Content Policies

Content policies define what content is allowed in document bodies, element bodies, and element details.

Policy Types

Policy Description Empty Content Result Example
null No content allowed null detail: null
"literal" Raw text only, no parsing "" (empty string) body: "literal"
"all" All element types allowed null body: "all"
string[] Specific element types null body: ["paragraph", "h1", "h2"]

Note: When content is empty (e.g., {} or []), literal policy returns an empty string "" to preserve the explicit empty value, while other policies return null since there are no elements to contain.

Examples

Literal Text Only:

lib.element({
  id: 'code',
  body: 'literal',  // Body contains raw code, no parsing
  detail: null,     // No detail
  attributes: [
    { id: 'language', type: 'string' }
  ]
});

Specific Elements:

lib.element({
  id: 'section',
  body: ['paragraph', 'h1', 'h2', 'h3'],  // Only these elements allowed
  attributes: []
});

All Elements:

lib.element({
  id: 'container',
  body: 'all',  // Any element type allowed
  attributes: []
});

Body and Detail:

lib.element({
  id: 'spoiler',
  body: ['paragraph'],   // Body: visible content
  detail: ['paragraph'], // Detail: hidden content
  attributes: [
    { id: 'revealed', type: 'boolean', default: false }
  ]
});

Validating Libraries

Note: While the validateLibrary function can be called explicitly, it is automatically invoked by both compile and compileFile before any compilation occurs. Explicit validation is useful for testing library definitions or providing early feedback during library construction.

Validates a library definition to ensure it has at least one document class defined and that all definitions are internally consistent.

This function performs comprehensive validation checks:

Signature:

chalk.validateLibrary(library: Library): Result<void, string>

Parameters:

Returns: Result object with either success or validation error

Example:

import chalk from '@jackhgns/dotchalk';

const lib = chalk.library()
  .document({
    name: 'article',
    body: 'all',
    attributes: [
      { id: 'title', type: 'string', required: true },
      { id: 'author', type: 'string' }
    ]
  })
  .element({
    id: 'section',
    body: ['paragraph', 'h1', 'h2'],
    attributes: []
  });

const result = chalk.validateLibrary(lib);

if (result.ok) {
  console.log('Library is valid!');
} else {
  console.error('Library validation failed:', result.error);
}

Validation Errors:

The validator catches common mistakes:

// Error: No document class defined
const lib1 = chalk.library()
  .element({ id: 'note', body: 'literal', attributes: [] });

chalk.validateLibrary(lib1);
// Returns: { ok: false, error: 'Library must define at least one document class using .document()' }

// Error: Undefined type reference
const lib2 = chalk.library()
  .document({
    name: 'article',
    body: 'all',
    attributes: [
      { id: 'priority', type: 'priority-level' }  // 'priority-level' not defined
    ]
  });

chalk.validateLibrary(lib2);
// Returns: { ok: false, error: "Document 'article' attribute 'priority' references undefined type 'priority-level'" }

// Error: Undefined element in body policy
const lib3 = chalk.library()
  .document({
    name: 'tutorial',
    body: ['step', 'note'],  // 'step' not defined
    attributes: []
  });

chalk.validateLibrary(lib3);
// Returns: { ok: false, error: "Document 'tutorial' body policy references undefined element 'step'" }

Usage in Testing:

Library validation is particularly useful in testing scenarios:

describe('Library Definition', () => {
  test('should define a valid library', () => {
    const library = chalk.library()
      .document({ name: 'article', body: 'all', attributes: [] })
      .element({ id: 'note', body: 'literal', attributes: [] });
    
    const result = chalk.validateLibrary(library);
    expect(result.ok).toBe(true);
  });
  
  test('should catch missing type definitions', () => {
    const library = chalk.library()
      .document({
        name: 'report',
        body: 'all',
        attributes: [{ id: 'status', type: 'report-status' }]
      });
    
    const result = chalk.validateLibrary(library);
    expect(result.ok).toBe(false);
    expect(result.error).toContain('undefined type');
  });
});

Complete Examples

Blog Library

import chalk from '@jackhgns/dotchalk';

// Create library
const blogLib = chalk.library()
  .document({
    name: 'blog-post',
    body: 'all',
    attributes: [
      { id: 'title', type: 'string', required: true },
      { id: 'author', type: 'string', required: true },
      { id: 'date', type: 'string', required: true },
      { id: 'status', type: 'status', default: 'draft' },
      { id: 'category', type: 'category' },
      { id: 'featured', type: 'boolean', default: false }
    ],
    config: {
      formatting: {
        bold: true,
        italic: true,
        code: true,
        latex: false,
        links: true
      }
    }
  });

// Define enums
blogLib
  .enum({
    id: 'status',
    values: ['draft', 'published', 'archived']
  })
  .enum({
    id: 'category',
    values: ['tech', 'design', 'business']
  });

// Define elements
blogLib
  .element({
    id: 'section',
    aliases: ['sec'],
    body: ['paragraph', 'h2', 'h3'],
    detail: ['paragraph'],
    attributes: [
      { id: 'title', type: 'string', required: true },
      { id: 'id', type: 'string' }
    ]
  })
  .element({
    id: 'callout',
    body: 'literal',
    attributes: [
      { id: 'type', type: 'string', default: 'info' },
      { id: 'title', type: 'string' }
    ]
  })
  .element({
    id: 'image',
    aliases: ['img'],
    body: 'literal',
    attributes: [
      { id: 'src', type: 'string', required: true },
      { id: 'alt', type: 'string', required: true },
      { id: 'caption', type: 'string' }
    ]
  });

// Use the library
const result = chalk.compile(`
*(
  title: My Blog Post
  author: John Doe
  date: 2025-12-21
  status: published
)

section{
  This is an **introduction** with *inline* formatting and \`code\`.
}[
  This is a side column detail.
](
  title: Introduction
)

callout{
  Don't forget to save your work!
}(
  type: warning
  title: Important
)

img{
  A beautiful landscape
}(
  src: photo.jpg
  alt: A photo
)
`, blogLib, 'blog-post');

Technical Documentation Library

import chalk from '@jackhgns/dotchalk';

// Create library
const docsLib = chalk.library()
  .document({
    name: 'documentation',
    body: 'all',
    attributes: [
      { id: 'title', type: 'string', required: true },
      { id: 'version', type: 'string', required: true },
      { id: 'api version', type: 'string' }  // Multi-word identifier
    ]
  });

// Custom enum for programming languages
docsLib.enum({
  id: 'lang',
  values: [
    'javascript', 'typescript', 'python', 'java', 
    'csharp', 'go', 'rust'
  ]
});

// Code block element
docsLib.element({
  id: 'code',
  body: 'literal',
  attributes: [
    { id: 'language', type: 'lang', default: 'javascript' },
    { id: 'filename', type: 'string' },
    { id: 'highlight lines', type: 'string' }
  ]
});

// API reference element
docsLib.element({
  id: 'api',
  body: ['paragraph'],
  detail: 'literal',
  attributes: [
    { id: 'method', type: 'string', required: true },
    { id: 'endpoint', type: 'string', required: true },
    { id: 'auth required', type: 'boolean', default: false }
  ]
});

Interactive Content Library with Custom Parser

import chalk from '@jackhgns/dotchalk';

const interactiveLib = chalk.library()
  .document({
    name: 'interactive',
    body: 'all',
    attributes: [
      { id: 'title', type: 'string', required: true },
      { id: 'interactive', type: 'boolean', default: true }
    ]
  });

// Link element with custom parser for markdown syntax
interactiveLib.element({
  id: 'link',
  aliases: ['lnk'],
  body: 'literal',
  attributes: [
    { id: 'url', type: 'string', required: true },
    { id: 'target', type: 'string' }
  ],
  parserPriority: 50,  // Medium priority - try before paragraphs
  parser: (input) => {
    // Custom parser for [text](url) syntax
    const match = input.match(/^\[(.+?)\]\((.+?)\)$/);
    if (!match) {
      return { ok: false, error: 'Invalid link syntax. Expected [text](url)' };
    }
    // Return just the link text as the body content
    return {
      ok: true,
      data: match[1]
    };
  }
});

// Quiz element with body and detail
interactiveLib.element({
  id: 'quiz',
  body: ['paragraph'],  // Body: question
  detail: 'literal',    // Detail: answer
  attributes: [
    { id: 'type', type: 'string', default: 'multiple-choice' },
    { id: 'points', type: 'string', default: '1' }
  ]
});

// Poll element
interactiveLib.element({
  id: 'poll',
  body: ['paragraph'],
  attributes: [
    { id: 'question', type: 'string', required: true },
    { id: 'options', type: 'string', required: true },
    { id: 'multi select', type: 'boolean', default: false }
  ]
});

Multi-Document Library with Scoping

import chalk from '@jackhgns/dotchalk';

const academicLib = chalk.library()
  // Define multiple document classes
  .document({
    name: 'tutorial',
    body: 'all',
    attributes: [
      { id: 'title', type: 'string', required: true },
      { id: 'difficulty', type: 'difficulty' },
      { id: 'estimated time', type: 'string' }
    ]
  })
  .document({
    name: 'mathPaper',
    body: 'all',
    attributes: [
      { id: 'title', type: 'string', required: true },
      { id: 'authors', type: 'string', required: true },
      { id: 'abstract', type: 'string' }
    ],
    config: {
      formatting: { latex: true }
    }
  })
  .document({
    name: 'article',
    body: 'all',
    attributes: [
      { id: 'title', type: 'string', required: true },
      { id: 'author', type: 'string' }
    ]
  })
  
  // Scoped enum (tutorial only)
  .enum({
    id: 'difficulty',
    values: ['beginner', 'intermediate', 'advanced'],
    documentClasses: ['tutorial']
  })
  
  // Scoped elements
  .element({
    id: 'step',
    body: ['paragraph', 'code'],
    attributes: [
      { id: 'number', type: 'string' }
    ],
    documentClasses: ['tutorial']  // Only in tutorials
  })
  .element({
    id: 'theorem',
    body: ['paragraph'],
    attributes: [
      { id: 'name', type: 'string', required: true },
      { id: 'number', type: 'string' }
    ],
    documentClasses: ['mathPaper']  // Only in math papers
  })
  .element({
    id: 'proof',
    body: ['paragraph'],
    attributes: [],
    documentClasses: ['mathPaper']  // Only in math papers
  })
  
  // Global elements (all document classes)
  .element({
    id: 'note',
    body: 'literal',
    attributes: [
      { id: 'type', type: 'string', default: 'info' }
    ]
  })
  .element({
    id: 'section',
    aliases: ['sec'],
    body: ['paragraph', 'h2', 'h3'],
    attributes: [
      { id: 'title', type: 'string', required: true }
    ]
  });

// Compile with different document classes
const tutorial = chalk.compile(tutorialSource, academicLib, 'tutorial');
const paper = chalk.compile(paperSource, academicLib, 'mathPaper');
const article = chalk.compile(articleSource, academicLib, 'article');

Best Practices

1. Use Meaningful Identifiers

// Good
lib.element({
  id: 'user-profile',
  attributes: [
    { id: 'display-name', type: 'string' }
  ]
});

// Avoid
lib.element({
  id: 'e1',
  attributes: [
    { id: 'a', type: 'string' }
  ]
});

2. Use Enums for Fixed Sets

// Good - constrains values
lib.enum({
  id: 'priority',
  values: ['low', 'medium', 'high']
});

lib.element({
  id: 'task',
  attributes: [
    { id: 'priority', type: 'priority', default: 'medium' }
  ]
});

// Avoid - allows any string
lib.element({
  id: 'task',
  attributes: [
    { id: 'priority', type: 'string' }
  ]
});

3. Use Aliases for Common Shortcuts

lib.element({
  id: 'section',
  aliases: ['sec', 's'],  // Allow 'sec{...}' and 's{...}'
  body: 'all',
  attributes: []
});

4. Multi-Word Identifiers

Attribute identifiers can contain spaces for readability:

lib.element({
  id: 'article',
  attributes: [
    { id: 'published status', type: 'string' },
    { id: 'is featured', type: 'boolean', default: false },
    { id: 'content type', type: 'string', default: 'article' }
  ]
});

5. Method Chaining

Take advantage of method chaining for cleaner code:

const lib = chalk.library()
  .document({ name: 'article', body: 'all', attributes: [...] })
  .element({ id: 'section', body: ['paragraph'], attributes: [...] })
  .element({ id: 'callout', body: 'literal', attributes: [...] })
  .enum({ id: 'status', values: ['draft', 'published'] })
  .type({ id: 'email', parse: emailParser });

6. Scope Wisely

Use document class scoping to create specialised elements:

// Global - use for common elements
lib.element({
  id: 'paragraph',
  body: 'literal',
  attributes: []
});

// Scoped - use for specialised elements
lib.element({
  id: 'theorem',
  body: ['paragraph'],
  attributes: [{ id: 'name', type: 'string' }],
  documentClasses: ['mathPaper']
});

Type Definitions Reference

For complete TypeScript type definitions of all interfaces and types used in the library API, see the Type Reference page.

Key Types: