{"id":13828,"library":"prsc","title":"prsc: Tiny Parser Combinators","description":"prsc is a compact parser combinators library for both JavaScript and TypeScript, heavily influenced by the Rust parsing library `nom`. It enables developers to construct complex parsers from simpler ones for string inputs, offering primitive parsers like `token` and combinators such as `map`, `filter`, `then`, and `star`. The library ships with ES6 modules (`.mjs`), UMD bundles (`.js`), and comprehensive TypeScript typings, facilitating its use across various environments, including Node.js and browsers. The current stable version is 4.0.0. Releases are somewhat frequent, with minor features and bug fixes rolled out between major versions, indicating active maintenance and continuous improvement in performance and usability for writing fast, reliable parsers.","status":"active","version":"4.0.0","language":"javascript","source_language":"en","source_url":"https://github.com/bwrrp/prsc.js","tags":["javascript","parser","combinators","typescript"],"install":[{"cmd":"npm install prsc","lang":"bash","label":"npm"},{"cmd":"yarn add prsc","lang":"bash","label":"yarn"},{"cmd":"pnpm add prsc","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"Use `import type` when only referencing the type in TypeScript to prevent accidental runtime imports and aid tree-shaking.","wrong":"import { Parser } from 'prsc';","symbol":"Parser","correct":"import type { Parser } from 'prsc';"},{"note":"The library primarily uses ESM imports. While UMD bundles are provided, the `require` syntax is generally discouraged for modern Node.js environments and TypeScript projects, especially since v4.0.0 improved ESM compatibility.","wrong":"const { ok, error } = require('prsc');","symbol":"ok, error","correct":"import { ok, error } from 'prsc';"},{"note":"These are common named exports representing core combinators. Destructuring them directly is the idiomatic way to use them.","wrong":"import * as prsc from 'prsc'; prsc.map(...);","symbol":"map, then, star, recognize, token, plus, preceded, optional","correct":"import { map, then, star, recognize, token, plus, preceded, optional } from 'prsc';"}],"quickstart":{"code":"import { ok, error, map, recognize, plus, then, token, star, preceded, optional } from 'prsc';\n\n// Create a primitive parser that accepts a single digit\nconst digit = (input, offset) => {\n\tif (/^[0-9]$/.test(input[offset])) {\n\t\treturn ok(offset + 1, input[offset]);\n\t}\n\treturn error(offset, ['digit']);\n};\n\n// Use that to accept a string of one or more digits\nconst digits = plus(digit);\n\n// Then use recognize to get the matching string and use map to parse that into a number\nconst number = map(recognize(digits), (str) => parseInt(str, 10));\n\n// Multiplication: term = number * term\n// Recursive definition requires indirection for `factor`\nconst termIndirect = (input, offset) => term(input, offset);\nconst factor = then(\n\tnumber,\n\toptional(preceded(token('*'), termIndirect)),\n\t(num, optFactor) => (optFactor ? num * optFactor : num)\n);\n\n// Addition: expression = factor + expression\nconst expressionIndirect = (input, offset) => expression(input, offset);\nconst expression = then(\n\tfactor,\n\tstar(preceded(token('+'), expressionIndirect)),\n\t(firstFactor, additionalFactors) =>\n\t\tadditionalFactors.reduce((sum, f) => sum + f, firstFactor)\n);\n\n// Parsing some input\nconst result1 = expression('2*3+4*5', 0);\nconsole.log(result1);\n// Expected: { success: true, offset: 7, value: 26 }\n\nconst result2 = expression('10+20*2', 0);\nconsole.log(result2);\n// Expected: { success: true, offset: 7, value: 50 } (10 + (20 * 2))\n","lang":"typescript","description":"This example demonstrates building a parser for a simple arithmetic language supporting addition and multiplication, showcasing primitive parsers, combinators like `map`, `then`, `star`, and handling recursive grammar rules."},"warnings":[{"fix":"Ensure you are using standard ESM imports (`import ... from 'prsc'`) in Node.js and modern browser environments. If you rely on direct paths to the UMD bundle for CJS, check the new file names in `dist/`.","message":"Version 4.0.0 primarily fixes ESM usage in Node.js environments. This is a breaking change because it renames the UMD module file provided for older CJS environments, which might affect direct file path references.","severity":"breaking","affected_versions":"4.0.0"},{"fix":"If you need the matched string value from `range`, combine it with the `recognize` combinator: `map(recognize(range(...)), value => ...)`.","message":"In version 3.0.0, the `range` parser no longer returns a value directly. It now acts purely as a consumption parser.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Wrap the recursive parser call in a function (e.g., `const parser = (input, offset) => actualParser(input, offset);`) and pass this function for the recursive part.","message":"When defining recursive parsers (e.g., `expression = term + expression`), it's crucial to use a layer of indirection (e.g., `termIndirect` function) to avoid circular dependencies in JavaScript module loading or infinite recursion at runtime.","severity":"gotcha","affected_versions":"all"},{"fix":"Always ensure that parsers wrapped by `star` or `plus` consume at least one unit of input if they succeed. If a parser fails to consume input, it should return an `error` result.","message":"An infinite loop can occur if a parser given to `star` (or `plus`) does not consume any input. While fixed for `star` in v2.1.0, this remains a common logical error for custom parsers.","severity":"gotcha","affected_versions":"<2.1.0"}],"env_vars":null,"search_vec":"'4.0.0':81 'across':69 'activ':98 'browser':75 'bug':90 'bundl':60 'combin':4,10,44,114 'compact':8 'complex':30 'comprehens':63 'construct':29 'continu':101 'current':77 'develop':27 'enabl':26 'environ':71 'es6':56 'facilit':66 'fast':109 'featur':88 'filter':48 'fix':91 'frequent':85 'heavili':17 'improv':102 'includ':72 'indic':97 'influenc':18 'input':37 'javascript':14,112 'js':61 'librari':11,23,53 'like':41 'mainten':99 'major':95 'map':47 'minor':87 'mjs':58 'modul':57 'node.js':73 'nom':24 'offer':38 'one':34 'pars':22 'parser':3,9,31,40,111,113 'perform':104 'primit':39 'prsc':1,5 'releas':82 'reliabl':110 'roll':92 'rust':21 'ship':54 'simpler':33 'somewhat':84 'stabl':78 'star':51 'string':36 'tini':2 'token':42 'type':65 'typescript':16,64,115 'umd':59 'usabl':106 'use':68 'various':70 'version':79,96 'write':108","created_at":"2026-04-20T01:56:31.532107+00:00","updated_at":"2026-04-20T01:56:31.532107+00:00","problems":[{"fix":"For TypeScript, use `import type { Parser } from 'prsc';`. For JavaScript, you likely don't need to import `Parser` itself as it's a type, not a runtime class.","cause":"Attempting to import `Parser` as a runtime value rather than a type in TypeScript, or incorrect CommonJS `require` syntax.","error":"TypeError: Parser is not a constructor"},{"fix":"Ensure you are using named ESM imports: `import { map, then } from 'prsc';`. Avoid `const prsc = require('prsc'); prsc.map;` for modern versions.","cause":"Incorrect import of combinators (e.g., `map`, `then`, `star`). This often happens with CommonJS `require` on ESM-only versions or attempting to access named exports via a default import.","error":"TypeError: Cannot read properties of undefined (reading 'map') or similar 'not a function' errors"},{"fix":"If you need the value, wrap `range` with `recognize`: `const valueParser = map(recognize(range('a', 'z')), str => str);`.","cause":"Using `range` parser from v3.0.0 onwards and expecting it to return a value, which it no longer does directly.","error":"ParserError: Expected range at offset X but got Y (or similar error when using `range`)"}],"ecosystem":"npm","meta_description":null,"install_score":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":null,"cli_name":"","cli_version":null,"type":"library","homepage":"https://prsc.js.org","github":"https://github.com/bwrrp/prsc.js","docs":null,"changelog":null,"pypi":null,"npm":"https://www.npmjs.com/package/prsc","openapi_spec":null,"status_page":null,"smithery":null,"categories":["serialization"],"base_url":null,"auth_type":null,"provenance":{"verified_status":null,"verified_at":null,"last_verified":"2026-06-17","next_check":"2026-07-18","install_tag":null}}