Parser generator for JavaScript that produces fast parsers with excellent error reporting capabilities
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Command-line tools for generating parsers, testing grammars, and working with Peggy from the terminal. The Peggy CLI provides comprehensive functionality for parser development workflows.
Main command-line interface class that handles argument parsing and command execution.
class PeggyCLI extends Command {
/**
* Create CLI instance with optional custom stdio streams
* @param stdio - Custom streams for testing (optional)
*/
constructor(stdio?: Stdio);
/**
* Parse command line arguments asynchronously
* @returns Promise resolving to configured CLI instance
* @throws {CommanderError} If command line arguments are invalid
*/
parseAsync(): Promise<PeggyCLI>;
/**
* Execute the main CLI functionality
* @returns Promise resolving to exit code (0 for success, 1 for error)
*/
main(): Promise<number>;
/** Parser options for generation */
parserOptions: SourceOptionsBase<"ast">;
/** Program options for execution */
progOptions: ProgOptions;
/** Standard input/output streams */
std: Stdio;
}
/**
* Standard I/O interface for CLI
*/
interface Stdio {
in: Readable;
out: Writable;
err: Writable;
}
/**
* Command-line parsing error
*/
class CommanderError extends Error {
code: string;
exitCode: number;
}
/**
* Invalid argument error
*/
class InvalidArgumentError extends CommanderError {
argument: string;
value: any;
reason: string;
}Basic CLI Usage:
# Generate parser from grammar file
peggy grammar.peggy
# Generate parser with specific output file
peggy grammar.peggy -o parser.js
# Generate CommonJS module
peggy grammar.peggy --format commonjs
# Generate with allowed start rules
peggy grammar.peggy --allowed-start-rules rule1,rule2,rule3
# Enable caching for better performance
peggy grammar.peggy --cache
# Generate with tracing enabled
peggy grammar.peggy --traceThe Peggy CLI supports extensive options for configuring parser generation:
# Input and Output
peggy [options] [input_file...] # Grammar files to read (default: stdin)
peggy [options] <grammar_file> -o <output_file>
# Format Options
--format <format> # Output format: amd, bare, commonjs, es, globals, umd (default: commonjs)
-e, --export-var <variable> # Global variable name (for globals/umd formats)
# Parser Options
--allowed-start-rules <rules> # Comma-separated list of allowed start rules (use '*' for all)
--cache # Enable result caching for better performance
--trace # Enable parser tracing for debugging
# Module Dependencies
-d, --dependency <dependency> # Module dependency (format: variable:module)
-D, --dependencies <json> # Dependencies as JSON object
# Output Control
-o, --output <file> # Output file (default: auto-generated from input)
--ast # Output grammar AST instead of parser code
--dts # Create TypeScript declaration file
# Source Maps
-m, --source-map [mapfile] # Generate source map file or inline
# Testing and Development
-t, --test <text> # Test parser with given text
-T, --test-file <filename> # Test parser with file contents
-S, --start-rule <rule> # Start rule for testing
-w, --watch # Watch input files and regenerate on changes
# Advanced Options
--plugin <module> # Load plugin modules
--extra-options <options> # Additional JSON options for generate()
-c, --extra-options-file <file> # Load additional options from file
--return-types <typeInfo> # Type information for rules (JSON)
--verbose # Enable verbose logging
# Help and Information
-h, --help # Display help information
-v, --version # Display version numberAdvanced CLI Examples:
# Generate ES module with dependencies
peggy grammar.peggy \
--format es \
--dependency "fs:fs" \
--dependency "path:path" \
-o parser.mjs
# Generate UMD module with global variable
peggy grammar.peggy \
--format umd \
--export-var MyParser \
-o parser.umd.js
# Generate with multiple start rules and caching
peggy grammar.peggy \
--allowed-start-rules "expression,statement,program" \
--cache \
--trace \
-o parser.js
# Generate source with inline source map
peggy grammar.peggy \
--output-format source-with-inline-map \
-o parser.jsThe CLI provides detailed error reporting for both command-line and grammar errors:
# Grammar syntax errors
$ peggy invalid.peggy
Error: Expected "!", "$", "&", "(", ".", "@", character class, comment, end of line, identifier, literal, or whitespace but "#" found.
--> invalid.peggy:3:9
|
3 | start = # 'a';
| ^
# Grammar semantic errors
$ peggy undefined-rule.peggy
Error: Rule "undefined_rule" is not defined
--> undefined-rule.peggy:1:9
|
1 | start = undefined_rule
| ^^^^^^^^^^^^^
# Command line errors
$ peggy --format invalid grammar.peggy
Error: Invalid format: invalid
Valid formats: amd, bare, commonjs, es, globals, umd
$ peggy --allowed-start-rules nonexistent grammar.peggy
Error: Unknown start rule "nonexistent"Using the CLI classes programmatically for custom build tools and integrations:
import { PeggyCLI, CommanderError, InvalidArgumentError } from "peggy/bin/peggy.js";
async function generateParser(args: string[]): Promise<number> {
try {
// Create CLI instance with custom arguments
process.argv = ["node", "peggy", ...args];
const cli = new PeggyCLI();
await cli.parseAsync();
// Execute CLI functionality
const exitCode = await cli.main();
return exitCode;
} catch (error) {
if (error instanceof CommanderError) {
console.error("CLI Error:", error.message);
return error.exitCode;
} else if (error instanceof InvalidArgumentError) {
console.error(`Invalid argument ${error.argument}: ${error.reason}`);
return 1;
} else {
console.error("Unexpected error:", error);
return 1;
}
}
}Programmatic Usage Example:
import { PeggyCLI } from "peggy/bin/peggy.js";
async function buildParser() {
// Simulate command line arguments
const args = [
"my-grammar.peggy",
"--format", "commonjs",
"--cache",
"--allowed-start-rules", "expression,statement",
"-o", "dist/parser.js"
];
const exitCode = await generateParser(args);
if (exitCode === 0) {
console.log("Parser generated successfully");
} else {
console.error("Parser generation failed");
}
}Examples of integrating Peggy CLI with common build tools:
npm scripts (package.json):
{
"scripts": {
"build:parser": "peggy src/grammar.peggy -o lib/parser.js --format commonjs --cache",
"build:parser:es": "peggy src/grammar.peggy -o dist/parser.mjs --format es",
"build:parsers": "npm run build:parser && npm run build:parser:es",
"watch:parser": "nodemon --watch src/grammar.peggy --exec 'npm run build:parser'"
},
"devDependencies": {
"peggy": "^5.0.6",
"nodemon": "^3.0.0"
}
}Makefile:
# Parser generation targets
lib/parser.js: src/grammar.peggy
peggy $< -o $@ --format commonjs --cache
dist/parser.mjs: src/grammar.peggy
peggy $< -o $@ --format es
dist/parser.umd.js: src/grammar.peggy
peggy $< -o $@ --format umd --export-var MyParser
# Build all parser variants
parsers: lib/parser.js dist/parser.mjs dist/parser.umd.js
# Clean generated files
clean:
rm -f lib/parser.js dist/parser.mjs dist/parser.umd.js
.PHONY: parsers cleanGulp task:
const { spawn } = require('child_process');
const gulp = require('gulp');
function buildParser() {
return new Promise((resolve, reject) => {
const peggy = spawn('peggy', [
'src/grammar.peggy',
'-o', 'lib/parser.js',
'--format', 'commonjs',
'--cache'
]);
peggy.on('close', (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`Peggy exited with code ${code}`));
}
});
});
}
gulp.task('parser', buildParser);
gulp.task('watch:parser', () => {
gulp.watch('src/grammar.peggy', gulp.series('parser'));
});While Peggy CLI doesn't support configuration files directly, you can create wrapper scripts for complex configurations:
peggy-config.js:
#!/usr/bin/env node
const { PeggyCLI } = require('peggy/bin/peggy.js');
const configurations = {
development: [
'src/grammar.peggy',
'--format', 'commonjs',
'--trace',
'--cache',
'-o', 'lib/parser.dev.js'
],
production: [
'src/grammar.peggy',
'--format', 'es',
'--cache',
'-o', 'dist/parser.js'
],
browser: [
'src/grammar.peggy',
'--format', 'umd',
'--export-var', 'MyParser',
'-o', 'dist/parser.umd.js'
]
};
async function build(env = 'development') {
const config = configurations[env];
if (!config) {
console.error(`Unknown environment: ${env}`);
process.exit(1);
}
process.argv = ['node', 'peggy', ...config];
try {
const cli = new PeggyCLI();
await cli.parseAsync();
const exitCode = await cli.main();
process.exit(exitCode);
} catch (error) {
console.error('Build failed:', error.message);
process.exit(1);
}
}
// Usage: node peggy-config.js [development|production|browser]
const env = process.argv[2] || 'development';
build(env);Usage:
# Use configuration script
node peggy-config.js development
node peggy-config.js production
node peggy-config.js browser
# Or add to package.json scripts
npm run build:dev # node peggy-config.js development
npm run build:prod # node peggy-config.js production
npm run build:browser # node peggy-config.js browserInstall with Tessl CLI
npx tessl i tessl/npm-peggy