{"id":30779792,"url":"https://github.com/angrycoding/histone","last_synced_at":"2026-01-20T17:28:04.135Z","repository":{"id":57286710,"uuid":"102780095","full_name":"angrycoding/histone","owner":"angrycoding","description":null,"archived":false,"fork":false,"pushed_at":"2025-09-04T16:35:34.000Z","size":254,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-04T18:31:10.116Z","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":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/angrycoding.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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2017-09-07T19:58:52.000Z","updated_at":"2025-09-04T16:35:37.000Z","dependencies_parsed_at":"2025-09-04T18:41:19.029Z","dependency_job_id":null,"html_url":"https://github.com/angrycoding/histone","commit_stats":null,"previous_names":["angrycoding/histone"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/angrycoding/histone","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angrycoding%2Fhistone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angrycoding%2Fhistone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angrycoding%2Fhistone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angrycoding%2Fhistone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/angrycoding","download_url":"https://codeload.github.com/angrycoding/histone/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angrycoding%2Fhistone/sbom","scorecard":{"id":196093,"data":{"date":"2025-08-11","repo":{"name":"github.com/angrycoding/jte","commit":"8d8a0b613ed34a50d8d183809d8f1a9495cd1625"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"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":"Code-Review","score":0,"reason":"Found 0/19 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":"Maintained","score":0,"reason":"0 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":"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":"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":"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":"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":"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":"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":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"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":"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":"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":"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-16T21:52:03.990Z","repository_id":57286710,"created_at":"2025-08-16T21:52:03.991Z","updated_at":"2025-08-16T21:52:03.991Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273685878,"owners_count":25149778,"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-09-04T02:00:08.968Z","response_time":61,"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":[],"created_at":"2025-09-05T06:45:47.162Z","updated_at":"2025-10-25T12:36:56.405Z","avatar_url":"https://github.com/angrycoding.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Histone - cross-platform template engine\u0026nbsp;\u0026nbsp;[![npm version](https://badge.fury.io/js/histone.svg)](https://npmjs.org/package/histone)\n\n[![NPM](https://nodei.co/npm/histone.png?downloads=true\u0026stars=true\u0026downloadRank=true)](https://nodei.co/npm/histone/)\n\n- [Histone documentation home](https://github.com/MegafonWebLab/histone-documentation)\n- [Histone reference](https://github.com/MegafonWebLab/histone-documentation/wiki)\n- [JavaScript reference](../../wiki)\n\n### Node.js® installation\n\n```bash\nnpm install histone\n```\n\nIn case if you do it for production, don't forget to tune it (see description below):\n\n```bash\nnpm install histone\ncd node_modules/histone/build\nnpm install\nnode build.js --format=commonjs --exclude-parser\n```\n\nIt works absolutely the same way even if you specify Histone as a project dependency in your package.json file:\n\n```json\n{\n    \"dependencies\": {\n        \"histone\": \"latest\"\n    }\n}\n```\n\nAnd then the production build would look like:\n\n```bash\nnpm install\ncd node_modules/histone/build\nnpm install\nnode build.js --format=commonjs --exclude-parser\n```\n\n### Running tests\n\nIn case if you wish to build some feature or just play around with it, you can run tests in order to see if your changes breaks something important:\n\n```bash\ncd node_modules/histone/test\nnpm install\nnode test.js\n```\n\nBy default tests are executed against source code (node_modules/histone/src/Histone.js) , to change that (testing custom build), pass --histone flag:\n\n```bash\ncd node_modules/histone/test\nnpm install\nnode test.js --histone=../Histone.js\n```\n\nIf you want to run specific test, pass --suite flag:\n\n```bash\ncd node_modules/histone/test\nnode test.js --suite=MyTestSuite.js\n```\n\n### Building production package from source code\n\nWhen you need to use Histone in the web - browser, you can prepare special package in required format, first of all you'll need to install Node.js® version of Histone as it's described above, then do the following:\n\n```bash\ncd node_modules/histone/build/\nnpm install\nnode build.js [options]\n```\n\nWhere options are:\n\n* **--verbose** - display messages during the build\n* **--exclude-parser** - don't include Parser into production package\n* **--format=_FORMAT_** - where **_FORMAT_** is one of the following:\n  * **_global_** - makes package where Histone is exported into the global variable\n  * **_amd_** - makes AMD - compatible package\n  * **_commonjs_** - just merges all original source files into one huge CommonJS module (**default**)\n* **--lang=_LANGUAGE_** - where **_LANGUAGE_** is the path to the language file (see i18n folder for example)\n* **--defaultLang=_LANGUAGE_** - specify language that will be used by default\n* **--target=PATH** - path to target file (default will be node_modules/histone/Histone.js)\n\nFor example if you need Histone as AMD module with Russian and English languages you'll do the following:\n\n```bash\nnpm install histone\ncd node_modules/histone/build/\nnpm install\nnode build.js --format=amd --lang=../i18n/ru.js --lang=../i18n/en.js --defaultLang=ru\n```\n\nProduction package build for the web - browser might look somewhat like this:\n\n```bash\nnpm install histone\ncd node_modules/histone/build/\nnpm install\nnode build.js --format=amd --lang=../i18n/ru.js --exclude-parser\n```\n\n### Using template engine\n\nWhen you connect Histone to your project (no matter if it's Node.js® or browser), you'll use it something like this:\n\n```javascript\nvar Histone = require('histone');\nHistone('2 x 2 = {{2 * 2}}').render(function(result) {\n    console.info(result);\n});\n```\n\nof course soon or late you'll want to load template from the file, in this case you'll have to set up resource loader which will be responsible for loading templates:\n\n```javascript\nvar FS = require('fs'),\n    Histone = require('histone');\n\nHistone.setResourceLoader(function(uri, ret) {\n    console.info('[ LOADING ]', uri);\n    FS.readFile(uri, 'UTF-8', function(error, result) {\n        ret(result);\n    });\n});\n\nHistone('{{loadText(\"test.txt\")}}').render(function(result) {\n    console.info(result);\n});\n```\n\n### Returning and passing raw JavaScript values from and to the template\n\nMost of the time you'll use Histone for text generation, but sometimes it's necessary for the template to return some raw JavaScript value, Histone will do the conversion between internal data types and JavaScript data types for you:\n\n```javascript\nrequire('histone')('{{return /regexp/ig}}').render(function(result) {\n    // Histone RegExp automatically converted into JavaScript RegExp\n    console.info(result instanceof RegExp);\n});\n```\n\nSame way you can pass any previously registered JavaScript object to the template's context:\n\n```javascript\nrequire('histone')('{{return this-\u003eisRegExp}}').render(function(result) {\n    // JavaScript RegExp automatically converted into Histone RegExp\n    // then Histone Boolean automatically converted into JavaScript Boolean\n    console.info(result, typeof result === 'boolean');\n}, /regexp/ig);\n```\n\nThis trick works with any data type recognized by Histone, i. e. [Histone.Undefined](../../wiki/Histone.Undefined) \u003c-\u003e JavaScript undefined, [Histone.Null](../../wiki/Histone.Null) \u003c-\u003e JavaScript null and so on. [Histone.Array](../../wiki/Histone.Array) will be automatically converted into JavaScript Array or JavaScript Object, depends on the array contents:\n\n```javascript\n// return Array\nrequire('histone')('{{return [1, 2]}}').render(function(result) {\n    // JavaScript Array\n    console.info(result instanceof Array);\n});\n\n// return Object\nrequire('histone')('{{return [foo: 1, bar: 2]}}').render(function(result) {\n    // JavaScript Object\n    console.info(result instanceof Object);\n});\n```\n\n[Histone.Date](../../wiki/Histone.Date) will be automatically converted into JavaScript date, and vice versa:\n\n```javascript\n// return JavaScript Date\nrequire('histone')('{{return getDate}}').render(function(result) {\n    // JavaScript Date\n    console.info(result instanceof Date);\n});\n\n// JavaScript Date will be automatically converted into HistoneDate\nrequire('histone')('{{this-\u003eisDate}}').render(function(result) {\n    // true\n    console.info(result);\n}, new Date);\n```\n\n[Histone.Macro](../../wiki/Histone.Macro) will be automatically converted into JavaScript function, but JavaScript function will never be converted into [Histone.Macro](../../wiki/Histone.Macro) when passed as template's context:\n\n```javascript\n// return Function\nrequire('histone')('{{return =\u003e 2 * 2}}').render(function(result) {\n    // JavaScript Function\n    console.info(result instanceof Function, result());\n});\n\n// JavaScript function will never be converted into HistoneMacro\nrequire('histone')('{{return this-\u003eisMacro}}').render(function(result) {\n    // false\n    console.info(result);\n}, function(){});\n```\n\n#### Managing return type produced by render\n\nIf you need Histone data type instead of it's JavaScript equivalent as a result of template rendering, you can convert it using [Histone.toHistone](../../wiki/Histone.toHistone):\n\n```javascript\nrequire('histone')('{{return [1, 2, 3]}}').render(function(result) {\n    // true\n    console.info(result instanceof Array);\n    // convert JavaScript Array into Histone.Array\n    result = Histone.toHistone(result);\n    // true\n    console.info(result instanceof Histone.Array);\n});\n```\n\nor you can specify return type explicitly:\n\n```javascript\nrequire('histone')('{{return [1, 2, 3]}}').render(function(result) {\n    // true\n    console.info(result instanceof Histone.Array);\n}, Histone.R_HISTONE);\n```\n\nSometimes it's required to have string as a result of template rendering (for example you use rendering result as a server response in the web - application), obviously you can check and convert result yourself:\n\n```javascript\nrequire('histone')('{{return [1, 2, 3]}}').render(function(result) {\n    // check and convert result if it's not a string\n    if (typeof result !== 'string') result = Histone.toString(result);\n    // ...\n});\n```\n\nor you can specify explicit stringification:\n\n```javascript\nrequire('histone')('{{return [1, 2, 3]}}').render(function(result) {\n    // string\n    console.info(typeof result);\n}, Histone.R_STRING);\n```\n\n### Extending template runtime\n\nYou can assign new methods (or overwrite existing ones) to any of the Histone built - in data types, using [Histone.register](../../wiki/Histone.register) method:\n\n```javascript\nHistone.register(PROTOTYPE, MEMBER_NAME, MEMBER_VALUE);\n```\n\nWhere PROTOTYPE is one of the following:\n\n* [Histone.Base.prototype](../../wiki/Histone.Base) - base data type for any Histone value\n* [Histone.Undefined.prototype](../../wiki/Histone.Undefined) - Undefined data type\n* [Histone.Null.prototype](../../wiki/Histone.Null) - Null data type\n* [Histone.Boolean.prototype](../../wiki/Histone.Boolean) - Boolean data type (in fact JavaScript Boolean)\n* [Histone.Number.prototype](../../wiki/Histone.Number) - Number data type (in fact JavaScript Number)\n* [Histone.String.prototype](../../wiki/Histone.String) - String data type (in fact JavaScript String)\n* [Histone.RegExp.prototype](../../wiki/Histone.RegExp) - RegExp data type (in fact JavaScript RegExp)\n* [Histone.Array.prototype](../../wiki/Histone.Array) - Array data type\n* [Histone.Date.prototype](../../wiki/Histone.Date) - Date data type\n* [Histone.Macro.prototype](../../wiki/Histone.Macro) - Macro data type\n* [Histone.Global.prototype](../../wiki/Histone.Global) - Global object\n\nHere are couple of simple examples that will give you some understading:\n\n```javascript\nvar Histone = require('histone');\n\n// create global method\nHistone.register(Histone.Global.prototype, 'hello', function(self, args) {\n    return 'Hello ' + args[0] + '!';\n});\n\n// test our brand new method\nHistone('{{hello(\"world\")}}').render(function(result) {\n    console.info(result);\n});\n```\n\nSame thing goes for any other valid Histone data type, i. e. you can introduce new methods for Strings, Numbers, Arrays and so on, the idea is that if you miss something you just add it yourself:\n\n```javascript\nvar Histone = require('histone');\n\n// create global method\nHistone.register(Histone.String.prototype, 'doSomethingWeird', function(self) {\n    return self.split('').sort().join('');\n});\n\n// test our brand new method\nHistone('{{\"bla-bla\"-\u003edoSomethingWeird}}').render(function(result) {\n    console.info(result);\n});\n```\n\nThird argument to [Histone.register](../../wiki/Histone.register) not necessary should be a function, it can be anything recognized by Histone, automatic conversion will be applied if needed:\n\n```javascript\nvar Histone = require('histone');\n\n// method that returns string\nHistone.register(Histone.Global.prototype, 'myStringMethod', 'myStringValue');\n\n// method that returns array, JavaScript array will be automatically converted into HistoneArray\nHistone.register(Histone.Global.prototype, 'myArrayMethod', [1, 2, 3]);\n\n// test it\nHistone('{{myStringMethod}}').render(function(result) {\n    // myStringValue\n    console.info(result);\n});\n\n// test it\nHistone('{{myArrayMethod-\u003etoJSON}}').render(function(result) {\n    // [1,2,3]\n    console.info(result);\n});\n```\n\n#### Returning self value\n\nIn some situations it's required for the method to return the value itself, usually you would solve it somewhat like this:\n\n```javascript\nvar Histone = require('histone');\n// register String method which returns string itself\nHistone.register(Histone.String.prototype, 'getSelf', function(self) {\n    return self;\n});\n// myString\nconsole.info(Histone.invoke('myString', 'getSelf'));\n```\n\nThis looks a bit stupid to create a whole function which does nothing but returning it's first argument. If you care about such things, use [Histone.R_SELF](../../wiki/Histone.register#using-histoner_self-to-specify-that-method-returns-the-value-itself) instead of function in such situations:\n\n```javascript\nvar Histone = require('histone');\n// register String method which returns string itself\nHistone.register(Histone.String.prototype, 'getSelf', Histone.R_SELF);\n// myString\nconsole.info(Histone.invoke('myString', 'getSelf'));\n```\n\n#### Handling arguments\n\nArguments to the called method are passed as an array in the second argument:\n\n```javascript\nvar Histone = require('histone');\n\n// create global method\nHistone.register(Histone.Global.prototype, 'getArgsCount', function(self, args) {\n    return args.length;\n});\n\n// test it\nHistone('{{getArgsCount(1, 2, 3)}}').render(function(result) {\n    // 3\n    console.info(result);\n});\n```\n\n#### Asynchronous methods\n\nIn order to support asynchronous processing, just define method handler as a function with at least 4 arguments:\n\n```javascript\nvar Histone = require('histone');\n\n// method that waits 1 second and returns string\nHistone.register(Histone.Global.prototype, 'myDelay', function(self, args, scope, ret) {\n    setTimeout(function() {\n       ret('WAITED 1000ms');\n    }, 1000);\n});\n\nHistone('{{myDelay}}').render(function(result) {\n    // WAITED 1000ms\n    console.info(result);\n});\n```\n\n#### Introducing new data types\n\nNative JavaScript classes can also be easily introduced to Histone, let's create a wrapper for JavaScript Date object:\n\n```javascript\nvar Histone = require('histone');\n\n// create global method which returns Date instance\nHistone.register(Histone.Global.prototype, 'getMyDate', function() {\n    return new Date;\n});\n\n// we have to register at least one method for the Date.prototype, so Histone can recognize it\nHistone.register(Date.prototype, 'toString', function(self) {\n    // self refers to the Date instance here\n    return self.toString();\n});\n\n// test our Date wrapper\nHistone('now is {{getMyDate}}').render(function(result) {\n    console.info(result);\n});\n```\n\n#### Returning values from the templates\n\nOnce we've registered the type, we can return it from the template:\n\n```javascript\nvar Histone = require('histone');\n\n// create global method which returns Date instance\nHistone.register(Histone.Global.prototype, 'getMyDate', function() {\n    return new Date;\n});\n\n// we have to register at least one method for the Date.prototype, so Histone can recognize it\nHistone.register(Date.prototype, 'toString', function(self) {\n    // self refers to the Date instance here\n    return self.toString();\n});\n\n// test our Date wrapper\nHistone('{{return getMyDate}}').render(function(result) {\n    console.info(result instanceof Date);\n});\n```\n\n#### Handling internal Histone data types\n\nNote that when you extending Histone, your method handlers will have to deal with internal Histone data types, not their JavaScript equivalents:\n\n```javascript\nvar Histone = require('histone');\n\n// create global method which returns true if it's argument is an array\nHistone.register(Histone.Global.prototype, 'myIsArray', function(self, args) {\n    // note that first argument here is not JavaScript Array\n    return (args[0] instanceof Histone.Array);\n});\n\nHistone('{{myIsArray([1, 2, 3])}}').render(function(result) {\n    // true\n    console.info(result);\n});\n```\n\nIf you don't care about internal Histone type, you can easily convert the value you receive in your method handler into native JavaScript value:\n\n```javascript\nvar Histone = require('histone');\n\n// create global method which returns true if it's argument is an array\nHistone.register(Histone.Global.prototype, 'myIsArray', function(self, args) {\n    var arg = Histone.toJavaScript(args[0]);\n    // note that first argument here is not JavaScript Array\n    return (arg instanceof Array);\n});\n\nHistone('{{myIsArray([1, 2, 3])}}').render(function(result) {\n    // true\n    console.info(result);\n});\n```\n\nSecond possibility is to explicitly specify desired argument type when registering method:\n\n```javascript\nvar Histone = require('histone');\n\n// create global method which returns true if it's argument is a JavaScript Date\nHistone.register(Histone.Global.prototype, 'myIsDate', function(self, args) {\n    return (args[0] instanceof Date);\n}, Histone.R_JS);\n\n// passing JavaScript Date, result = true\nconsole.info(Histone.invoke(Histone.global, 'myIsDate', new Date));\n// passing Histone Date, result = true\nconsole.info(Histone.invoke(Histone.global, 'myIsDate', new Histone.Date));\n```\n\nMost of Histone data types are simple references to the JavaScript data types, however it's recommended to use Histone.Type instead of it's JavaScript equivalent in order to be compatible with the future releases:\n\n```javascript\nvar Histone = require('histone');\n\n// create global method which returns true if it's argument is a RegExp\nHistone.register(Histone.Global.prototype, 'myIsRegExp', function(self, args) {\n    // this will be true, however it's recommended to use Histone.RegExp instead\n    return (args[0] instanceof RegExp);\n});\n\nHistone('{{myIsRegExp(/regexp/)}}').render(function(result) {\n    // true\n    console.info(result);\n});\n```\n\n#### Using Histone macros as callback functions\n\nSometimes you need to pass Histone macro as a callback in your custom method, then call it based on some condition:\n\n```javascript\nvar Histone = require('histone');\n\nHistone.register(Histone.Global.prototype, 'myMethod', function(self, args, scope, ret) {\n    var arg = args[0];\n    if (arg instanceof Histone.Macro)\n        arg.call([1, 2, 3], scope, ret);\n    else ret();\n});\n\nHistone('{{myMethod(=\u003e self.arguments-\u003etoJSON)}}').render(function(result) {\n    // [1,2,3]\n    console.info(result)\n});\n```\n\n#### Extending Histone data types\n\nYou can extend Histone data types and provide your own version of Array, Macro and so on, note that this won't work for the things like String, Number, RegExp and so on, because most of the current JavaScript engines won't allow you to extend native JavaScript objects, but this might change in the future, so for now it will really work only for Arrays and Macros:\n\n```javascript\nvar Histone = require('histone');\n\n// create our version of Array\nvar MyArray = function() { Histone.Array.apply(this, arguments); };\nMyArray.prototype = Object.create(Histone.Array.prototype);\nMyArray.prototype.constructor = MyArray;\nMyArray.prototype.test = function() { return 'MyArray.prototype.test'; };\n\n// define some method for our version of Array, otherwise Histone won't recognize it\nHistone.register(MyArray.prototype, 'test', function(self) {\n    // call method test on MyArray instance\n    return self.test();\n});\n\n// register global method wich will return MyArray instance\nHistone.register(Histone.Global.prototype, 'getMyArray', function(self) {\n    return new MyArray;\n});\n\n// test it\nHistone('{{getMyArray-\u003etest}}').render(function(result) {\n    // MyArray.prototype.test\n    console.info(result);\n});\n```\n\n### Converting internal Histone data types into native JavaScript data types\n\nWhen you're extending Histone and writing custom method handlers, you have to deal with internal Histone data types, however sometimes you don't need it and instead of working with internals, you prefer to convert them into JavaScript values, in this case there are couple of methods that you might find useful:\n\n* [Histone.toJavaScript](../../wiki/Histone.toJavaScript) - converts Histone value into a JavaScript value if converter is registered (see [Histone.M_TOJS](../../wiki/Histone.toJavaScript#register-custom-histonem_tojs-virtual-method))\n* [Histone.toBoolean](../../wiki/Histone.toBoolean) - converts Histone value into a JavaScript Boolean\n* [Histone.toString](../../wiki/Histone.toString) - converts Histone value into a JavaScript String\n* [Histone.toNumber](../../wiki/Histone.toNumber) - converts Histone value into a JavaScript Number\n* [Histone.toJSON](../../wiki/Histone.toJSON) - converts Histone value into a JSON String\n\n```javascript\nvar Histone = require('histone');\n\n// register global method to test conversion utils\nHistone.register(Histone.Global.prototype, 'myIsArray', function(self, args) {\n    // JavaScript Array\n    console.info('toJavaScript', Histone.toJavaScript(args[0]));\n    // true\n    console.info('toBoolean', Histone.toBoolean(args[0]));\n    // 1 2 3\n    console.info('toString', Histone.toString(args[0]));\n    // [1,2,3]\n    console.info('toJSON', Histone.toJSON(args[0]));\n    // 1\n    console.info('toNumber', Histone.toNumber(true));\n});\n\nHistone('{{myIsArray([1, 2, 3])}}').render(function(result) {\n    // ...\n});\n```\n\n### Calling Histone methods internally\n\nSometimes it's necessary to perform method call internally (for example in the method handler when extending the engine), in this case you can use [Histone.invoke](../../wiki/Histone.invoke) method:\n\n```javascript\nvar Histone = require('histone');\n\nHistone.register(Histone.Global.prototype, 'myMethod', function(self, args, scope) {\n    // value, member, arguments array, scope, callback function\n    Histone.invoke('string', 'split', function(result) {\n        console.info(result instanceof Histone.Array)\n    });\n});\n\nHistone('{{myMethod}}').render(function(result) {\n    // ...\n});\n```\n\nBtw this can be done even without templates, rendering and so on, check it out:\n\n```javascript\nvar Histone = require('histone');\n// same as {{\"string\"-\u003esplit}} in Histone template\nconsole.info(Histone.invoke('string', 'split'));\n```\n\nArguments will be converted into Histone data types automatically:\n\n```javascript\nvar Histone = require('histone');\n// JavaScript Array will be converted into HistoneArray automatically\n// result will be \"1.2.3.4\"\nconsole.info(Histone.invoke([1, 2, 3, 4], 'join', '.'));\n```\n\nCalling methods of the Histone's Global object is also as simple as this:\n\n```javascript\nvar Histone = require('histone');\n// Histone.global holds instance of Histone.Global.prototype\n// 1\nconsole.info(Histone.invoke(Histone.global, 'getMin', [1, 2, 3, 4]));\n// 4\nconsole.info(Histone.invoke(Histone.global, 'getMax', [1, 2, 3, 4]));\n```\n\nYou might notice already that in some situations there is a callback function which receives the result of the method call, but sometimes [Histone.invoke](../../wiki/Histone.invoke) returns the result directly without callback, what's the difference? Basically the idea is following, if you know what you calling, and you sure that the method you call is synchronous, then use [Histone.invoke](../../wiki/Histone.invoke) without callback, otherwise always use [Histone.invoke](../../wiki/Histone.invoke) in it's asynchronous form. For example, it's known that Array-\u003ejoin is synchronous, so you can safely call it synchronously, but if that wouldn't be truth (or you don't know it) then call it asynchronously, that won't fail in any case:\n\n```javascript\nvar Histone = require('histone');\n// call Array-\u003ejoin synchronously\nconsole.info(Histone.invoke([1, 2, 3, 4], 'join', '.'));\n// call Array-\u003ejoin asynchronously\nHistone.invoke([1, 2, 3, 4], 'join', '.', null, function() {\n    console.info(result);\n});\n```\n\nSo for the information about built-in methods and preferred way to call them, refer to [API](https://github.com/MegafonWebLab/histone-javascript/wiki) documentation, 3rd - party documentation or just call them asynchronously if you've got no idea about them.\n\n#### Handling return data types\n\nBy default, [Histone.invoke](../../Histone.invoke) (no matter whenever you call it synchronously or not) will return value represented as Histone data type, in most situations it's ok, but sometimes it's better to work with JavaScript data types, if that so, you have two possible solutions. First one is to convert the value returned by [Histone.invoke](../../wiki/Histone.invoke) using [Histone.toJavaScript](../../wiki/Histone.toJavaScript):\n\n```javascript\nvar result, Histone = require('histone');\n// Histone data type\nconsole.info(result = Histone.invoke('string', 'split'));\n// JavaScript data type\nconsole.info(result = Histone.toJavaScript(result));\n```\n\nTo make it even shorter, here comes the second variant, specify return type explicitly:\n\n```javascript\nvar Histone = require('histone');\n// JavaScript data type\nconsole.info(Histone.invoke('string', 'split', Histone.R_JS));\n```\n\n#### Calling method on prototypes\n\nIn some situations, when you're using native JavaScript prototype inheritance, you might need to be able to call method on the parent class / prototype (call super). For example, you've extended [Histone.Array](../../wiki/Histone.Array) in order to make your own Array with blackjack and hookers:\n\n```javascript\nvar Histone = require('histone');\n\n// create our version of Array\nvar MyArray = function() { Histone.Array.apply(this, arguments); };\nMyArray.prototype = Object.create(Histone.Array.prototype);\nMyArray.prototype.constructor = MyArray;\n\n// \"override\" Histone.Array-\u003etoString method with own implementation\nHistone.register(MyArray.prototype, 'toString', function(self) {\n    // hide the secret\n    return '(SECRET_CONTENT)';\n});\n```\n\nNow you want to call [Histone.Array](../../wiki/Histone.Array)-\u003etoString, in order to do that simply pass JavaScript - array, that consists of prototype and method name into [Histone.invoke](../../wiki/Histone.invoke):\n\n```javascript\n// \"override\" Histone.Array-\u003etoString method with own implementation\nHistone.register(MyArray.prototype, 'toString', function(self, args) {\n    // check if password valid\n    if (args[0] === 'password') {\n       // call original method\n       return Histone.invoke(self, [Histone.Array.prototype, 'toString']);\n    }\n    // go away\n    return '(SECRET_CONTENT)';\n});\n\n// define Global method that will return instance of MyArray\nHistone.register(Histone.Global.prototype, 'getMyArray', function(self, args) {\n    var result = new MyArray;\n    result.set('very');\n    result.set('secret');\n    result.set('content');\n    return result;\n});\n\n// (SECRET_CONTENT)\nHistone('{{getMyArray-\u003etoString}}').render(console.info);\n// very secret content\nHistone('{{getMyArray-\u003etoString(\"password\")}}').render(console.info);\n```\n\n### Magic methods\n\nSecond argument to [Histone.register](../../wiki/Histone.register) most of the time represents name of the registered method as a string, however there are some MAGIC methods that is used in special cases:\n\n* [Histone.M_GET](../../wiki/Histone.register#using-histonem_get-to-specify-property-getter) - called in case of attempt to read value's property, acts as property getter\n* [Histone.M_CALL](../../wiki/Histone.register#using-histonem_call-to-specify-call-handler) - called in case of attempt to call value as a method\n* [Histone.M_TOJS](../../wiki/Histone.register#using-histonem_tojs-to-specify-tojavascript-convertor) - called when conversion to native JavaScript value is required\n\n```javascript\nvar Histone = require('histone');\n\nfunction MyObject() {\n    this.internalObj = {\n       foo: 'bar',\n       bar: 'foo'\n    };\n}\n\n// register property getter\nHistone.register(MyObject.prototype, Histone.M_GET, function(self, args) {\n    return self.internalObj[args[0]];\n});\n\n// register call handler\nHistone.register(MyObject.prototype, Histone.M_CALL, function(self, args) {\n    return 'MyObject instance called as method!';\n});\n\n// register convertor to native JavaScript value\nHistone.register(MyObject.prototype, Histone.M_TOJS, function(self, args) {\n    return 'NATIVE_JS_VALUE';\n});\n\n// register method that returns MyObject instance\nHistone.register(Histone.Global.prototype, 'getMyObject', function(self, args) {\n    return new MyObject;\n});\n\nHistone('{{getMyObject.foo}}').render(function(result) {\n    // bar\n    console.info(result);\n});\n\nHistone('{{getMyObject()()}}').render(function(result) {\n    // MyObject instance called as method!\n    console.info(result);\n});\n\nHistone('{{return getMyObject}}').render(function(result) {\n    // NATIVE_JS_VALUE\n    console.info(result);\n});\n```\n\n### Converting templates into AST representation\n\nTemplate source code is good when you're developing your project, but once you go in production, parsing templates from source code is unnecessary overhead, so before uploading production version of you project, you'll want to convert all your templates into intermediate AST form, which won't require parser and will allow templates to be executed way more faster. In this case you use [getAST](../../wiki/Template.getAST) method wich will return AST tree for the specified template source code:\n\n```javascript\nvar Histone = require('histone');\nvar templateAST = Histone('10 x 2 = {{10 * 2}}').getAST();\n```\n\nThere are plenty of useful Node.js® modules, so you can figure out yourself how to process project's file set and convert all found \".tpl\" files into AST representation using code snippet provided above.\n\n### Managing internal Histone cache\n\nResults of call to Histone require, loadText, loadJSON method are cached by default, which means that the second call with the same argument will give you the same result as it was for the first time. It's good in the production (where nobody changes your templates), but it becomes a real problem in developement environment where template files are changed pretty frequent, so if you don't want to restart your server after each change in the template file you'll have to clear internal Histone cache on every change. In case if you don't want Histone to cache anything at all, simply turn off the cache before doing anything else:\n\n```javascript\nHistone.setCache(false);\n```\n\nBut in combination with great [chokidar](https://github.com/paulmillr/chokidar) module and [Histone.clearCache](../../wiki/Histone.clearCache), you can solve it more cleaver way:\n\n```javascript\n// watch for changes in tpl files\nchokidar.watch('**/*.tpl', {\n    cwd: __dirname,\n    ignoreInitial: true\n})\n// clear Histone cache on change\n.on('all', Histone.clearCache);\n```\n\n### Performing network operations\n\nSometimes you need to load text - file, JSON - file or template in your JavaScript code the way you're doing in the template. Of course you can use [Histone.invoke](../../wiki/Histone.invoke) to do that, but there is more convenient ways of doing that: [Histone.loadText](../../wiki/Histone.loadText), [Histone.loadJSON](../../wiki/Histone.loadJSON) and [Histone.require](../../wiki/Histone.require). All of this methods are behaving exactly as they were called from the template or using [Histone.invoke](../../wiki/Histone.invoke), it means that network request goes through the resource loader set by [Histone.setResourceLoader](../../wiki/Histone.setResourceLoader) and internal caching mechanism.\n\n```javascript\n// load text file using template\nHistone('{{return loadText(\"file.txt\")}}').render(function(result) {\n    console.info(result);\n});\n\n// load text file using Histone.invoke\nHistone.invoke(Histone.global, 'loadText', 'file.txt', function(result) {\n    console.info(result);\n});\n\n// load text file using Histone.loadText\nHistone.loadText('file.txt', function(result) {\n    console.info(result);\n});\n```\n\nWhen loading JSON - file, using [Histone.loadJSON](../../wiki/Histone.loadJSON) it's important to realize that result will always be converted into Histone data type:\n\n```javascript\n// load JSON file using Histone.loadJSON\nHistone.loadJSON('test.json', function(result) {\n    // result might be Histone or JavaScript value\n    console.info(result);\n});\n```\n\nYou can explicitly specify **Histone.R_JS** as desired result type:\n\n```javascript\n// load JSON file using Histone.loadJSON\nHistone.loadJSON('test.json', function(result) {\n    // result always JavaScript value\n    console.info(result);\n}, Histone.R_JS);\n```\n\nSame goes for require:\n\n```javascript\n// load and process template using Histone.require\nHistone.require('test.tpl', function(result) {\n    // result might be Histone or JavaScript value\n    console.info(result);\n});\n```\n\nIf you explicitly specify **Histone.R_JS** as desired result type, then returned result will be converted into corresponding JavaScript value:\n\n```javascript\n// load and process template using Histone.require\nHistone.require('test.tpl', function(result) {\n    // result always JavaScript value\n    console.info(result);\n}, Histone.R_JS);\n```\n\nIf you need string, set **Histone.R_STRING** as desired result type:\n\n```javascript\n// load and process template using Histone.require\nHistone.require('test.tpl', function(result) {\n    // result always string\n    console.info(result);\n}, Histone.R_STRING);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangrycoding%2Fhistone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fangrycoding%2Fhistone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangrycoding%2Fhistone/lists"}