npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

pegjs-template

v1.4.0

Published

Build PEG.js grammars using template strings.

Downloads

3

Readme

pegjs-template

Build PEG.js grammars using template strings.

PEG.js grammars are normally just strings; semantic actions are specified using JavaScript embedded in the string. This library allows you to write semantic actions using real JavaScript functions. This has several advantages:

  • Syntax highlighting works.
  • Code completion and other code intelligence features work.
  • Semantic actions can be written in TypeScript, allowing them to be type checked.
  • Semantic actions can easily reference variables or APIs defined outside the grammar, without any awkward workarounds like passing them in via the context.

In addition, pegjs-template allows you to write partial grammars. These are small grammars that can be merged together to make a complete grammar. This allows you to make your grammars modular and factor out shared code so that it can be reused in multiple grammars.

pegjs-template is a better way to write PEG.js grammars!

Basic usage

Use the pegGrammar function exported by this library as a template tag function and interpolate your semantic actions in as functions. If you're using the library from TypeScript, you'll need to provide a type parameter for pegGrammar; this is the type of the AST that your parser returns.

Semantic action functions must have this type:

type Action = (context: ActionContext, ...labels: any[]) => any;

The first argument to your semantic action will be an ActionContext object containing the standard PEG.js helpers:

export type PEGActionContext = {
  /** @returns the text matched by the current rule. */
  text(): string;

  /** @returns the source range matched by the current rule. */
  location(): SourceLocation;

  /** Throw an exception indicating that 'expected' was expected but not found. */
  expected(expected: string, location?: SourceLocation): never;

  /** Throw an exception with the error message 'message'. */
  error(message: string, location?: SourceLocation): never;

  /** Options passed to the parser. */
  options: Record<string, any>;
};

The remaining arguments are the semantic values for the labeled expressions in the current rule. Note that, while the context argument can be named anything, the label argument names must match the label names in the grammar exactly!

One limitation to be aware of: this library parses the argument list of your semantic action functions using a simple regular expression. Don't try to get fancy with destructuring or rest parameters in the argument list; they won't work the way you expect.

An example's worth a thousand words, so here's the arithmetic grammar example from the PEG.js docs, rewritten to use this library:

import { pegGrammar } from 'pegjs-template';

const parser = pegGrammar<number>`
// Simple Arithmetics Grammar
// ==========================
//
// Accepts expressions like "2 * (3 + 4)" and computes their value.

Expression
  = head:Term tail:(_ ("+" / "-") _ Term)* ${(_, head, tail) => {
      return tail.reduce(function(result, element) {
        if (element[1] === "+") { return result + element[3]; }
        if (element[1] === "-") { return result - element[3]; }
      }, head);
    }}

Term
  = head:Factor tail:(_ ("*" / "/") _ Factor)* ${(_, head, tail) => {
      return tail.reduce(function(result, element) {
        if (element[1] === "*") { return result * element[3]; }
        if (element[1] === "/") { return result / element[3]; }
      }, head);
    }}

Factor
  = "(" _ expr:Expression _ ")" ${(_, expr) => expr}
  / Integer

Integer "integer"
  = _ [0-9]+ ${(ctx) => parseInt(ctx.text(), 10)}

_ "whitespace"
  = [ \t\n\r]*
`;

parser.parse('2 * (3 + 4)');  // Returns '14'.

Partial grammars

You can create a partial grammar using the pegPartialGrammar function exported by this library. It's also a template tag function that works just like pegGrammar, except that instead of returning a parser it returns a PartialGrammar object.

You can interpolate PartialGrammar objects into other grammars using either pegGrammar or pegPartialGrammar. The result is just like you interpolated the source code into the grammar as text, except that any semantic action functions you defined in JavaScript come along for the ride. This makes it easy to combine smaller grammars into larger grammars while retaining all the benefits of defining your semantic actions in JavaScript.

Generate options

pegGrammar automatically calls PEG.js's generate() function for you to generate a parser from your grammar. This means that you can't provide options to generate() in the usual way. Normally the defaults are fine, but if you do need to provide options - for example, to enable tracing - you can use pegGenerateOptions(). This function accepts the same options argument that generate() does. It returns a GenerateOptions object that you can interpolate into your grammar using pegGrammar or pegPartialGrammar. This doesn't change the grammar source code itself, but the options will be recognized and passed to generate() as you'd expect.

There is one limitation: you can only interpolate one GenerateOptions object into your grammar. pegGrammar will throw an exception if you try to include more than one.