{"id":22903056,"url":"https://github.com/amekusa/cs-parser","last_synced_at":"2026-04-11T08:06:14.053Z","repository":{"id":84582615,"uuid":"122226981","full_name":"amekusa/cs-parser","owner":"amekusa","description":"Context-sensitive parser framework","archived":false,"fork":false,"pushed_at":"2025-05-19T06:21:51.000Z","size":1395,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-29T20:16:11.373Z","etag":null,"topics":["dsl","javascript","language","npm","parser"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/amekusa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","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-02-20T16:52:47.000Z","updated_at":"2025-05-19T06:21:54.000Z","dependencies_parsed_at":null,"dependency_job_id":"6ec0772a-5c25-4bda-ab44-3bcb7ea3063f","html_url":"https://github.com/amekusa/cs-parser","commit_stats":{"total_commits":104,"total_committers":1,"mean_commits":104.0,"dds":0.0,"last_synced_commit":"849d79e2683481d0ada21b326301586a8cdf60fb"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/amekusa/cs-parser","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amekusa%2Fcs-parser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amekusa%2Fcs-parser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amekusa%2Fcs-parser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amekusa%2Fcs-parser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/amekusa","download_url":"https://codeload.github.com/amekusa/cs-parser/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amekusa%2Fcs-parser/sbom","scorecard":{"id":188982,"data":{"date":"2025-08-11","repo":{"name":"github.com/amekusa/cs-parser","commit":"b8c9715930b6d174ad97825b699892bd10c65995"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"1 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-16T20:17:00.455Z","repository_id":84582615,"created_at":"2025-08-16T20:17:00.455Z","updated_at":"2025-08-16T20:17:00.455Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31673078,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T17:19:37.612Z","status":"online","status_checked_at":"2026-04-11T02:00:05.776Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["dsl","javascript","language","npm","parser"],"created_at":"2024-12-14T02:31:49.442Z","updated_at":"2026-04-11T08:06:14.025Z","avatar_url":"https://github.com/amekusa.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# [![CS Parser](https://raw.githubusercontent.com/amekusa/cs-parser/master/logo.png \"Context Sensitive Parser\")](https://github.com/amekusa/cs-parser)\n\n[![npm version](https://badge.fury.io/js/cs-parser.svg)](https://badge.fury.io/js/cs-parser) [![Apache License 2.0](http://img.shields.io/badge/license-Apache_2.0-blue.svg?style=flat)](LICENSE)\n\n\u003c!-- TOC depthfrom:2 depthto:3 --\u003e\n\n- [Write Your Own Parser](#write-your-own-parser)\n- [Getting Started](#getting-started)\n- [Examples](#examples)\n- [Basics](#basics)\n- [Defining a rule](#defining-a-rule)\n    - [Callback methods](#callback-methods)\n- [Let's parse!](#lets-parse)\n    - [Root context](#root-context)\n    - [Basic example](#basic-example)\n- [How do I debug my parser?](#how-do-i-debug-my-parser)\n- [Links](#links)\n\n\u003c!-- /TOC --\u003e\n\n---\n\n\n## Write Your Own Parser\nCS Parser is a tiny JS framework that gives you the power to easily write a parser for code in any language or data in any format.\nIt also can help you to develop your own languages or data formats.\n\nSince the mechanics of CS Parser is pretty simple and straightforward, its APIs are very easy to learn and use.\nWith the help of them, and if you have a basic knowledge of JavaScript, you can write a clean and readable parser for your specific needs without extensive coding.\n\n\n## Getting Started\nFirst, you have to install `cs-parser` via `npm`.\n\n```sh\nnpm i cs-parser\n```\n\nNext, `import` (ESM) or `require` (CJS) it in your JS.\n\n```js\n// ES Module\nimport csp from 'cs-parser'\n\n// CommonJS\nconst csp = require('cs-parser')\n```\n\nThen, call `create` method to get a [Parser](https://amekusa.github.io/cs-parser/latest/Parser.html) object which is the main API provider.\n\n```js\nlet parser = csp.create()\n```\n\n\n## Examples\nBefore we proceed to explain the basics, here are some working examples if you want to take a quick look first:\n- [examples/employees.js](https://github.com/amekusa/cs-parser/blob/master/examples/employees.js)\n- [examples/docblocks.js](https://github.com/amekusa/cs-parser/blob/master/examples/docblocks.js)\n\n\n## Basics\nThe workflow is as follows:\n\n#### 1. Define rules with `addRule` method.\n```js\nparser.addRule({ /* 1st rule definition */ })\nparser.addRule({ /* 2nd rule definition */ })\n  // You can add rules as many as you want.\n```\n\n#### 2. Parse data with `parse` or `parseFile` methods.\n```js\n// For data as a string\nlet results = parser.parse(data)\n\n// For data in a file\nlet results = await parser.parseFile('file/to/parse')\n```\n\n#### 3. Use the results, scanning with `traverse` method.\n```js\nresults.traverse(each =\u003e {\n  console.log(each.data)\n})\n```\n\n\n## Defining a rule\nA rule definition that you pass to `addRule()` has to be an object with some specific properties and methods.\n\n```js\nparser.addRule({\n  from: '{',\n  to:   '}'\n})\n```\n\n`from` and `to` properties determine **where the rule applies to in data**.\nSo the above rule means:\n- Activate this rule if the parser reached at `{`\n- Deactivate this rule if the parser reached at `}`\n\nYou can also use regex like this:\n\n```js\nparser.addRule({\n  from: /(\\w).* {/,\n  to:   '}'\n})\n```\n\nThis rule will be activated when the current reading buffer matches with\nthe pattern like: `something {` .\n\n### Callback methods\nA rule has to have at least one of `init`, `parse`, and `fin` callback methods.\n\n```js\nparser.addRule({\n  from: /(\\w).* {/,\n  to:   '}',\n  init(cx, chunk, matches) { ... },\n  parse(cx, chunk) { ... },\n  fin(cx, chunk, matches) { ... }\n})\n```\n\n- `init` will be called once when the rule is activated.\n- `parse` will be called for **every chunk** when the rule is active.\n- `fin`  will be called once when the rule is deactivated.\n\nThe 1st parameter `cx` is **a context object** (explained later) that is currently associated with this rule.\u003cbr\u003e\nThe 2nd parameter `chunk` is **the current chunk** (explained later) of data that the parser has just processed at the time.\u003cbr\u003e\nThe 3rd parameter of `init` / `fin` is optional, that are **results of regex matching** of `from` / `to` if they are regex.\n\n#### Chunk\nBy default, the parser processes the data **line-by-line**, and each line is passed to the 2nd parameter of the callback methods as \"chunk\". However, you can change this behavior if you want to, by setting `splitter` property to any string other than `\\n` (linebreak).\n\n#### Context object\nWhen a rule got activated, the parser generates a context object for it and also adds it to the context stack (the root context).\nThe rule can manipulate the associated context object with its callback methods however you want.\nIt can be said that the relationship between a rule and a context object is similar to the one between **a class and its instance**.\n\nFor convenience, a context object has `data` property which is just a plain object, so you can store any kinds of data in it, like this:\n\n```js\ninit(cx, chunk, matches) {\n  cx.data.name  = matches[1]\n  cx.data.lines = []\n\n  // Or you can just reassign a new value\n  cx.data = {\n    name:  matches[1],\n    lines: []\n  }\n}\n```\n\nVia their 1st parameter, `init`, `parse`, and `fin` callback methods can share the same instance of context object, like this:\n\n```js\nparse(cx, chunk) {\n  cx.data.lines.push(chunk)\n},\nfin(cx) {\n  console.log('Block: ' + cx.data.name)\n  console.log('Total Lines: ' + cx.data.lines.length)\n}\n```\n\n\n## Let's parse!\nOnce you've done with defining all the necessary rules, it's time to actually parse data and use the results for your purpose.\n\nIf you have a data as a string or a `Buffer` object, pass it to `parse()` method.\n\n```js\nlet data = '...' // Data to parse\nlet results = parser.parse(data)\n```\n\nAs a result, it returns **the \"root\" context** (explained later) which contains all the contexts that were generated throughout the entire parsing process.\n\nThere is another option: `parseFile()`, which parses the content of other file asynchronously.\n\n```js\n// With 'await'\nlet results = await parser.parseFile('path/to/file')\n\n// Or in the 'Promise' way\nparser.parseFile('path/to/file').then(results =\u003e {\n  ...\n});\n```\n\nSince its process is implemented as in a *streaming* manner, it is recommended over `parse()` method if the data is large.\n\n### Root context\nRoot context is a top-level context object that contains all the context objects generated throughout the entire parsing process.\n\nTo access to each context individually, pass a callback to `traverse` method of the root context.\n\n```js\nlet results = parser.parse(data)\nresults.traverse(each =\u003e {\n  console.log('Block: ' + each.data.name)\n})\n```\n\nEach context is passed to the 1st parameter of the callback you passed.\n\n### Basic example\nNow it's a good time for you to take a closer look at the 1st example: [employees.js](https://github.com/amekusa/cs-parser/blob/master/examples/employees.js).\u003cbr\u003e\nWe also recommend to download the file (or clone this repo) and see it running with `node`, and do some experiments by yourself.\n\n```sh\nnode employees.js\n```\n\nThere are more cool features like **nesting contexts**, which we cannot cover in this README because it would be too long.\u003cbr\u003e\nIf you are interested, see this example: [docblocks.js](https://github.com/amekusa/cs-parser/blob/master/examples/docblocks.js)\u003cbr\u003e\nAlso please check the [full documentations](https://amekusa.github.io/cs-parser/latest/).\n\n\n## How do I debug my parser?\nUse `outline()` method of [Context](https://amekusa.github.io/cs-parser/latest/Context.html) that outputs the outline of the structure of a context and all the sub-contexts of it.\n\nThis would be helpful to ensure if your parser correctly analyzed the structure of the data. Let's see the outline of the result of [employees.js](https://github.com/amekusa/cs-parser/blob/master/examples/employees.js).\n\n```js\nlet result = parser.parse(data)\nconsole.debug(result.outline())\n```\n\nThe output:\n\n```sh\nroot\n  anonymous\n  anonymous\n  anonymous\n  anonymous\n```\n\nThe reason it shows `anonymous` is, the rule associated with them doesn't have `name` property.\n\nLet's add `name: 'employee',` to the rule, and see the difference of `outline()`.\n\n```js\nparser.addRule({\n\tname: 'employee', // \u003c-Added\n\tfrom: /(\\w+) {/, // Starts with '(word) {'\n\tto:   '}',       //   Ends with '}'\n...\n```\n\nThe output:\n\n```sh\nroot\n  employee\n  employee\n  employee\n  employee\n```\n\nIt's somewhat better. But you can improve this output even more.\n\nWith `express` callback, you can totally customize how a context is expressed by `outline()`.\n\n```js\nparser.addRule({\n\tfrom: /(\\w+) {/, // Starts with '(word) {'\n\tto:   '}',       //   Ends with '}'\n\t...\n\texpress(cx) { // \u003c-Added\n\t\treturn 'employee: ' + cx.data.name\n\t}\n})\n```\n\nThe output:\n\n```sh\nroot\n  employee: Alice\n  employee: Bob\n  employee: Charlie\n  employee: Dolly\n```\n\nNow you can get much better outline!\n\n\n## Links\n+ [Documentations](https://amekusa.github.io/cs-parser/latest/)\n+ [GitHub](https://github.com/amekusa/cs-parser)\n\n\n\u003c!--TRUNCATE:START--\u003e\n---\n\n\u0026copy; 2018 Satoshi Soma ([amekusa.com](https://amekusa.com))\nCS Parser is licensed under the Apache License, Version 2.0\n\u003c!--TRUNCATE:END--\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famekusa%2Fcs-parser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famekusa%2Fcs-parser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famekusa%2Fcs-parser/lists"}