{"id":13683685,"url":"https://github.com/francisrstokes/arcsecond","last_synced_at":"2025-04-04T13:13:42.725Z","repository":{"id":35916639,"uuid":"162188752","full_name":"francisrstokes/arcsecond","owner":"francisrstokes","description":"✨Zero Dependency Parser Combinator Library for JS Based on Haskell's Parsec","archived":false,"fork":false,"pushed_at":"2024-02-15T16:15:36.000Z","size":1963,"stargazers_count":565,"open_issues_count":25,"forks_count":28,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-03-28T12:09:53.146Z","etag":null,"topics":["javascript","parsec","parser","parser-combinators","zero-dependency"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/francisrstokes.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-12-17T20:54:28.000Z","updated_at":"2025-03-19T16:53:41.000Z","dependencies_parsed_at":"2023-01-16T09:09:59.728Z","dependency_job_id":"d0bb03eb-f898-4ab2-aab9-0faa0541201e","html_url":"https://github.com/francisrstokes/arcsecond","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/francisrstokes%2Farcsecond","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/francisrstokes%2Farcsecond/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/francisrstokes%2Farcsecond/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/francisrstokes%2Farcsecond/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/francisrstokes","download_url":"https://codeload.github.com/francisrstokes/arcsecond/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247182420,"owners_count":20897381,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","parsec","parser","parser-combinators","zero-dependency"],"created_at":"2024-08-02T13:02:23.041Z","updated_at":"2025-04-04T13:13:42.698Z","avatar_url":"https://github.com/francisrstokes.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# Arcsecond\n\n\u003cimg src=\"./logo.png\"\u003e\n\nArcsecond is a zero-dependency, Fantasy Land compliant JavaScript [Parser Combinator](https://en.wikipedia.org/wiki/Parser_combinator) library largely inspired by Haskell's Parsec.\n\nThe [arcsecond-binary](https://github.com/francisrstokes/arcsecond-binary) peer library includes parsers specifically for working with binary data.\n\n---\n\n- [Arcsecond](#arcsecond)\n\n  - [Release Notes](#release-notes)\n  - [Installation](#installation)\n  - [Tutorial](#tutorials)\n  - [Usage](#usage)\n  - [Running the examples](#running-the-examples)\n  - [API](#api)\n\n      \u003cdetails\u003e\n        \u003csummary\u003eClick to expand\u003c/summary\u003e\n\n    - [Parser Methods](#methods)\n      - [.run](#run)\n      - [.fork](#fork)\n      - [.map](#map)\n      - [.errorMap](#errorMap)\n      - [.errorChain](#errorChain)\n      - [.chain](#chain)\n      - [.mapFromData](#mapFromData)\n      - [.chainFromData](#chainFromData)\n    - [Functions](#functions)\n      - [setData](#setData)\n      - [withData](#withData)\n      - [mapData](#mapData)\n      - [getData](#getData)\n      - [coroutine](#coroutine)\n      - [char](#char)\n      - [anyChar](#anyChar)\n      - [str](#str)\n      - [digit](#digit)\n      - [digits](#digits)\n      - [letter](#letter)\n      - [letters](#letters)\n      - [whitespace](#whitespace)\n      - [optionalWhitespace](#optionalWhitespace)\n      - [peek](#peek)\n      - [anyOfString](#anyOfString)\n      - [regex](#regex)\n      - [sequenceOf](#sequenceOf)\n      - [namedSequenceOf](#namedSequenceOf)\n      - [choice](#choice)\n      - [lookAhead](#lookAhead)\n      - [sepBy](#sepBy)\n      - [sepBy1](#sepBy1)\n      - [exactly](#exactly)\n      - [many](#many)\n      - [many1](#many1)\n      - [between](#between)\n      - [everythingUntil](#everythingUntil)\n      - [everyCharUntil](#everyCharUntil)\n      - [anythingExcept](#anythingExcept)\n      - [anyCharExcept](#anyCharExcept)\n      - [possibly](#possibly)\n      - [startOfInput](#startOfInput)\n      - [endOfInput](#endOfInput)\n      - [skip](#skip)\n      - [pipeParsers](#pipeParsers)\n      - [composeParsers](#composeParsers)\n      - [takeRight](#takeRight)\n      - [takeLeft](#takeLeft)\n      - [recursiveParser](#recursiveParser)\n      - [tapParser](#tapParser)\n      - [decide](#decide)\n      - [mapTo](#mapTo)\n      - [errorMapTo](#errorMapTo)\n      - [fail](#fail)\n      - [succeedWith](#succeedWith)\n      - [either](#either)\n      - [toPromise](#toPromise)\n      - [toValue](#toValue)\n      - [parse](#parse)\n      \u003c/details\u003e\n\n  - [A note on recursive grammars](#a-note-on-recursive-grammars)\n  - [Fantasy Land](#fantasy-land)\n    - [Equivalent Operations](#equivalent-operations)\n      - [of](#of)\n      - [map](#map)\n      - [chain](#chain)\n      - [ap](#ap)\n  - [Name](#name)\n\n## Release Notes\n\n[Since version 2.0.0, the release notes track changes to arcsecond.](./release-notes.md)\n\n## Installation\n\n```bash\nnpm i arcsecond\n```\n\n## Tutorials\n\nThe tutorials provide a practical introduction to many of the concepts in arcsecond, starting from the most basic foundations and working up to more complex topics.\n\n- [1. Parsing weather data](tutorial/tutorial-part-1.md)\n- [2. Extracting useful information](tutorial/tutorial-part-2.md)\n- [3. Error handling](tutorial/tutorial-part-3.md)\n- [4. Building utility parsers](tutorial/tutorial-part-4.md)\n- [5. Recursive Structures](tutorial/tutorial-part-5.md)\n- [6. Debugging](tutorial/tutorial-part-6.md)\n- [7. Stateful parsing](tutorial/tutorial-part-7.md)\n\n## Usage\n\nYou can use ES6 imports or CommonJS requires.\n\n```JavaScript\nconst {char} = require('arcsecond');\n\nconst parsingResult = char('a').fork(\n  // The string to parse\n  'abc123',\n\n  // The error handler (you can also return from this function!)\n  (error, parsingState) =\u003e {\n    const e = new Error(error);\n    e.parsingState = parsingState;\n    throw e;\n  },\n\n  // The success handler\n  (result, parsingState) =\u003e {\n    console.log(`Result: ${result}`);\n    return result;\n  }\n);\n```\n\n## Running the examples\n\n```bash\ngit clone git@github.com:francisrstokes/arcsecond.git\ncd arcsecond\nnpm i\n\n# json example\nnode -r esm examples/json/json.js\n```\n\nThe examples are built as es6 modules, which means they need node to be launched with the `-r esm` require flag, which allows import and export statements to be used.\n\n## API\n\n### Methods\n\n#### .run\n\n`.run` is a method on every parser, which takes input (which may be a `string`, [`TypedArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray), [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer), or [`DataView`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView)), and returns the result of parsing the input using the parser.\n\n**Example**\n\n```JavaScript\nstr('hello').run('hello')\n// -\u003e {\n//      isError: false,\n//      result: \"hello\",\n//      index: 5,\n//      data: null\n//    }\n```\n\n#### .fork\n\nThe `.fork` method is similar to `.run`. It takes input (which may be a `string`, [`TypedArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray), [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer), or [`DataView`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView)), an _error transforming function_ and a _success transforming function_, and parses the input. If parsing was successful, the result is transformed using the _success transforming function_ and returned. If parsing was not successful, the result is transformed using the _error transforming function_ and returned.\n\n**Example**\n\n```JavaScript\nstr('hello').fork(\n  'hello',\n  (errorMsg, parsingState) =\u003e {\n    console.log(errorMsg);\n    console.log(parsingState);\n    return \"goodbye\"\n  },\n  (result, parsingState) =\u003e {\n    console.log(parsingState);\n    return result;\n  }\n);\n// [console.log] Object {isError: false, error: null, target: \"hello\", data: null, index: 5, …}\n// -\u003e \"hello\"\n\nstr('hello').fork(\n  'farewell',\n  (errorMsg, parsingState) =\u003e {\n    console.log(errorMsg);\n    console.log(parsingState);\n    return \"goodbye\"\n  },\n  (result, parsingState) =\u003e {\n    console.log(parsingState);\n    return result;\n  }\n);\n// [console.log] ParseError (position 0): Expecting string 'hello', got 'farew...'\n// [console.log] Object {isError: true, error: \"ParseError (position 0): Expecting string 'hello',…\", target: \"farewell\", data: null, index: 0, …}\n// \"goodbye\"\n```\n\n#### .map\n\n`.map` takes a function and returns a parser does not consume input, but instead runs the provided function on the last matched value, and set that as the new last matched value. This method can be used to apply structure or transform the values as they are being parsed.\n\n**Example**\n\n```JavaScript\nconst newParser = letters.map(x =\u003e ({\n  matchType: 'string',\n  value: x\n});\n\nnewParser.run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: {\n//        matchType: \"string\",\n//        value: \"hello\"\n//      },\n//      index: 5,\n//      data: null\n//    }\n```\n\n#### .chain\n\n`.chain` takes a function which recieves the last matched value and should return a parser. That parser is then used to parse the following input, forming a chain of parsers based on previous input. `.chain` is the fundamental way of creating _contextual parsers_.\n\n**Example**\n\n```JavaScript\n\nconst lettersThenSpace = sequenceOf([\n  letters,\n  char(' ')\n]).map(x =\u003e x[0]);\n\nconst newParser = lettersThenSpace.chain(matchedValue =\u003e {\n  switch (matchedValue) {\n    case 'number': return digits;\n\n    case 'string': return letters;\n\n    case 'bracketed': return sequenceOf([\n      char('('),\n      letters,\n      char(')')\n    ]).map(values =\u003e values[1]);\n\n    default: return fail('Unrecognised input type');\n  }\n});\n\nnewParser.run('string Hello')\n// -\u003e {\n//      isError: false,\n//      result: \"Hello\",\n//      index: 12,\n//      data: null\n//    }\n\nnewParser.run('number 42')\n// -\u003e {\n//      isError: false,\n//      result: \"42\",\n//      index: 9,\n//      data: null\n//    }\n\nnewParser.run('bracketed (arcsecond)')\n// -\u003e {\n//      isError: false,\n//      result: \"arcsecond\",\n//      index: 21,\n//      data: null\n//    }\n\nnewParser.run('nope nothing')\n// -\u003e {\n//      isError: true,\n//      error: \"Unrecognised input type\",\n//      index: 5,\n//      data: null\n//    }\n```\n\n#### .mapFromData\n\n`.mapFromData` is almost the same as `.map`, except the function which it is passed also has access to the _internal state data_, and can thus transform values based on this data.\n\n**Example**\n\n```JavaScript\n\nconst parserWithData = withData(letters.mapFromData(({result, data}) =\u003e ({\n  matchedValueWas: result,\n  internalDataWas: data\n})));\n\nparserWithData(42).run('hello');\n// -\u003e {\n//      isError: false,\n//      result: {\n//        matchedValueWas: \"hello\",\n//        internalDataWas: 42\n//      },\n//      index: 5,\n//      data: 42\n//    }\n```\n\n#### .chainFromData\n\n`.chainFromData` is almost the same as `.chain`, except the function which it is passed also has access to the _internal state data_, and can choose how parsing continues based on this data.\n\n**Example**\n\n```JavaScript\nconst lettersThenSpace = sequenceOf([\n  letters,\n  char(' ')\n]).map(x =\u003e x[0]);\n\nconst parser = withData(lettersThenSpace.chainFromData(({result, data}) =\u003e {\n  if (data.bypassNormalApproach) {\n    return digits;\n  }\n\n  return letters;\n}));\n\nparser({ bypassNormalApproach: false }).run('hello world');\n// -\u003e {\n//      isError: false,\n//      result: \"world\",\n//      index: 11,\n//      data: { bypassNormalApproach: false }\n//    }\n\nparser({ bypassNormalApproach: true }).run('hello world');\n// -\u003e {\n//      isError: true,\n//      error: \"ParseError (position 6): Expecting digits\",\n//      index: 6,\n//      data: { bypassNormalApproach: true }\n//    }\n```\n\n#### .errorMap\n\n`.errorMap` is like [.map](#map) but it transforms the error value. The function passed to `.errorMap` gets an object the _current error message_ (`error`) , the _index_ (`index`) that parsing stopped at, and the _data_ (`data`) from this parsing session.\n\n**Example**\n\n```JavaScript\nconst newParser = letters.errorMap(({error, index}) =\u003e `Old message was: [${error}] @ index ${index}`);\n\nnewParser.run('1234')\n// -\u003e {\n//      isError: true,\n//      error: \"Old message was: [ParseError (position 0): Expecting letters] @ index 0\",\n//      index: 0,\n//      data: null\n//    }\n```\n\n#### .errorChain\n\n`.errorChain` is almost the same as `.chain`, except that it only runs if there is an error in the parsing state. This is a useful method when either trying to recover from errors, or for when a more specific error message should be constructed.\n\n**Example**\n\n```JavaScript\n\nconst parser = digits.errorChain(({error, index, data}) =\u003e {\n  console.log('Recovering...');\n  return letters;\n});\n\np.run('42');\n// -\u003e {\n//      isError: false,\n//      result: \"42\",\n//      index: 2,\n//      data: null\n//    }\n\np.run('hello');\n// [console.log] Recovering...\n// -\u003e {\n//      isError: false,\n//      result: \"hello\",\n//      index: 5,\n//      data: null\n//    }\n\ns = parser.run('');\n// [console.log] Recovering...\n// -\u003e {\n//     isError: true,\n//     error: \"ParseError (position 0): Expecting letters\",\n//     index: 0,\n//     data: null\n//   }\n```\n\n### Functions\n\n#### setData\n\n`setData` takes anything that should be set as the _internal state data_, and returns a parser that will perform that side effect when the parser is run. This does not consume any input. If parsing is currently in an errored state, then the data **will not** be set.\n\n**Example**\n\n```JavaScript\nconst parser = coroutine(run=\u003e {\n  const name = run(letters);\n\n  if (name === 'Jim') {\n    run(setData('The name is Jim'));\n  }\n\n  return name;\n});\n\nparser.run('Jim');\n// -\u003e {\n//      isError: false,\n//      result: \"Jim\",\n//      index: 3,\n//      data: \"The name is Jim\"\n//    }\n```\n\nIf dealing with any complex level of state - such as an object where individual keys will be updated or required, then it can be useful to create utility parsers to assist with updating the _internal state data_.\nOne possible pattern that could be used is the reducer pattern, famed by redux:\n\n**Example**\n\n```JavaScript\n\nconst createStateReducer = reducer =\u003e action =\u003e getData.chain(state =\u003e setData(reducer(state, action)));\n\nconst updateCounterState = createStateReducer((state = 0, action) =\u003e {\n  switch (action.type) {\n    case 'INC': {\n      return state + 1;\n    }\n    case 'DEC': {\n      return state - 1;\n    }\n    case 'ADD': {\n      return state + action.payload;\n    }\n    case 'RESET': {\n      return 0;\n    }\n  }\n});\n\nconst parser = coroutine(run=\u003e{\n  let count = run(updateCounterState({ type: 'RESET' }));\n  console.log(count);\n\n  run(updateCounterState({ type: 'INC' }));\n  run(updateCounterState({ type: 'INC' }));\n  run(updateCounterState({ type: 'DEC' }));\n  count = run(updateCounterState({ type: 'INC' }));\n  console.log(count);\n\n  return run(updateCounterState({ type: 'ADD', payload: 10 }));\n});\n\nparser.run('Parser is not looking at the text!');\n// [console.log] 0\n// [console.log] 2\n// -\u003e {\n//      isError: false,\n//      result: 12,\n//      index: 0,\n//      data: 12\n//    }\n```\n\n#### withData\n\n`withData` takes a _provided parser_, and returns a function waiting for some _state data_ to be set, and then returns a new parser. That parser, when run, ensures that the _state data_ is set as the _internal state data_ before the _provided parser_ runs.\n\n**Example**\n\n```JavaScript\nconst parserWithoutData = letters;\nconst parser = withData(parserWithoutData);\n\nparser(\"hello world!\").run('Jim');\n// -\u003e {\n//      isError: false,\n//      result: \"Jim\",\n//      index: 3,\n//      data: \"hello world!\"\n//    }\n\nparserWithoutData.run('Jim');\n// -\u003e {\n//      isError: false,\n//      result: \"Jim\",\n//      index: 3,\n//      data: null\n//    }\n```\n\n#### mapData\n\n`mapData` takes a function that recieves and returns some _state data_, and transforms the _internal state data_ using the function, without consuming any input.\n\n**Example**\n\n```JavaScript\nconst parser = withData(mapData(s =\u003e s.toUpperCase()));\n\nparser(\"hello world!\").run('Jim');\n// -\u003e {\n//      isError: false,\n//      result: null,\n//      index: 0,\n//      data: \"HELLO WORLD!\"\n//    }\n```\n\n#### getData\n\n`getData` is a parser that will always return what is contained in the _internal state data_, without consuming any input.\n\n**Example**\n\n```JavaScript\nconst parser = withData(sequenceOf([\n  letters,\n  digits,\n  getData\n]));\n\nparser(\"hello world!\").run('Jim1234');\n// -\u003e {\n//      isError: false,\n//      result: [\"Jim\", \"1234\", \"hello world!\"],\n//      index: 3,\n//      data: \"hello world!\"\n//    }\n```\n\nIf dealing with any complex level of state - such as an object where individual keys will be updated or required, then it can be useful to create utility parsers to assist.\n\n**Example**\n\n```JavaScript\n\nconst selectState = selectorFn =\u003e getData.map(selectorFn);\n\nconst parser = withData(coroutine(run=\u003e {\n  // Here we can take or transform the state\n  const occupation = run(selectState(({job}) =\u003e job));\n  const initials = run(selectState(({firstName, lastName}) =\u003e `${firstName[0]}${lastName[0]}`));\n\n  console.log(`${initials}: ${occupation}`);\n\n  const first = run(letters);\n  const second = run(digits);\n\n  return `${second}${first}`;\n}));\n\nparser({\n  firstName: \"Francis\",\n  lastName: \"Stokes\",\n  job: \"Developer\"\n}).run('Jim1234');\n// [console.log] FS: Developer\n// -\u003e {\n//      isError: false,\n//      result: \"1234Jim\",\n//      index: 3,\n//      data: {\n//        firstName: \"Francis\",\n//        lastName: \"Stokes\",\n//        job: \"Developer\"\n//      }\n//    }\n```\n\n#### coroutine\n\n`coroutine` takes a user provided _parser function_, to which is passed a `run` function. Within the _parser function_, the user can `run` other parsers, and get immediate access to their results.\n\n`coroutine` allows you to write parsers in a more imperative and sequential way - in much the same way `async/await` allows you to write code with promises in a more sequential way.\n\nInside of the _parser function_, you can use all regular JavaScript language features, like loops, variable assignments, try/catch, and conditional statements. This makes it easy to write very powerful parsers using `coroutine`, but on the other side it can lead to less readable, more complex code.\n\nDebugging is also much easier, as breakpoints can be easily added, and values logged to the console after they have been parsed.\n\n**Example**\n\n```JavaScript\nconst parser = coroutine(run =\u003e {\n  // Capture some letters and assign them to a variable\n  const name = run(letters);\n\n  // Capture a space\n  run(char(' '));\n\n  const age = run(digits.map(Number));\n\n  // Capture a space\n  run(char(' '));\n\n  if (age \u003e= 18) {\n    run(str('is an adult'));\n  } else {\n    run(str('is a child'));\n  }\n\n  return { name, age };\n});\n\nparser.run('Jim 19 is an adult');\n// -\u003e {\n//      isError: false,\n//      result: { name: \"Jim\", age: 19 },\n//      index: 18,\n//      data: null\n//    }\n\nparser.run('Jim 17 is an adult');\n// -\u003e {\n//      isError: true,\n//      error: \"ParseError (position 7): Expecting string 'is a child', got 'is an adul...'\",\n//      index: 7,\n//      data: null\n//    }\n```\n\n#### char\n\n`char` takes a character and returns a parser that matches that character **exactly one** time.\n\n**Example**\n\n```JavaScript\nchar ('h').run('hello')\n// -\u003e {\n//      isError: false,\n//      result: \"h\",\n//      index: 1,\n//      data: null\n//    }\n```\n\n#### anyChar\n\n`anyChar` matches **exactly one** utf-8 character.\n\n**Example**\n\n```JavaScript\nanyChar.run('a')\n// -\u003e {\n//      isError: false,\n//      result: \"a\",\n//      index: 1,\n//      data: null\n//    }\n\nanyChar.run('😉')\n// -\u003e {\n//      isError: false,\n//      result: \"😉\",\n//      index: 4,\n//      data: null\n//    }\n```\n\n#### str\n\n`str` takes a string and returns a parser that matches that string **exactly one** time.\n\n**Example**\n\n```JavaScript\nstr('hello').run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: \"hello\",\n//      index: 5,\n//      data: null\n//    }\n```\n\n#### digit\n\n`digit` is a parser that matches **exactly one** numerical digit `/[0-9]/`.\n\n**Example**\n\n```JavaScript\ndigit.run('99 bottles of beer on the wall')\n// -\u003e {\n//      isError: false,\n//      result: \"9\",\n//      index: 1,\n//      data: null\n//    }\n```\n\n#### digits\n\n`digits` is a parser that matches **one or more** numerical digit `/[0-9]/`.\n\n**Example**\n\n```JavaScript\ndigits.run('99 bottles of beer on the wall')\n// -\u003e {\n//      isError: false,\n//      result: \"99\",\n//      index: 2,\n//      data: null\n//    }\n```\n\n#### letter\n\n`letter` is a parser that matches **exactly one** alphabetical letter `/[a-zA-Z]/`.\n\n**Example**\n\n```JavaScript\nletter.run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: \"h\",\n//      index: 1,\n//      data: null\n//    }\n```\n\n#### letters\n\n`letters` is a parser that matches **one or more** alphabetical letter `/[a-zA-Z]/`.\n\n**Example**\n\n```JavaScript\nletters.run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: \"hello\",\n//      index: 5,\n//      data: null\n//    }\n```\n\n#### whitespace\n\n`whitespace` is a parser that matches **one or more** whitespace characters.\n\n**Example**\n\n```JavaScript\nconst newParser = sequenceOf ([\n  str ('hello'),\n  whitespace,\n  str ('world')\n]);\n\nnewParser.run('hello           world')\n// -\u003e {\n//      isError: false,\n//      result: [ \"hello\", \"           \", \"world\" ],\n//      index: 21,\n//      data: null\n//    }\n\nnewParser.run('helloworld')\n// -\u003e {\n//      isError: true,\n//      error: \"ParseError 'many1' (position 5): Expecting to match at least one value\",\n//      index: 5,\n//      data: null\n//    }\n```\n\n#### optionalWhitespace\n\n`optionalWhitespace` is a parser that matches **zero or more** whitespace characters.\n\n**Example**\n\n```JavaScript\nconst newParser = sequenceOf ([\n  str ('hello'),\n  optionalWhitespace,\n  str ('world')\n]);\n\nnewParser.run('hello           world')\n// -\u003e {\n//      isError: false,\n//      result: [ \"hello\", \"           \", \"world\" ],\n//      index: 21,\n//      data: null\n//    }\n\nnewParser.run('helloworld')\n// -\u003e {\n//      isError: false,\n//      result: [ \"hello\", \"\", \"world\" ],\n//      index: 10,\n//      data: null\n//    }\n```\n\n#### peek\n\n`peek` matches **exactly one** _numerical byte_ without consuming any input.\n\n**Example**\n\n```JavaScript\npeek.run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: 104,\n//      index: 0,\n//      data: null\n//    }\n\nsequenceOf([\n  str('hello'),\n  peek\n]).run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: [ \"hello\", 32 ],\n//      index: 5,\n//      data: null\n//    }\n```\n\n#### anyOfString\n\n`anyOfString` takes a string and returns a parser that matches **exactly one** character from that string.\n\n**Example**\n\n```JavaScript\nanyOfString('aeiou').run('unusual string')\n// -\u003e {\n//      isError: false,\n//      result: \"u\",\n//      index: 1,\n//      data: null\n//    }\n```\n\n#### regex\n\n`regex` takes a RegExp and returns a parser that matches **as many characters** as the RegExp matches.\n\n**Example**\n\n```JavaScript\nregex(/^[hH][aeiou].{2}o/).run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: \"hello\",\n//      index: 5,\n//      data: null\n//    }\n```\n\n#### sequenceOf\n\n`sequenceOf` takes an array of parsers, and returns a new parser that matches each of them sequentially, collecting up the results into an array.\n\n**Example**\n\n```JavaScript\nconst newParser = sequenceOf ([\n  str ('he'),\n  letters,\n  char (' '),\n  str ('world'),\n])\n\nnewParser.run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: [ \"he\", \"llo\", \" \", \"world\" ],\n//      index: 11,\n//      data: null\n//    }\n```\n\n#### namedSequenceOf\n\n`namedSequenceOf` takes an array of string/parser pairs, and returns a new parser that matches each of them sequentially, collecting up the results into an object where the key is the string in the pair.\n\nA pair is just an array in the form: `[string, parser]`\n\n**Example**\n\n```JavaScript\nconst newParser = namedSequenceOf ([\n  ['firstPart', str ('he')],\n  ['secondPart', letters],\n  ['thirdPart', char (' ')],\n  ['forthPart', str ('world')],\n])\n\nnewParser.run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: {\n//        firstPart: \"he\",\n//        secondPart: \"llo\",\n//        thirdPart: \" \",\n//        forthPart: \"world\"\n//      },\n//      index: 11,\n//      data: null\n//    }\n```\n\n#### choice\n\n`choice` takes an array of parsers, and returns a new parser that tries to match each one of them sequentially, and returns the first match. If `choice` fails, then it returns the error message of the parser that matched the most from the string.\n\n**Example**\n\n```JavaScript\nconst newParser = choice ([\n  digit,\n  char ('!'),\n  str ('hello'),\n  str ('pineapple')\n])\n\nnewParser.run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: \"hello\",\n//      index: 5,\n//      data: null\n//    }\n```\n\n#### lookAhead\n\n`lookAhead` takes _look ahead_ parser, and returns a new parser that matches using the _look ahead_ parser, but without consuming input.\n\n**Example**\n\n```JavaScript\nconst newParser = sequenceOf ([\n  str ('hello '),\n  lookAhead (str ('world')),\n  str ('wor')\n]);\n\nnewParser.run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: [ \"hello \", \"world\", \"wor\" ],\n//      index: 9,\n//      data: null\n//    }\n```\n\n#### sepBy\n\n`sepBy` takes two parsers - a _separator_ parser and a _value_ parser - and returns a new parser that matches **zero or more** values from the _value_ parser that are separated by values of the _separator_ parser. Because it will match zero or more values, this parser will _fail_ if a _value_ is followed by a _separator_ but NOT another _value_. If there's no _value_, the result will be an empty array, not failure.\n\n**Example**\n\n```JavaScript\nconst newParser = sepBy (char (',')) (letters)\n\nnewParser.run('some,comma,separated,words')\n// -\u003e {\n//      isError: false,\n//      result: [ \"some\", \"comma\", \"separated\", \"words\" ],\n//      index: 26,\n//      data: null\n//    }\n\nnewParser.run('')\n// -\u003e {\n//      isError: false,\n//      result: [],\n//      index: 0,\n//      data: null\n//    }\n\nnewParser.run('12345')\n// -\u003e {\n//      isError: false,\n//      result: [],\n//      index: 0,\n//      data: null\n//    }\n```\n\n#### sepBy1\n\n`sepBy1` is the same as `sepBy`, except that it matches **one or more** occurence.\n\n**Example**\n\n```JavaScript\nconst newParser = sepBy1 (char (',')) (letters)\n\nnewParser.run('some,comma,separated,words')\n// -\u003e {\n//      isError: false,\n//      result: [ \"some\", \"comma\", \"separated\", \"words\" ],\n//      index: 26,\n//      data: null\n//    }\n\nnewParser.run('1,2,3')\n// -\u003e {\n//      isError: true,\n//      error: \"ParseError 'sepBy1' (position 0): Expecting to match at least one separated value\",\n//      index: 0,\n//      data: null\n//    }\n```\n\n#### exactly\n\n`exactly` takes a positive number and returns a function. That function takes a parser and returns a new parser which matches the given parser the specified number of times.\n\n**Example**\n\n```JavaScript\nconst newParser = exactly (4)(letter)\n\nnewParser.run('abcdef')\n// -\u003e {\n//      isError: false,\n//      result: [ \"a\", \"b\", \"c\", \"d\" ],\n//      index: 4,\n//      data: null\n//    }\n\nnewParser.run('abc')\n// -\u003e {\n//      isError: true,\n//      error: 'ParseError (position 0): Expecting 4 letter, but got end of input.',\n//      index: 0,\n//      data: null\n//    }\n\nnewParser.run('12345')\n// -\u003e {\n//      isError: true,\n//      error: 'ParseError (position 0): Expecting 4 letter, got '1'',\n//      index: 0,\n//      data: null\n//    }\n```\n\n#### many\n\n`many` takes a parser and returns a new parser which matches that parser **zero or more** times. Because it will match zero or more values, this parser will always match, resulting in an empty array in the zero case.\n\n**Example**\n\n```JavaScript\nconst newParser = many (str ('abc'))\n\nnewParser.run('abcabcabcabc')\n// -\u003e {\n//      isError: false,\n//      result: [ \"abc\", \"abc\", \"abc\", \"abc\" ],\n//      index: 12,\n//      data: null\n//    }\n\nnewParser.run('')\n// -\u003e {\n//      isError: false,\n//      result: [],\n//      index: 0,\n//      data: null\n//    }\n\nnewParser.run('12345')\n// -\u003e {\n//      isError: false,\n//      result: [],\n//      index: 0,\n//      data: null\n//    }\n```\n\n#### many1\n\n`many1` is the same as `many`, except that it matches **one or more** occurence.\n\n**Example**\n\n```JavaScript\nconst newParser = many1 (str ('abc'))\n\nnewParser.run('abcabcabcabc')\n// -\u003e {\n//      isError: false,\n//      result: [ \"abc\", \"abc\", \"abc\", \"abc\" ],\n//      index: 12,\n//      data: null\n//    }\n\nnewParser.run('')\n// -\u003e {\n//   isError: true,\n//   error: \"ParseError 'many1' (position 0): Expecting to match at least one value\",\n//   index: 0,\n//   data: null\n// }\n\nnewParser.run('12345')\n// -\u003e {\n//   isError: true,\n//   error: \"ParseError 'many1' (position 0): Expecting to match at least one value\",\n//   index: 0,\n//   data: null\n// }\n```\n\n#### between\n\n`between` takes 3 parsers, a _left_ parser, a _right_ parser, and a _value_ parser, returning a new parser that matches a value matched by the _value_ parser, between values matched by the _left_ parser and the _right_ parser.\n\nThis parser can easily be partially applied with `char ('(')` and `char (')')` to create a `betweenRoundBrackets` parser, for example.\n\n**Example**\n\n```JavaScript\nconst newParser = between (char ('\u003c')) (char ('\u003e')) (letters);\n\nnewParser.run('\u003chello\u003e')\n// -\u003e {\n//      isError: false,\n//      result: \"hello\",\n//      index: 7,\n//      data: null\n//    }\n\nconst betweenRoundBrackets = between (char ('(')) (char (')'));\n\nbetweenRoundBrackets (many (letters)).run('(hello world)')\n// -\u003e {\n//      isError: true,\n//      error: \"ParseError (position 6): Expecting character ')', got ' '\",\n//      index: 6,\n//      data: null\n//    }\n```\n\n#### everythingUntil\n\n**Note**: Between 2.x and 3.x, the definition of the `everythingUntil` has changed. In 3.x, what was previously `everythingUntil` is now [`everyCharUntil`](#everyCharUntil).\n\n`everythingUntil` takes a _termination_ parser and returns a new parser which matches every possible _numerical byte_ up until a value is matched by the _termination_ parser. When a value is matched by the _termination_ parser, it is not \"consumed\".\n\n**Example**\n\n```JavaScript\neverythingUntil (char ('.')).run('This is a sentence.This is another sentence')\n// -\u003e {\n//      isError: false,\n//      result: [84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 115, 101, 110, 116, 101, 110, 99, 101],\n//      index: 18,\n//      data: null\n//    }\n\n// termination parser doesn't consume the termination value\nconst newParser = sequenceOf ([\n  everythingUntil (char ('.')),\n  str ('This is another sentence')\n]);\n\nnewParser.run('This is a sentence.This is another sentence')\n// -\u003e {\n//      isError: true,\n//      error: \"ParseError (position 18): Expecting string 'This is another sentence', got '.This is another sentenc...'\",\n//      index: 18,\n//      data: null\n//    }\n```\n\n#### everyCharUntil\n\n`everyCharUntil` takes a _termination_ parser and returns a new parser which matches every possible _character_ up until a value is matched by the _termination_ parser. When a value is matched by the _termination_ parser, it is not \"consumed\".\n\n**Example**\n\n```JavaScript\neveryCharUntil (char ('.')).run('This is a sentence.This is another sentence')\n// -\u003e {\n//      isError: false,\n//      result: 'This is a sentence',\n//      index: 18,\n//      data: null\n//    }\n\n// termination parser doesn't consume the termination value\nconst newParser = sequenceOf ([\n  everyCharUntil (char ('.')),\n  str ('This is another sentence')\n]);\n\nnewParser.run('This is a sentence.This is another sentence')\n// -\u003e {\n//      isError: true,\n//      error: \"ParseError (position 18): Expecting string 'This is another sentence', got '.This is another sentenc...'\",\n//      index: 18,\n//      data: null\n//    }\n```\n\n#### anythingExcept\n\n**Note**: Between 2.x and 3.x, the definition of the `anythingExcept` has changed. In 3.x, what was previously `anythingExcept` is now [`anyCharExcept`](#anyCharExcept).\n\n`anythingExcept` takes a _exception_ parser and returns a new parser which matches **exactly one** _numerical byte_, if it is not matched by the _exception_ parser.\n\n**Example**\n\n```JavaScript\nanythingExcept (char ('.')).run('This is a sentence.')\n// -\u003e {\n//   isError: false,\n//   result: 84,\n//   index: 1,\n//   data: null\n// }\n\nconst manyExceptDot = many (anythingExcept (char ('.')))\nmanyExceptDot.run('This is a sentence.')\n// -\u003e {\n//      isError: false,\n//      result: [84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 115, 101, 110, 116, 101, 110, 99, 101, 46],\n//      index: 18,\n//      data: null\n//    }\n```\n\n#### anyCharExcept\n\n`anyCharExcept` takes a _exception_ parser and returns a new parser which matches **exactly one** _character_, if it is not matched by the _exception_ parser.\n\n**Example**\n\n```JavaScript\nanyCharExcept (char ('.')).run('This is a sentence.')\n// -\u003e {\n//   isError: false,\n//   result: 'T',\n//   index: 1,\n//   data: null\n// }\n\nconst manyExceptDot = many (anyCharExcept (char ('.')))\nmanyExceptDot.run('This is a sentence.')\n// -\u003e {\n//      isError: false,\n//      result: ['T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 's', 'e', 'n', 't', 'e', 'n', 'c', 'e'],\n//      index: 18,\n//      data: null\n//    }\n```\n\n#### possibly\n\n`possibly` takes an _attempt_ parser and returns a new parser which tries to match using the _attempt_ parser. If it is unsuccessful, it returns a null value and does not \"consume\" any input.\n\n**Example**\n\n```JavaScript\nconst newParser = sequenceOf ([\n  possibly (str ('Not Here')),\n  str ('Yep I am here')\n]);\n\nnewParser.run('Yep I am here')\n// -\u003e {\n//      isError: false,\n//      result: [ null, \"Yep I am here\" ],\n//      index: 13,\n//      data: null\n//    }\n```\n\n#### startOfInput\n\n`startOfInput` is a parser that only succeeds when the parser is at the beginning of the input.\n\n**Example**\n\n```JavaScript\nconst mustBeginWithHeading = sequenceOf([\n    startOfInput,\n    str(\"# \")\n  ]);\nconst newParser = between(mustBeginWithHeading)(endOfInput)(everyCharUntil(endOfInput));\n\nnewParser.run('# Heading');\n// -\u003e {\n//      isError: false,\n//      result: \"# Heading\",\n//      index: 9,\n//      data: null\n//    }\n\nnewParser.run(' # Heading');\n// -\u003e {\n//      isError: true,\n//      error: \"ParseError (position 0): Expecting string '# ', got ' #...'\",\n//      index: 0,\n//      data: null\n//    }\n```\n\n#### endOfInput\n\n`endOfInput` is a parser that only succeeds when there is no more input to be parsed.\n\n**Example**\n\n```JavaScript\nconst newParser = sequenceOf ([\n  str ('abc'),\n  endOfInput\n]);\n\nnewParser.run('abc')\n// -\u003e {\n//      isError: false,\n//      result: [ \"abc\", null ],\n//      index: 3,\n//      data: null\n//    }\n\nnewParser.run('')\n// -\u003e {\n//      isError: true,\n//      error: \"ParseError (position 0): Expecting string 'abc', but got end of input.\",\n//      index: 0,\n//      data: null\n//    }\n```\n\n#### skip\n\n`skip` takes a _skip_ parser and returns a new parser which matches using the _skip_ parser, but doesn't return its value, but instead the value of whatever came before it.\n\n**Example**\n\n```JavaScript\nconst newParser = pipeParsers ([\n  str ('abc'),\n  str('123'),\n  skip (str ('def'))\n])\n\nnewParser.run('abc123def')\n// -\u003e {\n//      isError: false,\n//      result: \"123\",\n//      index: 9,\n//      data: null\n//    }\n```\n\n#### pipeParsers\n\n`pipeParsers` takes an array of parsers and composes them left to right, so each parsers return value is passed into the next one in the chain. The result is a new parser that, when run, yields the result of the final parser in the chain.\n\n**Example**\n\n```JavaScript\nconst newParser = pipeParsers ([\n  str ('hello'),\n  char (' '),\n  str ('world')\n]);\n\nnewParser.run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: \"world\",\n//      index: 11,\n//      data: null\n//    }\n```\n\n#### composeParsers\n\n`composeParsers` takes an array of parsers and composes them right to left, so each parsers return value is passed into the next one in the chain. The result is a new parser that, when run, yields the result of the final parser in the chain.\n\n**Example**\n\n```JavaScript\nconst newParser = composeParsers ([\n  str ('world'),\n  char (' '),\n  str ('hello')\n]);\n\nnewParser.run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: \"world\",\n//      index: 11,\n//      data: null\n//    }\n```\n\n#### takeRight\n\n`takeRight` takes two parsers, _left_ and _right_, and returns a new parser that first matches the _left_, then the _right_, and keeps the value matched by the _right_.\n\n**Example**\n\n```JavaScript\nconst newParser = takeRight (str ('hello ')) (str ('world'))\n\nnewParser.run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: \"world\",\n//      index: 11,\n//      data: null\n//    }\n```\n\n#### takeLeft\n\n`takeLeft` takes two parsers, _left_ and _right_, and returns a new parser that first matches the _left_, then the _right_, and keeps the value matched by the _left_.\n\n**Example**\n\n```JavaScript\nconst newParser = takeLeft (str ('hello ')) (str ('world'))\n\nnewParser.run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: \"hello\",\n//      index: 11,\n//      data: null\n//    }\n```\n\n#### recursiveParser\n\n`recursiveParser` takes a function that returns a parser (a thunk), and returns that same parser. This is needed in order to create _recursive parsers_ because JavaScript is not a \"lazy\" language.\n\nIn the following example both the `value` parser and the `matchArray` parser are defined in terms of each other, so one must be one **must** be defined using `recursiveParser`.\n\n**Example**\n\n```JavaScript\nconst value = recursiveParser (() =\u003e choice ([\n  matchNum,\n  matchStr,\n  matchArray\n]));\n\nconst betweenSquareBrackets = between (char ('[')) (char (']'));\nconst commaSeparated = sepBy (char (','));\nconst spaceSeparated = sepBy (char (' '));\n\nconst matchNum = digits;\nconst matchStr = letters;\nconst matchArray = betweenSquareBrackets (commaSeparated (value));\n\nspaceSeparated(value).run('abc 123 [42,somethingelse] 45')\n// -\u003e {\n//      isError: false,\n//      result: [ \"abc\", \"123\", [ \"42\", \"somethingelse\" ], \"45\" ],\n//      index: 29,\n//      data: null\n//    }\n```\n\n#### tapParser\n\n`tapParser` takes a function and returns a parser that does nothing and consumes no input, but runs the provided function on the last parsed value. This is intended as a debugging tool to see the state of parsing at any point in a sequential operation like `sequenceOf` or `pipeParsers`.\n\n**Example**\n\n```JavaScript\nconst newParser = sequenceOf ([\n  letters,\n  tapParser(console.log),\n  char (' '),\n  letters\n]);\n\nnewParser.run('hello world')\n// -\u003e [console.log]: Object {isError: false, error: null, target: \"hello world\", data: null, index: 5, …}\n// -\u003e {\n//      isError: false,\n//      result: [ \"hello\", \"hello\", \" \", \"world\" ],\n//      index: 11,\n//      data: null\n//    }\n```\n\n#### decide\n\n`decide` takes a function that recieves the last matched value and returns a new parser. It's important that the function **always** returns a parser. If a valid one cannot be selected, you can always use [fail](#fail).\n\n`decide` allows an author to create a [context-sensitive grammar](https://en.wikipedia.org/wiki/Context-sensitive_grammar).\n\n**Example**\n\n```JavaScript\nconst newParser = sequenceOf ([\n  takeLeft (letters) (char (' ')),\n  decide (v =\u003e {\n    switch (v) {\n      case 'asLetters': return letters;\n      case 'asDigits': return digits;\n      default: return fail(`Unrecognised signifier '${v}'`);\n    }\n  })\n]);\n\nnewParser.run('asDigits 1234')\n// -\u003e {\n//      isError: false,\n//      result: [ \"asDigits\", \"1234\" ],\n//      index: 13,\n//      data: null\n//    }\n\nnewParser.run('asLetters hello')\n// -\u003e {\n//      isError: false,\n//      result: [ \"asLetters\", \"hello\" ],\n//      index: 15,\n//      data: null\n//    }\n\nnewParser.run('asPineapple wayoh')\n// -\u003e {\n//      isError: true,\n//      error: \"Unrecognised signifier 'asPineapple'\",\n//      index: 12,\n//      data: null\n//    }\n```\n\n#### mapTo\n\n`mapTo` takes a function and returns a parser does not consume input, but instead runs the provided function on the last matched value, and set that as the new last matched value. This function can be used to apply structure or transform the values as they are being parsed.\n\n**Example**\n\n```JavaScript\nconst newParser = pipeParsers([\n  letters,\n  mapTo(x =\u003e {\n    return {\n      matchType: 'string',\n      value: x\n    }\n  })\n]);\n\nnewParser.run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: {\n//        matchType: \"string\",\n//        value: \"hello\"\n//      },\n//      index: 5,\n//      data: null\n//    }\n```\n\n#### errorMapTo\n\n`errorMapTo` is like [mapTo](#mapto) but it transforms the error value. The function passed to `errorMapTo` gets the _current error message_ as its first argument and the _index_ that parsing stopped at as the second.\n\n**Example**\n\n```JavaScript\nconst newParser = pipeParsers([\n  letters,\n  errorMapTo((message, index) =\u003e `Old message was: [${message}] @ index ${index}`)\n]);\n\nnewParser.run('1234')\n// -\u003e {\n//      isError: true,\n//      error: \"Old message was: [ParseError (position 0): Expecting letters] @ index 0\",\n//      index: 0,\n//      data: null\n//    }\n```\n\n#### fail\n\n`fail` takes an _error message_ string and returns a parser that always fails with the provided _error message_.\n\n**Example**\n\n```JavaScript\nfail('Nope').run('hello world')\n// -\u003e {\n//      isError: true,\n//      error: \"Nope\",\n//      index: 0,\n//      data: null\n//    }\n```\n\n#### succeedWith\n\n`succeedWith` takes an value and returns a parser that always matches that value and does not consume any input.\n\n**Example**\n\n```JavaScript\nsucceedWith ('anything').run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: \"anything\",\n//      data: null\n//      index: 0,\n//    }\n```\n\n#### either\n\n`either` takes a parser and returns a parser that will always succeed, but the captured value will be an Either, indicating success or failure.\n\n**Example**\n\n```JavaScript\neither(fail('nope!')).run('hello world')\n// -\u003e {\n//      isError: false,\n//      result: {\n//        isError: true,\n//        value: \"nope!\"\n//      },\n//      index: 0,\n//      data: null\n//    }\n```\n\n#### toPromise\n\n`toPromise` converts a `ParserResult` (what is returned from `.run`) into a `Promise`.\n\n**Example**\n\n```JavaScript\nconst parser = str('hello');\n\ntoPromise(parser.run('hello world'))\n  .then(console.log)\n  .catch(({error, index, data}) =\u003e {\n    console.log(error);\n    console.log(index);\n    console.log(data);\n  });\n// -\u003e [console.log] hello\n\ntoPromise(parser.run('goodbye world'))\n  .then(console.log)\n  .catch(({error, index, data}) =\u003e {\n    console.log('Error!');\n    console.log(error);\n    console.log(index);\n    console.log(data);\n  });\n// -\u003e [console.log] Error!\n// -\u003e [console.log] ParseError (position 0): Expecting string 'hello', got 'goodb...'\n// -\u003e [console.log] 0\n// -\u003e [console.log] null\n```\n\n#### toValue\n\n`toValue` converts a `ParserResult` (what is returned from `.run`) into a regular value, and throws an error if the result contained one.\n\n**Example**\n\n```JavaScript\nconst result = str ('hello').run('hello worbackgroiund\u003chAld');\n\ntry {\n  const value = toValue(result);\n  console.log(value);\n  // -\u003e 'hello'\n} catch (parseError) {\n  console.error(parseError.message)\n}\n```\n\n#### parse\n\n`parse` takes a parser and input (which may be a `string`, [`TypedArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray), [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer), or [`DataView`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView)), and returns the result of parsing the input using the parser.\n\n**Example**\n\n```JavaScript\nparse (str ('hello')) ('hello')\n// -\u003e {\n//      isError: false,\n//      result: \"hello\",\n//      index: 5,\n//      data: null\n//    }\n```\n\n## A note on recursive grammars\n\nIf you're parsing a programming language, a configuration, or anything of sufficient complexity, it's likely that you'll need to define some parsers in terms of each other. You might want to do something like:\n\n```JavaScript\nconst value = choice ([\n  matchNum,\n  matchStr,\n  matchArray\n]);\n\nconst betweenSquareBrackets = between (char ('[')) (char (']'));\nconst commaSeparated = sepBy (char (','));\n\nconst matchNum = digits;\nconst matchStr = letters;\nconst matchArray = betweenSquareBrackets (commaSeparated (value));\n```\n\nIn this example, we are trying to define `value` in terms of `matchArray`, and `matchArray` in terms of `value`. This is problematic in a language like JavaScript because it is what's known as an [\"eager language\"](https://en.wikipedia.org/wiki/Eager_evaluation). Because the definition of `value` is a function call to `choice`, the arguments of `choice` must be fully evaluated, and of course none of them are yet. If we just move the definition below `matchNum`, `matchStr`, and `matchArray`, we'll have the same problem with `value` not being defined before `matchArray` wants to use it.\n\nWe can get around JavaScript's eagerness by using [recursiveParser](#recursiveparser), which takes a function that returns a parser:\n\n```JavaScript\nconst value = recursiveParser(() =\u003e choice ([\n  matchNum,\n  matchStr,\n  matchArray\n]));\n\nconst betweenSquareBrackets = between (char ('[')) (char (']'));\nconst commaSeparated = sepBy (char (','));\n\nconst matchNum = digits;\nconst matchStr = letters;\nconst matchArray = betweenSquareBrackets (commaSeparated (value));\n```\n\n## Fantasy Land\n\nThis library implements the following Fantasy Land (v3) interfaces:\n\n- [Functor](https://github.com/fantasyland/fantasy-land#functor)\n- [Apply](https://github.com/fantasyland/fantasy-land#apply)\n- [Applicative](https://github.com/fantasyland/fantasy-land#applicative)\n- [Chain](https://github.com/fantasyland/fantasy-land#chain)\n\nEvery parser, or parser made from composing parsers has a `.of`, `.map`, `.chain`, and `.ap` method.\n\n### Equivalent Operations\n\n#### of\n\n```JavaScript\nParser.of(42)\n\n// is equivalent to\n\nsucceedWith (42)\n```\n\n#### map\n\n```JavaScript\nletters.map (fn)\n\n// is equivalent to\n\npipeParsers ([ letters, mapTo (fn) ])\n```\n\n#### chain\n\n```JavaScript\nletters.chain (x =\u003e someOtherParser)\n\n// is equivalent to\n\npipeParsers ([ letters, decide (x =\u003e someOtherParser) ])\n```\n\n#### ap\n\n```JavaScript\nletters.ap (Parser.of (fn))\n\n// is equivalent to\n\npipeParsers ([\n  sequenceOf ([ succeedWith (fn), letters ]),\n  mapTo (([fn, x]) =\u003e fn(x))\n]);\n```\n\n## Name\n\nThe name is also derived from parsec, which in astronomical terms is an [\"astronomical unit [that] subtends an angle of one arcsecond\"](https://en.wikipedia.org/wiki/Parsec).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrancisrstokes%2Farcsecond","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffrancisrstokes%2Farcsecond","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrancisrstokes%2Farcsecond/lists"}