mrkeyoor.com_
Wed 23 Sept 00:32 UTC
npmUtilsupdated 22 Sept 2026

parse-statements review

parse-statements 1.0.14 scans source text for non-overlapping sequences of regex tokens. You describe each statement and comment delimiter, then callbacks receive the matched offsets and mutate a context object supplied by the caller. It can pull imports, directives, or other predictable fragments from many text formats, but it has no grammar, AST, nesting model, or language validation. Our full browser import measured 3.4 KB minified and 1.4 KB gzipped. The current release repairs CommonJS output and Node 10 exports after 1.0.13 added a public `CreateParseFunction` type and CJS tests.

Verdict

parse-statements 1.0.14 installed in 0.8 seconds with 0 dependencies and produced a 1.4 KB gzipped browser bundle in our sandbox, making it cheap for fixed token-sequence extraction. Use a language parser once nesting, overlap, backtracking, or syntax correctness enters the requirement.

We installed it

Lab card: what happened when we installed parse-statementsScreenshot of parse-statements documentation
Install✓ · 0.8s1 package on disk · 1 MB
ImportESM import works · require() works · ESM package with exports map
Browser1.4 KBgzipped (3.4 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does parse-statements install cleanly?

Yes. In a fresh container with an empty cache, npm install parse-statements finished in 0.8s, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.

How much does parse-statements add to a browser bundle?

1.4 KB gzipped (3.4 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does parse-statements work with both ESM and CommonJS?

Yes. Both import 'parse-statements' and require('parse-statements') worked in Node 22 in our run. The package is published as ESM with an exports map.

Does parse-statements include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

parse-statements or esprima: which should you use?

esprima: Use it when JavaScript input needs an ESTree syntax tree. parse-statements 1.0.14 installed in 0.8 seconds with 0 dependencies and produced a 1.4 KB gzipped browser bundle in our sandbox, making it cheap for fixed token-sequence extraction.

When should you not use parse-statements?

Correct JavaScript, TypeScript, SQL, or CSS syntax matters. Regex token chains cannot replace that language's parser or produce an AST.

API stability4/5Version 1.0.14 exposes one runtime factory, `createParseFunction`, and keeps parser behavior in typed statement and comment descriptors. The 1.x line has added options such as `regexpFlags`, `shouldSearchBeforeComments`, and callback end-index overrides without replacing the original callback model. The recent CJS build fix shows that packaging, rather than the parsing contract, is the likelier source of breakage.
Docs3/5The README specifies the `gmu` defaults, offset objects, incomplete-statement behavior, comment attachment, precedence option, custom end positions, runtime floor, and every exported type. Its import and export example is detailed enough to copy into a test. The drawback is presentation: one long page carries both tutorial and reference material, with few short recipes for malformed text or competing tokens.
Maintenance4/5npm published 1.0.13 on August 9, 2026 and 1.0.14 on August 13, followed by a GitHub push that same day. The changes added CommonJS tests, exposed a missing factory type, and corrected CJS plus Node 10 exports. GitHub reports 0 open issues or pull requests and an unarchived repository, though 12 stars and one visible maintainer imply a narrow maintenance base.
Ecosystem3/5npm counted 5,254,356 downloads in the latest completed week, while GitHub reports 12 stars. The package works through ESM and CommonJS, carries declarations for both export paths, and has no runtime dependency graph. Adoption tooling stops there: the README names no grammar packs, plugins, editor adapters, or language-specific extensions, so every token definition remains application code.

Use it if

  • A tool needs offsets for a few predictable, non-overlapping token sequences without a full language grammar.
  • Comments may sit between statement tokens and their opening and closing positions must be retained.
  • One parser configuration will scan many strings into separate caller-owned context objects.
  • The same package must support ESM, CommonJS, and TypeScript declarations.
Skip it if

Setup reality

We installed parse-statements 1.0.14 in 0.8 seconds in a clean Node 22 Bookworm sandbox. It left 1 package and 1 MB on disk. The package has 0 direct dependencies, 0 peer dependencies, 84 KB unpacked, and an MIT license. npm audit returned 0 known vulnerabilities. No credentials, native compiler, generated files, or separate configuration are involved.

The package is ESM with an exports map, plus a CommonJS build. Both require() and ESM import worked in our test, and TypeScript declarations are bundled. Version 1.0.14 specifically fixes the CJS build and Node 10 export path. A browser import bundled to 3.4 KB minified and 1.4 KB gzipped.

Every token is a string used to construct a RegExp; the default flags are gmu. Backslashes must survive JavaScript string parsing, so a regex word boundary is written as '\b'. Replacing regexpFlags replaces the defaults, and dropping g interferes with scanning. Comments are recognized only when you define their opening and closing token pairs.

Callback offsets use an exclusive end, ready for source.slice(start, end). An incomplete sequence calls the statement's onError with the tokens found so far. A callback may return a custom end position, but then it must account for comments inside the manually consumed span. Matches do not overlap, and the mutable context is supplied anew for each parse call.

Patterns

Capture text between two tokens find-token-sequence

import { createParseFunction } from 'parse-statements';

type Context = { values: string[] };

const parse = createParseFunction<Context>({
  statements: [{
    tokens: ['^BEGIN\b', '\bEND$'],
    onParse: ({ values }, source, first, last) => {
      values.push(source.slice(first.end, last.start).trim());
    },
  }],
});

const context: Context = { values: [] };
parse(context, 'BEGIN useful text END');

Each token becomes a `RegExp`; the JavaScript string must contain an escaped backslash for `\b`.

Keep the entire matched span capture-whole-statement

const parse = createParseFunction<{ statements: string[] }>({
  statements: [{
    tokens: ['^include\b', ';'],
    onParse: (context, source, first, last) => {
      context.statements.push(source.slice(first.start, last.end));
    },
  }],
});

Token `start` is inclusive and `end` is exclusive, so these offsets pass directly to `String.prototype.slice`.

Save a partial statement as an error report-incomplete-statement

const parse = createParseFunction<{ errors: string[] }>({
  statements: [{
    tokens: ['^import\b', '\bfrom\b', '$\n?'],
    onError: (context, source, ...tokens) => {
      const first = tokens[0]!;
      const last = tokens[tokens.length - 1]!;
      context.errors.push(source.slice(first.start, last.end));
    },
  }],
});

The local `onError` receives the tokens matched before the expected next token could not be found.

Read slash line comments parse-line-comments

const parse = createParseFunction<{ comments: string[] }>({
  comments: [{
    tokens: ['\/\/', '$\n?'],
    onParse: (context, source, open, close) => {
      context.comments.push(source.slice(open.end, close.start));
    },
  }],
});

The closing token is another regex string; `$\n?` consumes the optional newline at the end of the comment.

Reject an unclosed block comment parse-block-comments

const parse = createParseFunction<{ comments: string[] }>({
  comments: [{
    tokens: ['\/\*', '\*\/'],
    onParse: (context, source, open, close) => {
      context.comments.push(source.slice(open.end, close.start));
    },
    onError: (_context, source, open) => {
      throw new SyntaxError(`Unclosed comment at ${open.start}: ${source.slice(open.start)}`);
    },
  }],
});

When the closing `*/` is absent, this comment's error callback runs and parsing stops at that failure.

Match a statement around comments allow-comments-inside

const parse = createParseFunction<{ imports: string[] }>({
  comments: [{ tokens: ['\/\*', '\*\/'] }],
  statements: [{
    canIncludeComments: true,
    shouldSearchBeforeComments: true,
    tokens: ['^import\b', '\bfrom\b', '$\n?'],
    onParse: (context, source, first, _from, last) => {
      context.imports.push(source.slice(first.start, last.end));
    },
  }],
});

Attached comments live on the preceding token. `shouldSearchBeforeComments` decides which opener wins at one position.

Extract comments attached to a token read-attached-comments

const onParse: OnParse<Context, 3> = (context, source, first, middle, last) => {
  for (const [open, close] of first.comments ?? []) {
    context.comments.push(source.slice(open.end, close.start));
  }
  context.values.push(source.slice(first.end, last.start));
};

The final token has no `comments` property because attached pairs occupy the gap before the following token.

Collect global scanner errors handle-global-error

const parse = createParseFunction<{ errors: string[] }>({
  onError: (context, _source, message, index) => {
    context.errors.push(`${index}: ${message}`);
  },
  statements,
  comments,
});

This handler receives scanner-level failures; statement and comment descriptors have separate local error callbacks.

Resume after a manually found brace override-statement-end

const parse = createParseFunction<Context>({
  statements: [{
    tokens: ['^section\b', '\{'],
    onParse: (context, source, first, openBrace) => {
      const close = findMatchingBrace(source, openBrace.end);
      context.sections.push(source.slice(first.start, close + 1));
      return close + 1;
    },
  }],
});

Returning `close + 1` skips to that offset. The callback must process any comments inside the skipped range itself.

Parse two sources with isolated state reuse-configured-parser

const parseDirectives = createParseFunction<Context>(options);

const first: Context = { directives: [], errors: [] };
const second: Context = { directives: [], errors: [] };

parseDirectives(first, sourceA);
parseDirectives(second, sourceB);

Each call mutates its supplied context; `parseDirectives` does not allocate or return a result container.

Alternatives

PackageRegistryPick it when
esprimanpmUse it when JavaScript input needs an ESTree syntax tree.
@babel/parsernpmUse it for JavaScript, TypeScript, JSX, proposals, and recoverable parse errors.
meriyahnpmUse it when fast ECMAScript parsing and a real AST matter more than format neutrality.

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.