ABNF Parser Generator

raw JSON →
4.4.0 verified Tue Apr 21 auth: no javascript

JavaScript APG is a robust ABNF Parser Generator that enables developers to create recursive-descent parsers directly from a superset of ABNF (SABNF). It is currently stable at version 4.4.0, with a release cadence that has seen several updates in the past year, indicating active development and maintenance. Key differentiators include its ability to generate parsers for both standard `apg-js` and the more lightweight `apg-lite` framework, and its focus on fixing issues related to large grammars with mutually-recursive rules, a significant improvement over its predecessors like `apg-js2`. The library is designed to produce efficient parsers and provides options for TypeScript-compatible grammar objects, making it suitable for modern JavaScript and TypeScript environments.

error ReferenceError: Buffer is not defined
cause Prior to `apg-js@4.2.0`, the library relied on global Node.js objects like `Buffer` without explicit imports, causing issues in non-Node.js environments or when bundled.
fix
Upgrade apg-js to version 4.2.0 or higher to resolve direct global Node.js dependency issues.
error Build error with browserify when using `require('node:buffer')` or similar 'node:' prefixed imports.
cause Using the `node:` prefix with `require()` (e.g., `require('node:buffer')`) can cause compatibility problems with bundlers like `browserify`.
fix
The library itself fixed this in apg-js@4.2.0 by removing the node: prefix. Ensure your project and any custom tooling use the standard require('buffer') format where applicable.
error Parser fails or hangs unexpectedly on large or complex grammars with many mutually-recursive rules.
cause A major bug in the attributes algorithm of `apg-js2` and earlier versions could lead to parsing failures or performance issues with complex, mutually-recursive ABNF rules.
fix
Migrate your project to apg-js@4.0.0 or a newer version, which contains a corrected attributes algorithm, and retest your grammars.
breaking `apg-js` versions prior to 4.2.0 could cause bundling issues in browser environments or with specific bundlers due to reliance on `this` context for exported functions and direct use of Node.js globals like `Buffer` without explicit imports.
fix Upgrade to `apg-js@4.2.0` or newer, which explicitly imports Node.js globals and removes reliance on global `this` references.
breaking In `apg-js` versions prior to 4.2.1, ABNF zero repetitions (e.g., `0char`, `0"x"`) were inconsistently and often incorrectly processed as empty string acceptors, sometimes failing unexpectedly.
fix Upgrade to `apg-js@4.2.1` or newer for correct processing. However, prefer `""` for explicit empty strings as zero repetitions are deprecated.
deprecated The use of zero repetitions (e.g., `0"x"`) for empty string acceptance in ABNF grammars is deprecated, even though `apg-js` 4.2.1+ supports it correctly. Not all APG implementations accept it, and it is slightly less efficient.
fix Always use the empty literal string `""` for explicit empty string acceptors in your ABNF grammars.
breaking `apg-js` (version 4.x) is a complete rewrite and replacement for older packages like `apg-js2`, `apg-js2-lib`, `apg-js2-exp`, `apg-js2-api`, `apg-conv`, and `apg-conv-api`. It fixes a critical flaw in the attributes algorithm that could cause failures with large grammars and extensive mutual recursion in previous versions.
fix Migrate existing projects from `apg-js2` or related packages to `apg-js` and re-evaluate grammar definitions, as the API and internal behavior have changed significantly.
npm install apg-js
yarn add apg-js
pnpm add apg-js

Demonstrates defining a simple ABNF grammar programmatically and using `ApgParser` to parse input strings, logging success or failure.

import { ApgParser } from 'apg-js';

// Define a simple grammar object programmatically. In a real scenario,
// this would often be generated from an ABNF file using the apg-js generator.
// This grammar parses a list of digits separated by commas.
const grammar = {
    _grammar: 'SimpleList',
    callbacks: {
        list: () => {}, // No semantic action needed for this simple example
        element: () => {},
        digit: () => {}
    },
    rules: {
        list: {
            // list = element *("," element)
            op: [
                { type: 1, p: 'element' },
                { type: 2, p: [
                    { type: 7, p: ',' },
                    { type: 1, p: 'element' }
                ]}
            ]
        },
        element: {
            // element = 1*DIGIT
            op: [{ type: 5, min: 1, max: 0, p: 'digit' }]
        },
        digit: {
            // digit = %d48-57 ; '0'-'9'
            op: [{ type: 3, min: 48, max: 57 }]
        }
    },
    udts: {},
    operators: [],
    ast: {
        defined: false,
        nodes: []
    }
};

const parser = new ApgParser(grammar);

const inputString1 = "1,23,456";
const result1 = parser.parse(inputString1);

if (result1.success) {
    console.log(`Successfully parsed "${inputString1}"`);
} else {
    console.error(`Failed to parse "${inputString1}": ${result1.state.toString()}`);
}

const inputString2 = "1,23,A456"; // Invalid input
const result2 = parser.parse(inputString2);

if (result2.success) {
    console.log(`Successfully parsed "${inputString2}"`);
} else {
    console.error(`Failed to parse "${inputString2}": ${result2.state.toString()}`);
}