{"id":43770189,"url":"https://github.com/cesbit/jsleri","last_synced_at":"2026-02-05T16:34:31.784Z","repository":{"id":34865036,"uuid":"38866741","full_name":"cesbit/jsleri","owner":"cesbit","description":"Parser for JavaScript","archived":false,"fork":false,"pushed_at":"2025-11-18T18:15:26.000Z","size":2320,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-11-18T20:11:45.954Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"payara/Cloud-Connectors","license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cesbit.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,"zenodo":null}},"created_at":"2015-07-10T07:16:27.000Z","updated_at":"2025-11-18T18:14:04.000Z","dependencies_parsed_at":"2023-11-14T12:31:02.836Z","dependency_job_id":"745f11de-3576-4fee-90bd-cd0ade14c6fc","html_url":"https://github.com/cesbit/jsleri","commit_stats":null,"previous_names":["transceptor-technology/jsleri"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/cesbit/jsleri","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesbit%2Fjsleri","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesbit%2Fjsleri/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesbit%2Fjsleri/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesbit%2Fjsleri/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cesbit","download_url":"https://codeload.github.com/cesbit/jsleri/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesbit%2Fjsleri/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29125877,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-05T14:05:12.718Z","status":"ssl_error","status_checked_at":"2026-02-05T14:03:53.078Z","response_time":65,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2026-02-05T16:34:31.103Z","updated_at":"2026-02-05T16:34:31.774Z","avatar_url":"https://github.com/cesbit.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![CI](https://github.com/cesbit/jsleri/workflows/CI/badge.svg)](https://github.com/cesbit/jsleri/actions)\n[![Release Version](https://img.shields.io/github/release/cesbit/jsleri)](https://github.com/cesbit/jsleri/releases)\n\n# Javascript Left-Right Parser\nJsleri is an easy-to-use language parser for JavaScript.\n\n---------------------------------------\n  * [Installation](#installation)\n  * [Related projects](#related-projects)\n  * [Quick usage](#quick-usage)\n  * [Grammar](#grammar)\n    * [Grammar.parse()](#parse)\n  * [Result](#result)\n    * [isValid](#isvalid)\n    * [Position](#position)\n    * [Tree](#tree)\n    * [Expecting](#expecting)\n  * [Elements](#elements)\n    * [Keyword](#keyword)\n    * [Regex](#regex)\n    * [Token](#token)\n    * [Tokens](#tokens)\n    * [Sequence](#sequence)\n    * [Choice](#choice)\n    * [Repeat](#repeat)\n    * [List](#list)\n    * [Optional](#optional)\n    * [Ref](#ref)\n    * [Prio](#prio)\n\n---------------------------------------\n\n## Installation\nUsing npm:\n\n```\n$ npm i jsleri\n```\n\nIn your project:\n\n```javascript\nimport * as jsleri from 'jsleri';\n// Exposes:\n// - jsleri.version\n// - jsleri.noop\n// - jsleri.Keyword\n// - jsleri.Regex\n// - jsleri.Token\n// - jsleri.Tokens\n// - jsleri.Sequence\n// - jsleri.Choice\n// - jsleri.Repeat\n// - jsleri.List\n// - jsleri.Optional\n// - jsleri.Ref\n// - jsleri.Prio\n// - jsleri.THIS\n// - jsleri.Grammar\n// - jsleri.EOS\n\n```\n\nOr... download the latest release from [here](https://github.com/cesbit/jsleri/releases/latest) and load the file in inside your project.\nFor example:\n```html\n\u003c!-- Add this line to the \u003chead\u003e section to expose window.jsleri --\u003e\n\u003cscript src=\"jsleri-1.1.15.min.js\"\u003e\u003c/script\u003e\n```\n\n## Related projects\n- [pyleri](https://github.com/cesbit/pyleri): Python parser (can export grammar to pyleri, cleri and jsleri)\n- [libcleri](https://github.com/cesbit/libcleri): C parser\n- [goleri](https://github.com/cesbit/goleri): Go parser\n- [jleri](https://github.com/cesbit/jleri): Java parser\n\n\n## Quick usage\n```javascript\nimport { Regex, Keyword, Sequence, Grammar } from 'jsleri';\n\n// create your grammar\nclass MyGrammar extends Grammar {\n    static START = Sequence(\n        Keyword('hi'),\n        Regex('(?:\"(?:[^\"]*)\")+')\n    );\n}\n\n// create a instance of your grammar\nconst myGrammar = new MyGrammar();\n\n// do something with the grammar\nalert(myGrammar.parse('hi \"Iris\"').isValid);  // alerts true\nalert(myGrammar.parse('hello \"Iris\"').isValid);  // alerts false\n```\n\n## Grammar\nWhen writing a grammar you should subclass Grammar. A Grammar expects at least a `START` property so the parser knows where to start parsing. Grammar has a parse method: `parse()`.\n\n\n### parse\nsyntax:\n```javascript\nmyGrammar.parse(string)\n```\nThe `parse()` method returns a result object which has the following properties that are further explained in [Result](#result):\n- `expecting`\n- `isValid`\n- `pos`\n- `tree`\n\n\n## Result\nThe result of the `parse()` method contains 4 properties that will be explained next.\n\n### isValid\n`isValid` returns a boolean value, `True` when the given string is valid according to the given grammar, `False` when not valid.\nnode_result.isValid) # =\u003e False\n\nLet us take the example from Quick usage.\n```javascript\nalert(myGrammar.parse('hello \"Iris\"').isValid);  // alerts false\n```\n\n### Position\n`pos` returns the position where the parser had to stop. (when `isValid` is `True` this value will be equal to the length of the given string with `str.rstrip()` applied)\n\nLet us take the example from Quick usage.\n```javascript\nalert(myGrammar.parse('hello \"Iris\"').pos);  // alerts 0\n```\n\n### Tree\n`tree` contains the parse tree. Even when `isValid` is `False` the parse tree is returned but will only contain results as far as parsing has succeeded. The tree is the root node which can include several `children` nodes. The structure will be further clarified in the example found in the \"example\" folder. It explains a way of visualizing the parse tree.\n\nThe nodes in the example contain 5 properties:\n\n- `start` property returns the start of the node object.\n- `end` property returns the end of the  node object.\n- `element` returns the type of [Element](#elements) (e.g. Repeat, Sequence, Keyword, etc.).\n- `string` returns the string that is parsed.\n- `children` can return a node object containing deeper layered nodes provided that there are any. In our example the root node has an element type `Repeat()`, starts at 0 and ends at 24, and it has two `children`. These children are node objects that have both an element type `Sequence`, start at 0 and 12 respectively, and so on.\n\n\n### Expecting\n`expecting` returns an array containing elements which jsleri expects at `pos`. Even if `isValid` is true there might be elements in this object, for example when an `Optional()` element could be added to the string. Expecting is useful if you want to implement things like auto-completion, syntax error handling, auto-syntax-correction etc. In the \"example\" folder you will find an example. Run the html script in a browser. You will see that `expecting` is used to help you create a valid query string for SiriDB. SiriDB is an open source time series database with its own grammar class. Start writing something, click one of the options that appear and see what happens.\n\n\n## Elements\nJsleri has several Elements which can be used to create a grammar.\n\n### Keyword\n```javascript\nKeyword(keyword, ignCase)\n```\nThe parser needs to match the keyword which is just a string. When matching keywords we need to tell the parser what characters are allowed in keywords. By default Jsleri uses `^\\w+` which equals to `^[A-Za-z0-9_]+`. Keyword() accepts one more argument `ignCase` to tell the parser if we should match case insensitive.\n\nExample:\n```javascript\nconst grammar = new Grammar(\n    Keyword('tic-tac-toe', true),   // case insensitive\n    '[A-Za-z-]+'                    // alternative keyword matching\n);\n\nconsole.log(grammar.parse('Tic-Tac-Toe').isValid);  // true\n```\n\n### Regex\n```javascript\nRegex(pattern, ignCase)\n```\nThe parser compiles a regular expression. Argument ignCase is set to `false` by default but can be set to `true` if you want the regular expression to be case insensitive. Note that `ignore case` is the only `re` flag from pyleri which will be compiled and accepted by `jsleri`.\n\nSee the [Quick Usage](#quick-usage) example for how to use `Regex`.\n\n### Token\n```javascript\nToken(token)\n```\nA token can be one or more characters and is usually used to match operators like `+`, `-`, `//` and so on. When we parse a string object where jsleri expects an element, it will automatically be converted to a `Token()` object.\n\nExample:\n```javascript\n// We could just write '-' instead of Token('-')\n// because any string will be converted to Token()\nconst grammar = new Grammar(List(Keyword('ni'), Token('-')));\n\nconsole.log(grammar.parse('ni-ni-ni-ni-ni').isValid);  // true\n```\n\n### Tokens\n```javascript\nTokens(tokens)\n```\nCan be used to register multiple tokens at once. The tokens argument should be a string with tokens separated by spaces. If given tokens are different in size the parser will try to match the longest tokens first.\n\nExample:\n```javascript\nconst grammar = new Grammar(List(Keyword('ni'), Tokens('+ - !=')));\n\ngrammar.parse('ni + ni != ni - ni').isValid  // =\u003e True\n```\n\n### Sequence\n```javascript\nSequence(element, element, ...)\n```\nThe parser needs to match each element in a sequence.\n\nExample:\n```javascript\nconst grammar = new Grammar(Sequence(\n    Keyword('Tic'),\n    Keyword('Tac'),\n    Keyword('Toe')\n));\nconsole.log(grammar.parse('Tic Tac Toe').isValid);  // true\n```\n\n### Repeat\n```javascript\nRepeat(element, mi, ma)\n```\nThe parser needs at least `mi` elements and at most `ma` elements. When `ma` is set to `undefined` we allow unlimited number of elements. `mi` can be any integer value equal or higher than 0 but not larger then `ma`. The default value for `mi` is 0 and `undefined` for `ma`\n\nExample:\n```javascript\nconst grammar = new Grammar(Repeat(Keyword('ni')));\n\nconsole.log(grammar.parse('ni ni ni ni').isValid);  // true\n```\n\nOne should avoid to bind a name to the same element twice and Repeat(element, 1, 1) is a common solution to bind the element a second (or more) time(s).\n\nFor example consider the following:\n```javascript\nconst r_name = Regex('(?:\"(?:[^\"]*)\")+');\n\n// Do NOT do this\nconst r_address = r_name; // WRONG\n\n// Instead use Repeat\nconst r_address = Repeat(r_name, 1, 1);  // Correct\n```\n\n### List\n```javascript\nList(element, delimiter, mi, ma, opt)\n```\nList is like Repeat but with a delimiter. A comma is used as default delimiter but any element is allowed. When a string is used as delimiter it will be converted to a Token element. `mi` and `ma` work excatly like with [Repeat](#repeat). `opt` kan be set to set to `true` to allow the list to end with a delimiter. By default this is set to `false` which means the list has to end with an element.\n\nExample:\n```javascript\nconst grammar = new Grammar(List(Keyword('ni')));\n\nconsole.log(grammar.parse('ni, ni, ni, ni, ni').isValid);  // true\n```\n\n### Optional\n```javascript\nOptional(element)\n```\nThe parser looks for an optional element. It is like using `Repeat(element, 0, 1)` but we encourage to use `Optional` since it is more readable. (and slightly faster)\n\nExample:\n```javascript\nconst grammar = new Grammar(Sequence(\n    Keyword('hi'),\n    Optional(Regex('(?:\"(?:[^\"]*)\")+'))\n));\n\nconsole.log(grammar.parse('hi \"Iris\"').isValid);  // true\nconsole.log(grammar.parse('hi').isValid);  // true\n```\n\n### Ref\n```javascript\nRef(Constructor)\n```\nThe grammar can make a forward reference to make recursion possible. In the example below we create a forward reference to START but note that\na reference to any element can be made.\n\n\u003eWarning: A reference is not protected against testing the same position in\n\u003ein a string. This could potentially lead to an infinite loop.\n\u003eFor example:\n\u003e```javascript\n\u003elet r = Ref(Optional);\n\u003er.set(Optional(r));  // DON'T DO THIS\n\u003e```\n\u003eUse [Prio](#prio) if such recursive construction is required.\n\nExample:\n```javascript\n// make a forward reference START to a Sequence.\nlet START = Ref(Sequence);\n\n// we can now use START\nconst ni_item = Choice(Keyword('ni'), START);\n\n// here we actually set START\nSTART.set(Sequence('[', List(ni_item), ']'));\n\n// create and test the grammar\nconst grammar = Grammar(START);\nconsole.log(grammar.parse('[ni, [ni, [], [ni, ni]]]').isValid);  // true\n```\n\n### Prio\n```javascript\nPrio(element, element, ...)\n```\nChoose the first match from the prio elements and allow `THIS` for recursive operations. With `THIS` we point to the `Prio` element. Probably the example below explains how `Prio` and `THIS` can be used.\n\n\u003eNote: Use a [Ref](#ref) when possible.\n\u003eA `Prio` element is required when the same position in a string is potentially\n\u003echecked more than once.\n\nExample:\n```javascript\nconst grammar = new Grammar(Prio(\n    Keyword('ni'),\n    Sequence('(', THIS, ')'),\n    Sequence(THIS, Keyword('or'), THIS),\n    Sequence(THIS, Keyword('and'), THIS)\n));\n\nconsole.log(grammar.parse('(ni or ni) and (ni or ni)').isValid);  // true\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcesbit%2Fjsleri","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcesbit%2Fjsleri","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcesbit%2Fjsleri/lists"}