Skip to content

Repository files navigation

ferronconf

A TypeScript library for parsing, querying, and serializing ferron.conf configuration files — the domain-specific language used by the Ferron web server. Based on the reference implementation written in Rust.

Installation

npm install ferronconf

Usage

Parse a configuration file

import { parse } from "ferronconf";

const config = parse(`
example.com {
    root /var/www/example

    if curl_client {
        use set_curl
    }
}
`);

The result is a Config AST that can be inspected programmatically.

Find directives

import { findDirectives, getStringArg } from "ferronconf";

const blocks = findHostBlocks(config);
for (const block of blocks) {
    const roots = findDirectives(block.block, "root");
    for (const root of roots) {
        console.log(getStringArg(root, 0)); // /var/www/example
    }
}

Find host blocks

import { findHostBlocks, hostPatternToString, matchesHost } from "ferronconf";

const blocks = findHostBlocks(config);

// Iterate over all host blocks
for (const block of blocks) {
    for (const host of block.hosts) {
        console.log(hostPatternToString(host)); // "example.com" or "127.0.0.1:8080"
    }
}

// Check if a block matches a host
if (matchesHost(blocks[0], "example.com")) {
    // ...
}

Find match blocks

import { findMatchBlocks, isRegexExpr, operandAsIdentifier, operandAsString } from "ferronconf";

const matchBlocks = findMatchBlocks(config);
for (const block of matchBlocks) {
    if (block.matcher === "curl_client") {
        for (const expr of block.expressions) {
            if (isRegexExpr(expr)) {
                const path = operandAsIdentifier(expr.left)?.join(".");
                const pattern = operandAsString(expr.right);
                console.log(`${path} ~ ${pattern}`);
            }
        }
    }
}

Serialize back to text

import { display } from "ferronconf";

const text = display(config);
// Round-trip: parse → display → re-parse is guaranteed to be lossless.
const reparsed = parse(text);

Working with directive arguments

import { findDirectives, getStringArg, getIntegerArg, getBooleanArg, valueAsInteger } from "ferronconf";

const directives = findDirectives(config, "my_directive");
for (const d of directives) {
    // Type-safe accessors (return undefined on type mismatch):
    const str = getStringArg(d, 0);   // string | undefined
    const num = getIntegerArg(d, 0);  // number | undefined
    const bool = getBooleanArg(d, 0); // boolean | undefined

    // Low-level access with type narrowing:
    if (d.args[0]?.kind === "integer") {
        console.log(`Value: ${d.args[0].value}`);
    }
}

API

Core functions

Function Description
parse(input: string): Config Parse a ferron.conf string into an AST. Throws ParseError on invalid input.
display(config: Config): string Serialize a Config AST back to text. The output is guaranteed to re-parse to an equivalent AST.

Query functions

Function Description
findDirectives(config, name) Find all top-level directives by name.
findDirectivesInBlock(block, name) Find all directives in a block by name.
findDirectiveInBlock(block, name) Find the first matching directive in a block.
findHostBlocks(config) Find all host blocks.
findMatchBlocks(config) Find all match blocks.
getStringArg(directive, index) Get an argument as a string (returns undefined if wrong type).
getIntegerArg(directive, index) Get an argument as an integer.
getBooleanArg(directive, index) Get an argument as a boolean.
matchesHost(hostBlock, host) Check if a host block matches a given host string.

Value & operand helpers

Function Description
valueAsString(val) Extract string value.
valueAsInteger(val) Extract integer value.
valueAsFloat(val) Extract float value.
valueAsBoolean(val) Extract boolean value.
valueAsInterpolatedString(val) Extract interpolated string parts.
operandAsString(op) Extract operand as string.
operandAsInteger(op) Extract operand as integer.
operandAsFloat(op) Extract operand as float.
operandAsIdentifier(op) Extract operand as identifier path.
isComment(stmt) Check if a statement is a comment.

Operator helpers

Function Description
operatorToString(op) Render operator as text (==, !=, ~, !~, in).
isComparison(op) true for == or !=.
isRegexOp(op) true for ~ or !~.

Matcher expression helpers

Function Description
isEquality(expr) true if expression uses ==.
isInequality(expr) true if expression uses !=.
isRegexExpr(expr) true if expression uses ~ or !~.

Host helpers

Function Description
hostLabelsToString(labels) Render host labels as text (e.g. example.com, [::1], *).
hostPatternToString(hp) Render host pattern without protocol (e.g. example.com:8080).
hostPatternToFullString(hp) Render host pattern with protocol (e.g. http example.com).
getHostPatterns(hb) Get all host patterns as full strings.
stringPartToString(part) Render an interpolated string part back to source form.

Types

Key AST types exported:

  • Config — root node with statements, trailingComments, blankLinesBefore
  • Statement — discriminated union: directive, hostBlock, matchBlock, globalBlock, snippetBlock, comment
  • Directivename, args: Value[], block: Block | null
  • HostBlockhosts: HostPattern[], block: Block
  • MatchBlockmatcher: string, expressions: MatcherExpression[]
  • Blockstatements: Statement[]
  • Value — discriminated union: string, integer, float, boolean, interpolated
  • HostLabels — discriminated union: hostname, ipAddr, wildcard
  • ParseError — thrown on parse failures, has span: { line, column }

Configuration Syntax

ferron.conf is a block-structured configuration language. Key features:

  • Directivesname value1 value2 { ... }
  • Host blocksexample.com:8080 { ... }, [::1] { ... }, * { ... }
  • Matchersmatch name { expr ~ pattern }
  • Snippetssnippet name { ... }
  • Global blocks{ ... }
  • Strings"quoted", r"raw", bare
  • Interpolation"prefix {{ path.to.var }} suffix"
  • Comments# line comment
  • Operators==, !=, ~, !~, in

License

MIT

About

A TypeScript library for parsing, querying, and serializing ferron.conf files

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages