{"id":28512814,"url":"https://github.com/rustamli/candygen","last_synced_at":"2025-07-21T13:34:30.010Z","repository":{"id":57193601,"uuid":"65617957","full_name":"rustamli/candygen","owner":"rustamli","description":"Highly customizable multi-purpose rule based generator","archived":false,"fork":false,"pushed_at":"2021-01-03T20:53:26.000Z","size":277,"stargazers_count":6,"open_issues_count":2,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-28T20:07:57.500Z","etag":null,"topics":["code-generation","javascript","static-gen","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rustamli.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-08-13T13:14:41.000Z","updated_at":"2025-02-05T23:57:29.000Z","dependencies_parsed_at":"2022-09-15T22:20:14.174Z","dependency_job_id":null,"html_url":"https://github.com/rustamli/candygen","commit_stats":null,"previous_names":["candyland-js/candygen"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rustamli/candygen","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustamli%2Fcandygen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustamli%2Fcandygen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustamli%2Fcandygen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustamli%2Fcandygen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rustamli","download_url":"https://codeload.github.com/rustamli/candygen/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustamli%2Fcandygen/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266312157,"owners_count":23909744,"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","status":"online","status_checked_at":"2025-07-21T11:47:31.412Z","response_time":64,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"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":["code-generation","javascript","static-gen","typescript"],"created_at":"2025-06-09T01:05:00.126Z","updated_at":"2025-07-21T13:34:29.991Z","avatar_url":"https://github.com/rustamli.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# candygen :candy:\n\nHighly customizable multi-purpose rule based generator that can be used in a wide variety of use-cases. Candygen has been previously used for building static websites with arbitrary structure, email templating and even code generation (see [Examples](#examples) section for more details).\n\n---\n\n:warning: Currently working on a [Snowpack](https://www.snowpack.dev/) based upgraded version of candygen with Hot module reload, Built-in helpers, Smart defaults, Native CSV/JSON support and Server-Sider Rendering. Please check this repository for more details: https://github.com/rustamli/snowpack-handlebars-starter\n\n_Also feel free to reach out [on twitter](https://twitter.com/nehfy) if you have questions or feedback_\n\n---\n\n## Getting Started\n\nThese section will guide you through installation and basic setup for your first candygen project.\n\n## Live Demo\n\n[![Edit candygen-test](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/2ojvol3yyp)\n\n### Prerequisites\n\nIn order to use candygen you will need to have [Node.js](https://nodejs.org/en/) installed on your system. \n\nExamples below use [yarn](https://yarnpkg.com/en/) for package management. However, same results could be achieved by using corresponding `npm` commands.\n\n### Installation\n\nCreate an empty folder for your project:\n\n```\nmkdir myproject\ncd myproject\n```\n\nOptionally, run `npm init` or `yarn init` to create a `package.json`:\n\n```\nyarn init\n```\n\nAdd candygen generator as a dependency to your project:\n\n```\nyarn add @candygen/generator\n```\n\nCreate initial candygen configuration file, by running:\n\n```\nyarn cg init\n```\n\nThis will create a file named `candygen.config.js`, with following content:\n\n```javascript\nmodule.exports = {  \n  init: function () {\n    return {\n      schemaVersion: '1.0',\n      rules: [\n        // {\n        //   template: '',\n        //   script: '',\n        //   data: '',\n        //   output: ''\n        // }\n      ]\n    }\n  }\n};\n```\n\n### Usage example\n\nCandygen [configuration](#configuration-file) file should always contain a method called `init()` that returns JavaScript object with the final rule set, partials and helpers definition\n\nModify `candygen.config.js` to look like:\n\n```javascript\nmodule.exports = {  \n  init: function () {\n    return {\n      schemaVersion: '1.0',\n      rules: [\n        {\n          template: 'index.html.hbs',\n          data: 'data.json',\n          output: 'index.html'\n        }\n      ],\n      partials: []\n    }\n  }\n};\n```\n\nCreate a new file `data.json` with the following content:\n\n```json\n{\"message\":\"Hello, World!\"}\n```\n\nAnd another file named `index.html.hbs` containing: \n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n    \u003ctitle\u003eWelcome!\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n  \u003ch1\u003e{{message}}\u003c/h1\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nRun the following command to generate output:\n\n```\nyarn cg\n```\n\nCheck the newly created `output` folder that should contain `index.html` with the following contents: \n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n    \u003ctitle\u003eWelcome!\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n  \u003ch1\u003eHello, World!\u003c/h1\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n \n### Generator commands\n\nThere are several commands that could be used once `@candygen/generator` is added as a dependency in your project folder:\n\n- `yarn cg` - runs generator once\n- `yarn cg init` - created `candygen.config.js` with empty default configurations\n- `yarn cg version` - outputs the current version of the candygen generator\n\n### Static files folder\n\nIf you need to copy a number of files as they are from your project folder into your output folder you should place them in a folder named `static`.\nThis is particularly useful for asset files in case of static website generation, such as CSS stylesheets, JavaScript files, images etc. \n\nBelow is a small illustration of how this works: \n\n```\n/sample\n  candygen.config.js\n  /static\n    style.css\n    /images\n      1.png\n      2.png\n```\n\nIf you run:\n\n```\nyarn cg\n```\n\nYou will get:\n\n```\n/sample\n  candygen.config.js\n  /static\n    style.css\n    /images\n      1.png\n      2.png\n  /output\n    style.css\n    /images\n      1.png\n      2.png\n```\n\n### Configuration file\n\nConfiguration file must always be named `candygen.config.js` and it must always be on the root level of the project folder\n\nThis file must contain a method named `init()`:\n\n```javascript\nmodule.exports = {  \n  init: function () {\n    return [CONFIGURATION];\n  }\n};\n```\n\n`[CONFIGURATION]` must always be an object with the following properties: \n\n-  `inputPath: string;` [Optional] Change the folder that should be treated as the root input folder by the generator\n-  `outputPath: string;` [Optional] Alternative output path for the results of the generation\n-  `rules: Rule[];` Set of rules describing the generation process. See **Rule** section below for more details\n-  `partials: Partial[];` Set of reusable partial templates that could be used for injecting repeated sections as well as for layouting (For example, for header, footers). See **Partials** section below for more details\n-  `helpers?: Helper[];` [Optional] Set of templating helpers implemented in JavaScript. See **Partials** section below for more details\n\n\n\n**Rule**\n\nRule defines an atomic action perfomed by the generator during the output generation process. There several properties for each rule:\n\n![Candygen explained](media/cg1.png)\n\n\n*data* (optional)\n\nData contains data in the JSON format that either will be directly passed to the handlebars template defined under `template` property, or will first be transformed by a script defined in a `script` property. \n\nIn case if data is directly passed to the template it should be in the following format:\n\n```javascript\n{\n  \"pages\": [\n    {...}\n  ]\n}\n```\n\n*script* (optional)\n\nPath to a JavaScript file containing a function called `run()` that will be executed to prepare the templating data.\n\nIn case if `data` property is defined for the rule. The parsed JSON value of the file specified in the `data` property is passed to the `run()` method.\n\nScripts could be very useful for various transformations on the initial data. An example below illustrates a usage of a script in order to change post titles in the example above to be in the upper case:\n\n```javascript\nmodule.exports = {\n  run (data) {\n    data.pages.forEach(page =\u003e {\n      page.posts.forEach(post =\u003e {\n        post.title = post.title.toUpperCase();\n      });\n    })\n    return data;\n  }\n}\n```\n\nA script must always return output in the following format:\n\n\n```javascript\n{\n  \"pages\": [\n    {...}\n  ]\n}\n```\n\n*template*\n\nA relative (to the input folder) path to a [handlebars](http://handlebarsjs.com) template file\n\n*output*\n\nA file name or a file name pattern for the resulting output. Two special tokens are replaced in the output value depending on the resulting page that is being processed. This way *one rule can produce multiple output files*: \n\n- `@ID@` - `pageId` value of the page will be injected instead of this token\n- `@PAGENUM@` - number of the page in the pages array will be injected instead of this token\n\n\n**Partial**\n\nPartials are defining handlebars partials that can contain repeated sections (such as header, footer, copyrights) or alternative be used as layouts (see [handlebars partials](http://handlebarsjs.com/partials.html) documentation for more details)\n\nTwo properties are needed to define a partial:\n\n- `name` - partial's name, will be used in other templates or partials to refer to this partial\n- `template` - path to a file containing handlebars template for this partial\n\nHere's an example definition for two partials header and footer:\n\n```javascript\n...\nschemaVersion: '1.0',\nrules: [\n  ...\n],\npartials: [\n  {\n    name: 'header',\n    template: 'templates/partials/header.hbs'\n  },\n  {\n    name: 'footer',\n    template: 'templates/partials/footer.hbs'\n  }\n]\n...\n```\n\nAfter being defined these partials can be used in other templates and other partials in the following way:\n\n```html\n{{\u003e header}}\n\u003cdiv class=\"content\"\u003e\n...\n\u003c/div\u003e\n{{\u003e footer}}\n```\n\n**Helpers**\n\nSimilarly to partials, helpers section can be used to define custom handlebars helpers ([inline](https://handlebarsjs.com/expressions.html) and [block helpers](https://handlebarsjs.com/block_helpers.html) are supported). \n\nTwo properties are needed to define a helper:\n\n- `name` - helper's name, will be used in other templates or partials to refer to this helper\n- `fn` - JavaScript function - implementation of this helper\n\nBelow is an example helper definition:\n\n```javascript\n...\nschemaVersion: '1.0',\nrules: [\n  ...\n],\npartials: [\n  ...\n],\nhelpers: [\n  {\n    name: 'upperCaseOrMissing',\n    fn: (value) =\u003e {\n      return value ? value.toUpperCase() : 'MISSING';\n    }\n  }\n]\n...\n```\n\n## Dev Server\n\nCandygen Dev Server runs in background and serves the latest result of the generation. When any input file changes, Dev Server updates the output correspondingly. It is installable as a separate package:\n\n```\nyarn add @candygen/dev-server\n```\n\nIn order to run it, run the following command in the folder contaning `candygen.config.js`:\n\n```\nyarn cg-dev\n```\n\nOptionally you can specify a port on which dev server will run:\n\n```\nyarn cg-dev port=3333\n```\n\n## Developing candygen\n\nThis repo contains all packages related to candygen and represents a monorepo. It is using (lerna)[https://lernajs.io/] to manage multiple packages.\nIt is recommended to use [yarn](https://yarnpkg.com/en/) for package management as this project relies on yarn workspaces. This repo includes a basic [VSCode](https://code.visualstudio.com/) configuration for debugging generator and dev-server packages. In order to start developing locally, checkout this repository and run:\n\n```\nyarn build\n```\n\nTo run TypeScript compiler in watch mode for all sub-packages use the following command:\n\n```\nyarn tsc-all--watch\n```\n\n## Examples\n\nHere's a list of websites using candygen:\n\n- [landmax.pro](https://www.landmax.pro)\n- [getguided.net](https://getguided.net)\n\nAnother example could be found under `packages/candygen-example`\nThis example package is also installable running `yarn add @candygen/example`\n\n## Versioning\n\nWe use [SemVer](http://semver.org/) for versioning\n\n## Authors\n\n* **Turan Rustamli** ([rustamli](https://github.com/rustamli))\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frustamli%2Fcandygen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frustamli%2Fcandygen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frustamli%2Fcandygen/lists"}