{"id":16758217,"url":"https://github.com/foo123/grammartemplate","last_synced_at":"2025-04-10T17:11:41.376Z","repository":{"id":36680167,"uuid":"40986601","full_name":"foo123/GrammarTemplate","owner":"foo123","description":"GrammarTemplate: versatile and intuitive grammar-based templating for PHP, Python, JavaScript","archived":false,"fork":false,"pushed_at":"2022-08-02T11:54:52.000Z","size":183,"stargazers_count":8,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-24T14:51:23.002Z","etag":null,"topics":["grammar-specification","grammar-template","template-engine","template-language"],"latest_commit_sha":null,"homepage":"https://foo123.github.io/examples/grammar-template/","language":"PHP","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/foo123.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}},"created_at":"2015-08-18T17:23:55.000Z","updated_at":"2023-01-15T03:27:37.000Z","dependencies_parsed_at":"2022-08-08T16:31:06.500Z","dependency_job_id":null,"html_url":"https://github.com/foo123/GrammarTemplate","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo123%2FGrammarTemplate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo123%2FGrammarTemplate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo123%2FGrammarTemplate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo123%2FGrammarTemplate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/foo123","download_url":"https://codeload.github.com/foo123/GrammarTemplate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248261684,"owners_count":21074223,"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":["grammar-specification","grammar-template","template-engine","template-language"],"created_at":"2024-10-13T04:04:31.072Z","updated_at":"2025-04-10T17:11:41.355Z","avatar_url":"https://github.com/foo123.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GrammarTemplate\n\n`GrammarTemplate` versatile and intuitive grammar-based templating for PHP, Python, Browser / Node.js / XPCOM Javascript (see for example [here](https://github.com/foo123/Dialect) and [here](https://github.com/foo123/Xpresion) and [eventualy here](https://github.com/foo123/RhoLambda))\n\n\n![GrammarTemplate](/grammartemplate.jpg)\n\n\n[Etymology of *\"grammar\"*](http://www.etymonline.com/index.php?term=grammar)\n[Etymology of *\"template\"*](http://www.etymonline.com/index.php?term=template)\n\n\n**light-weight (~7.7kB minified, ~3.2kB zipped)**\n\n* `GrammarTemplate` is also a `XPCOM JavaScript Component` (Firefox) (e.g to be used in firefox browser addons/plugins)\n\n\n**version 3.0.0** [GrammarTemplate.js](https://raw.githubusercontent.com/foo123/GrammarTemplate/master/src/js/GrammarTemplate.js), [GrammarTemplate.min.js](https://raw.githubusercontent.com/foo123/GrammarTemplate/master/src/js/GrammarTemplate.min.js)\n\n[Live Playground Example](https://foo123.github.io/examples/grammar-template)\n\n[![GrammarTemplate Editor](/grammartemplate-editor.png)](https://foo123.github.io/examples/grammar-template)\n\n\n**see also:**\n\n* [ModelView](https://github.com/foo123/modelview.js) a simple, fast, powerful and flexible MVVM framework for JavaScript\n* [tico](https://github.com/foo123/tico) a tiny, super-simple MVC framework for PHP\n* [LoginManager](https://github.com/foo123/LoginManager) a simple, barebones agnostic login manager for PHP, JavaScript, Python\n* [SimpleCaptcha](https://github.com/foo123/simple-captcha) a simple, image-based, mathematical captcha with increasing levels of difficulty for PHP, JavaScript, Python\n* [Dromeo](https://github.com/foo123/Dromeo) a flexible, and powerful agnostic router for PHP, JavaScript, Python\n* [PublishSubscribe](https://github.com/foo123/PublishSubscribe) a simple and flexible publish-subscribe pattern implementation for PHP, JavaScript, Python\n* [Importer](https://github.com/foo123/Importer) simple class \u0026amp; dependency manager and loader for PHP, JavaScript, Python\n* [Contemplate](https://github.com/foo123/Contemplate) a fast and versatile isomorphic template engine for PHP, JavaScript, Python\n* [HtmlWidget](https://github.com/foo123/HtmlWidget) html widgets, made as simple as possible, both client and server, both desktop and mobile, can be used as (template) plugins and/or standalone for PHP, JavaScript, Python (can be used as [plugins for Contemplate](https://github.com/foo123/Contemplate/blob/master/src/js/plugins/plugins.txt))\n* [Paginator](https://github.com/foo123/Paginator)  simple and flexible pagination controls generator for PHP, JavaScript, Python\n* [Formal](https://github.com/foo123/Formal) a simple and versatile (Form) Data validation framework based on Rules for PHP, JavaScript, Python\n* [Dialect](https://github.com/foo123/Dialect) a cross-vendor \u0026amp; cross-platform SQL Query Builder, based on [GrammarTemplate](https://github.com/foo123/GrammarTemplate), for PHP, JavaScript, Python\n* [DialectORM](https://github.com/foo123/DialectORM) an Object-Relational-Mapper (ORM) and Object-Document-Mapper (ODM), based on [Dialect](https://github.com/foo123/Dialect), for PHP, JavaScript, Python\n* [Unicache](https://github.com/foo123/Unicache) a simple and flexible agnostic caching framework, supporting various platforms, for PHP, JavaScript, Python\n* [Xpresion](https://github.com/foo123/Xpresion) a simple and flexible eXpression parser engine (with custom functions and variables support), based on [GrammarTemplate](https://github.com/foo123/GrammarTemplate), for PHP, JavaScript, Python\n* [Regex Analyzer/Composer](https://github.com/foo123/RegexAnalyzer) Regular Expression Analyzer and Composer for PHP, JavaScript, Python\n\n### API\n\n**Grammar Template**\n\nA block inside `[..]` represents an optional block of `code` (depending on passed parameters) and `\u003c..\u003e` describe placeholders for `query` parameters / variables (i.e `non-terminals`).\nThe optional block of code depends on whether **all** optional parameters defined inside (with `\u003c?..\u003e`, `\u003c?!..\u003e` or `\u003c*..\u003e` and `\u003c{n,m}..\u003e` for rest parameters) exist. Then, that block (and any nested blocks it might contain) is output, else bypassed.\n\nA block defined with `:=[..]` represents a (recursive) sub-template, which can be used to render any deep/structured argument a needed (see below).\n\n\n```javascript\nvar GrammarTemplate = require(\"../src/js/GrammarTemplate.js\"), echo = console.log;\n\necho('GrammarTemplate.VERSION = ' + GrammarTemplate.VERSION);\necho( );\n\nvar tpl = \"SELECT \u003ccolumn.select\u003e[, \u003c*column.select\u003e]\\nFROM \u003ctable.from\u003e[, \u003c*table.from\u003e][\\nWHERE (\u003c?required.where\u003e) AND (\u003c?condition.where\u003e)][\\nWHERE \u003c?required.where\u003e\u003c?!condition.where\u003e][\\nWHERE \u003c?!required.where\u003e\u003c?condition.where\u003e][\\nGROUP BY \u003c?group\u003e[, \u003c*group\u003e]][\\nHAVING (\u003c?required.having\u003e) AND (\u003c?condition.having\u003e)][\\nHAVING \u003c?required.having\u003e\u003c?!condition.having\u003e][\\nHAVING \u003c?!required.having\u003e\u003c?condition.having\u003e][\\nORDER BY \u003c?order\u003e[, \u003c*order\u003e]][\\nLIMIT \u003coffset|0\u003e, \u003c?count\u003e]\";\n\nvar sql = new GrammarTemplate( tpl );\n\necho(\"input template:\");\necho(tpl);\n\necho( );\n\necho(\"output:\");\necho(sql.render({\n    column      : { select : [ 'field1', 'field2', 'field3', 'field4' ] },\n    table       : { from : [ 'tbl1', 'tbl2' ] },\n    condition   : { where : 'field1=1 AND field2=2', having : 'field3=1 OR field4=2' },\n    count       : 5\n}));\n```\n\n**output**\n```text\nGrammarTemplate.VERSION = 3.0.0\n\ninput template:\nSELECT \u003ccolumn.select\u003e[, \u003c*column.select\u003e]\nFROM \u003ctable.from\u003e[, \u003c*table.from\u003e][\nWHERE (\u003c?required.where\u003e) AND (\u003c?condition.where\u003e)][\nWHERE \u003c?required.where\u003e\u003c?!condition.where\u003e][\nWHERE \u003c?!required.where\u003e\u003c?condition.where\u003e][\nGROUP BY \u003c?group\u003e[, \u003c*group\u003e]][\nHAVING (\u003c?required.having\u003e) AND (\u003c?condition.having\u003e)][\nHAVING \u003c?required.having\u003e\u003c?!condition.having\u003e][\nHAVING \u003c?!required.having\u003e\u003c?condition.having\u003e][\nORDER BY \u003c?order\u003e[, \u003c*order\u003e]][\nLIMIT \u003coffset|0\u003e, \u003c?count\u003e]\n\noutput:\nSELECT field1, field2, field3, field4\nFROM tbl1, tbl2\nWHERE field1=1 AND field2=2\nHAVING field3=1 OR field4=2\nLIMIT 0, 5\n```\n\n```javascript\nvar GrammarTemplate = require(\"../src/js/GrammarTemplate.js\"), echo = console.log;\n\necho('GrammarTemplate.VERSION = ' + GrammarTemplate.VERSION);\necho( );\n\n/*\n    i.e: \n    foreach \"expression:terms\" as \"term\":\n        foreach \"term:factors\" as \"factor\":\n            ..\n    \n    here an :EXPR template is defined which itself uses (anonymous) sub-templates\n    it is equivalent to (expand sub-templates to distinct):\n\n\u003c:FACTOR\u003e:=[\u003clhs\u003e[ \u003c?op\u003e \u003crhs|NULL\u003e]]\n\n\u003c:TERM\u003e:=[(\u003cfactor:FACTOR\u003e[ AND \u003c*factor:FACTOR\u003e])]\n\n\u003c:EXPR\u003e:=[\u003cterm:TERM\u003e[ OR \u003c*term:TERM\u003e]]\n\n\u003cexpression:EXPR\u003e\n\u003cexpression2:EXPR\u003e\n\n*/\n\nvar tpl = \"\u003c:EXPR\u003e:=[\u003cterm\u003e:=[(\u003cfactor\u003e:=[\u003clhs\u003e[ \u003c?op\u003e \u003crhs|NULL\u003e]][ AND \u003c*factor\u003e])][ OR \u003c*term\u003e]]\u003cexpression:EXPR\u003e\\n\u003cexpression2:EXPR\u003e\";\n\nvar expr = new GrammarTemplate( tpl );\n\necho(\"input template:\");\necho(tpl);\n\necho( );\n\necho(\"output:\");\necho(expr.render({\n    expression  : [\n        // term\n        [\n            // factor\n            {lhs: 1, op: '=', rhs: 1},\n            // factor\n            {lhs: 1, op: '=', rhs: 2},\n            // factor\n            {lhs: 1, op: '=', rhs: 3}\n        ],\n        // term\n        [\n            // factor\n            {lhs: 1, op: '\u003c', rhs: 1},\n            // factor\n            {lhs: 1, op: '\u003c', rhs: 2},\n            // factor\n            {lhs: 1, op: '\u003c', rhs: 3}\n        ],\n        // term\n        [\n            // factor\n            {lhs: 1, op: '\u003e', rhs: 1},\n            // factor\n            {lhs: 1, op: '\u003e', rhs: 2},\n            // factor\n            {lhs: 1, op: '\u003e', rhs: 3}\n        ]\n    ],\n    expression2  : [\n        // term\n        [\n            // factor\n            {lhs: 2, op: '=', rhs: 1},\n            // factor\n            {lhs: 2, op: '=', rhs: 2},\n            // factor\n            {lhs: 2, op: '=', rhs: 3}\n        ],\n        // term\n        [\n            // factor\n            {lhs: 2, op: '\u003c', rhs: 1},\n            // factor\n            {lhs: 2, op: '\u003c', rhs: 2},\n            // factor\n            {lhs: 2, op: '\u003c', rhs: 3}\n        ],\n        // term\n        [\n            // factor\n            {lhs: 2, op: '\u003e', rhs: 1},\n            // factor\n            {lhs: 2, op: '\u003e', rhs: 2},\n            // factor\n            {lhs: 2, op: '\u003e', rhs: 3}\n        ],\n        // term\n        [\n            // factor\n            {lhs: 3},\n            // factor\n            {lhs: 3, op: '!='}\n        ]\n    ]\n}));\n```\n**output**\n```text\nGrammarTemplate.VERSION = 3.0.0\n\ninput template:\n\u003c:EXPR\u003e:=[\u003cterm\u003e:=[(\u003cfactor\u003e:=[\u003cglobalNegation:NEG\u003e\u003clhs\u003e[ \u003c?op:OP\u003e \u003crhs|NULL\u003e]][ AND \u003c*factor\u003e])][ OR \u003c*term\u003e]]\u003cexpression:EXPR\u003e\n\u003cexpression2:EXPR\u003e\n\noutput:\n(NOT 1 = 1 AND NOT 1 = 2 AND NOT 1 = 3) OR (NOT 1 \u003c 1 AND NOT 1 \u003c 2 AND NOT 1 \u003c 3) OR (NOT 1 \u003e 1 AND NOT 1 \u003e 2 AND NOT 1 \u003e 3)\n(NOT 2 = 1 AND NOT 2 = 2 AND NOT 2 = 3) OR (NOT 2 \u003c 1 AND NOT 2 \u003c 2 AND NOT 2 \u003c 3) OR (NOT 2 \u003e 1 AND NOT 2 \u003e 2 AND NOT 2 \u003e 3) OR (NOT 3 AND NOT 3 \u003c\u003e NULL)\n```\n\n```javascript\nvar GrammarTemplate = require(\"../src/js/GrammarTemplate.js\"), echo = console.log;\n\necho('GrammarTemplate.VERSION = ' + GrammarTemplate.VERSION);\necho( );\n\nvar tpl = \"\u003c:BLOCK\u003e:=[BLOCK \u003c.name\u003e\\n{\\n[    \u003c@.blocks:BLOCKS\u003e?\\n]}]\u003c:BLOCKS\u003e:=[\u003c@block:BLOCK\u003e[\\n\u003c@block:BLOCK\u003e*]]\u003c@blocks:BLOCKS\u003e\";\n\nvar aligned = new GrammarTemplate( tpl, null, true );\n\necho(\"input template:\");\necho(tpl);\n\necho( );\n\necho(\"output:\");\necho(aligned.render({\n    blocks      : [\n    {\n        name        : \"block1\",\n        blocks      : null\n    },\n    {\n        name        : \"block2\",\n        blocks      : [\n            {\n                name   : \"block21\",\n                blocks : [\n                    {\n                        name   : \"block211\",\n                        blocks : [\n                            {\n                                name   : \"block2111\",\n                                blocks : null\n                            },\n                            {\n                                name   : \"block2112\"\n                            }\n                        ]\n                    },\n                    {\n                        name   : \"block212\"\n                    }\n                ]\n            },\n            {\n                name   : \"block22\",\n                blocks : [\n                    {\n                        name   : \"block221\"\n                    },\n                    {\n                        name   : \"block222\"\n                    }\n                ]\n            }\n        ]\n    },\n    {\n        name        : \"block3\"\n    }\n]\n}));\n```\n\n\n```text\nGrammarTemplate.VERSION = 3.0.0\n\ninput template:\n\u003c:BLOCK\u003e:=[BLOCK \u003c.name\u003e\n{\n[    \u003c@.blocks:BLOCKS\u003e?\n]}]\u003c:BLOCKS\u003e:=[\u003c@block:BLOCK\u003e[\n\u003c@block:BLOCK\u003e*]]\u003c@blocks:BLOCKS\u003e\n\noutput:\nBLOCK block1\n{\n}\nBLOCK block2\n{\n    BLOCK block21\n    {\n        BLOCK block211\n        {\n            BLOCK block2111\n            {\n            }\n            BLOCK block2112\n            {\n            }\n        }\n        BLOCK block212\n        {\n        }\n    }\n    BLOCK block22\n    {\n        BLOCK block221\n        {\n        }\n        BLOCK block222\n        {\n        }\n    }\n}\nBLOCK block3\n{\n}\n```\n\n### TODO\n\n* handle literal symbols (so for example grammar-specific delimiters can also be used literaly, right now delimiters can be adjusted as parameters) [DONE, through escaping]\n* handle nested/deep arguments [DONE, through nested object-dot notation]\n* handle recursion/loop deep structured arguments and sub-templates [DONE, through defining recursive sub-templates for rendering any deep argument]\n* handle boolean-like optional arguments [DONE, through setting (empty) default value for optional argumement, is handled as pure boolean on/off flag argument]\n* optimise parsing and rendering [DONE]\n* support some basic and/or user-defined functions [DONE, similar custom function definition as custom sub-template, calls function if custom function with same name has been defined]\n* support both `pre-` and `post-` (repeat) grammar operators, i.e both `\u003c?symbol\u003e`,`\u003c*symbol\u003e`,`\u003c{n,m}symbol\u003e` and `\u003csymbol\u003e?`,`\u003csymbol\u003e*`,`\u003csymbol\u003e{n,m}` for more familiar grammar syntax [DONE, via extra parameter in template instantiation]\n* support comments [DONE, through comment block notation, i.e `[# comment here #]`]\n* handle generic/dynamic unknown before-hand custom rendering methods [DONE, can attach to generic wildcard renderer `*` and handle/dispatch based on passed template name]\n* handle same name local and global arguments in (deep) recursive templates, avoiding possible global conflicts and infinite loops [DONE, through explicit local dot `.` argument notation]\n* handle explicit text/code alignment/indentation expansion in sequence [DONE, use aligned `@` argument notation]\n* handle custom delimiters with different lengths and possibly same prefixes [DONE, by dynamicaly arranging parsing by delimiter string length]\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoo123%2Fgrammartemplate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffoo123%2Fgrammartemplate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoo123%2Fgrammartemplate/lists"}