{"id":15065486,"url":"https://github.com/damianc/shortcodejs","last_synced_at":"2025-09-22T23:22:51.903Z","repository":{"id":40844340,"uuid":"134153261","full_name":"damianc/ShortcodeJS","owner":"damianc","description":"A tiny library allowing to compose website components being used repeatedly.","archived":false,"fork":false,"pushed_at":"2023-07-08T02:14:49.000Z","size":58,"stargazers_count":6,"open_issues_count":4,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-25T12:43:27.170Z","etag":null,"topics":["shortcode","shortcode-ui","template-engine","templates","transpiler","wordpress","wordpress-development"],"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/damianc.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":"2018-05-20T13:31:25.000Z","updated_at":"2024-12-04T05:01:42.000Z","dependencies_parsed_at":"2025-04-10T16:43:01.594Z","dependency_job_id":"0918c7d3-368b-4f39-a0d8-3b2527b6f6bb","html_url":"https://github.com/damianc/ShortcodeJS","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/damianc/ShortcodeJS","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/damianc%2FShortcodeJS","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/damianc%2FShortcodeJS/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/damianc%2FShortcodeJS/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/damianc%2FShortcodeJS/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/damianc","download_url":"https://codeload.github.com/damianc/ShortcodeJS/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/damianc%2FShortcodeJS/sbom","scorecard":{"id":317981,"data":{"date":"2025-08-11","repo":{"name":"github.com/damianc/ShortcodeJS","commit":"17c2954b07644060475cf41e350f9824407a8f71"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.3,"checks":[{"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":"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":"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":"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":"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":"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":"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":"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":"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"}},{"name":"Vulnerabilities","score":0,"reason":"20 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-6chw-6frg-f759","Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-rq8g-5pc5-wrhr","Warn: Project is vulnerable to: GHSA-qrmc-fj45-qfc2","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-44pw-h2cw-w3vq","Warn: Project is vulnerable to: GHSA-c429-5p7v-vgjp","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-4xc9-xhrj-v574","Warn: Project is vulnerable to: GHSA-x5rq-j2xg-h7qm","Warn: Project is vulnerable to: GHSA-jf85-cpcp-j695","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T00:41:59.923Z","repository_id":40844340,"created_at":"2025-08-18T00:41:59.923Z","updated_at":"2025-08-18T00:41:59.923Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276487888,"owners_count":25651213,"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-22T02:00:08.972Z","response_time":79,"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":["shortcode","shortcode-ui","template-engine","templates","transpiler","wordpress","wordpress-development"],"created_at":"2024-09-25T00:39:10.990Z","updated_at":"2025-09-22T23:22:51.867Z","avatar_url":"https://github.com/damianc.png","language":"JavaScript","readme":"# ShortcodeJS\n\nA tiny library allowing to compose website components being used repeatedly by wrapping them in the callbacks that produce respective HTML markup.\n\n## Using the library\n\nFirst of all, you need to include _ShortcodeJS_ library. When you're done with the former, new shortcodes are meant to be registered with\nthe `Shortcode.register()` method. Finally, sources can be parsed by the `Shortcode.parse()` method.\n\nThere are two kinds of shortcode:\n* _empty shortcode_ being standalone shortcode with no content surrounded, e.g. `[shortcode/]`\n* _content shortcode_ being shortcode that surrounds a content, e.g. `[shortcode]Content.[/shortcode]`\n\nIn addition, both can have attributes assigned, e.g. `[shortcode attr=\"val\"/]`.\n\n### Methods overview\n\n**`Shortcode.register(name, cb)`**\n\nRegisters new shortcode.  \nReturns: `undefined`.  \nParameters:\n* `name` - a `string` that represents the name of the shortcode\n* `cb` - a callback `function` that returns HTML markup, having taken up to 2 parameters:\n\t* `attr` - an `object` containing attributes assigned to a shortcode\n\t* `content` - a `string` representing the content of a shortcode\n\n**`Shortcode.parse(source[, variables])`**\n\nParses a source turning registered shortcodes into respecitve HTML markup.  \nReturns: `string` being HTML markup.  \nParameters:\n* `source` - a `string` that holds the content to be parsed\n* `variables` - a `object` that holds variables that can be interpolated in the content\n(consult [Interpolating variables](#interpolating-variables) for details)\n\n**`Shortcode.set(option, value)`**\n\nSets a particular option using given value.  \nReturns: `undefined`.  \nParameters:\n* `option` - a `string` representing a name of the option being set\n* `value` - a `string` representing a value to set\n\nThe table below shows available options to set.\n\nOption | Default value | Description\n-------|---------------|------------\n`attributeNameToCamelCase` | `true` | Whether to turn dash-case attribute name into camelCase, for example `sc-attr` into `scAttr`.\n\n\n### Complete example\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\n\u003chead\u003e\n    \u003cmeta charset=\"utf-8\" /\u003e\n    \u003ctitle\u003eShortcodeJS\u003c/title\u003e\n\u003c/head\u003e\n\n\u003cbody\u003e\n    \u003cblockquote id=\"quotation\"\u003e\n        \u003cp\u003eWe don't need another JavaScript framework. We need stuff like the [b]ShortcodeJS[/b] library.\u003c/p\u003e\n        \u003ccite\u003e~ @:author\u003c/cite\u003e\n    \u003c/blockquote\u003e\n\n    \u003cscript src=\"shortcode.js\"\u003e\u003c/script\u003e\n    \u003cscript\u003e\n        Shortcode.register('b', function (attr, content) {\n            return `\u003cb\u003e${content}\u003c/b\u003e`;\n        });\n\n        var quotation = document.getElementById('quotation');\n        quotation.innerHTML = Shortcode.parse(quotation.innerHTML, {author: 'A. Lincoln'});\n    \u003c/script\u003e\n\u003c/body\u003e\n\n\u003c/html\u003e\n```\n\nNote that the name of a shortcode is passed as first argument of the `Shortcode.register()` method, then this name is used within\na content that will be processed.\n\n## Composing a component\n\n### Empty shortcode\n\nSimplest component only consists of name.  \nNeither component's attributes nor its content is involved, therefore no parameters are used with the callback composing HTML markup.\n\n```javascript\nShortcode.register('separator', function () {\n    return '\u003chr /\u003e';\n});\n\n/*\n    given input:\n    [separator/]\n\n    expected output:\n    \u003chr /\u003e\n*/\n```\n\n### Empty shortcode with attributes\n\nRight beside the name, a shortcode can have attributes assigned.  \nIt can be done the same way as if it were regular HTML element.\n\n```javascript\nShortcode.register('separator', function (attr) {\n    return `\u003chr style=\"width: ${attr.width}\" /\u003e`;\n});\n\n/*\n    given input:\n    [separator width=\"50%\"/]\n\n    expected output:\n    \u003chr style=\"width: 50%\" /\u003e\n*/\n```\n\n### Content shortcode\n\nAs well, the shortcodes are able to hold content, including another nested shortcodes.  \nThough the example below does not use attributes, passing `attr` parameter is essential as it precedes the `content` parameter that we make use of.\n\n```javascript\nShortcode.register('frame', function (attr, content) {\n    return `\u003cdiv style=\"border: solid 1px #333\"\u003e${content}\u003c/div\u003e`;\n});\n\n/*\n    given input:\n    [frame]This content is important.[/frame]\n\n    expected output:\n    \u003cdiv style=\"border: solid 1px #333\"\u003eThis content is important.\u003c/div\u003e\n*/\n```\n\n### Content shortcode with attributes\n\nContent shortcodes are any less different when it comes to assigning attributes.\n\n```javascript\nShortcode.register('cite', function (attr, content) {\n    return `@${attr.user}: ${content}`;\n});\n\n/*\n    given input:\n    [cite user=\"damianc\"]I hope you will make good use of it.[/cite]\n\n    expected output:\n    @damianc: I hope you will make good use of it.\n*/\n```\n\n### Interpolating variables\n\nAn input string can have assigned variables whose values will be inserted when parsing.\nTo indicate placeholder for a variable, it's necessary to use `@:name` or `@@:name` syntax.\nThere are two kinds of such variables:\n\n* _pre-parsing_ - these variables will be interpolated before processing shortcodes (use `@@:name` syntax)\n* _post-parsing_ - these variables will be interpolated after processing shortcodes (use `@:name` syntax)\n\nValues of variables are being received from an object passed as a second parameter of the `parse()` method call.\nThe keys of the object are mapped to variable names used within an input string while while their values correspond to the\nvalues of the object's properties with identical names.\n\nIn the code below, following steps are being done:\n* `@@:textDecoration` is replaced with `b` string\n* the input string with shortcodes embedded is processed\n* `@:languageName` is replaced with `JavaScript`, `@:libraryName` is replaced with `ShortcodeJS`\n\n```html\n\u003cp id=\"frame\"\u003e\n    Among @:languageName libraries worth to discover is [@@:textDecoration]@:libraryName[/@@:textDecoration].\n\u003c/p\u003e\n```\n\n```javascript\nvar frame = document.getElementById('frame');\nframe.innerHTML = Shortcode.parse(frame.innerHTML, {\n    textDecoration: 'bold' ? 'b' : 'u',\n    languageName: 'JavaScript',\n    libraryName: 'ShortcodeJS'\n});\n\n/*\n    expected output:\n    Among JavaScript libraries worth to discover is \u003cb\u003eShortcodeJS\u003c/b\u003e.\n*/\n```\n\nAs done in the code above, using pre-parsing variables is recommended mostly for things that can affect process of parsing a shortcode,\ni.e., name of a shortcode or values that its attributes have assigned. Other values can be inserted after the shortcode parsing is\nperfrormed; this is what post-parsing variables are meant to.\n\n## Default attribute values\n\nIt may happen that your shortcode is to take a multiple of attributes of which not all are required.\nIn the case, default values should be guaranteed to be delivered.\n\n\u003e  \n\u003e **Note that attribute names must not contain uppercase characters as they will not be preserved.**  \u003cbr/\u003e\u003cbr/\u003e\n\u003e Even if you use a shortcode like `[frame borderColor=\"red\"]`, the `attr` object is to contain `bordercolor` property rather than `borderColor`.  \u003cbr/\u003e\u003cbr/\u003e\n\u003e Still, you could use dash-case name, e.g. `[frame border-color=\"red\"]`, in which case the respective property name can remain the same, i.e. `border-color` (keep in mind that such a name is required to be surrounded with quotes when accessed).\nSee [Combined attribute names](#combined-attribute-names) for details.\n\u003e  \n\n```javascript\nShortcode.register('frame', function (attr, content) {\n    var settings = Object.assign({\n        borderwidth: '1px',\n        bordercolor: '#333'\n    }, attr);\n\t\n    return `\u003cdiv style=\"border: solid ${settings.borderwidth} ${settings.bordercolor}\"\u003e\n        ${content}\n    \u003c/div\u003e`;\n});\n\n/*\n    given input:\n    [frame bordercolor=\"red\"]This message is very important![/frame]\n\n    expected output:\n    \u003cdiv style=\"border: solid 1px red\"\u003eThis message is very important!\u003c/div\u003e\n*/\n```\n\n## Combined attribute names\n\nBy default, attribute names consisting of the words separated by dash are turning into the camelCase form to be accessed with the `attr` object in the shortcode callback (e.g. `sc-attr` -\u003e `scAttr`). Why that happens is because the `attributeNameToCamelCase` setting is set to `true` by default. To keep attribute names dash-case set this option to `false` with `Shortcode.set()` method.\n\n```javascript\nShortcode.set('attributeNameToCamelCase', false);\n```\n\n## Running out of browser\n\nShortcodeJS is supposed to run in browser environment that delivers the `window.document` object.\nFor environments like Node.js (without the `document` object by default), function returning ShortcodeJS API is provided - this function takes appropriate `document` object that can be derived from an external library like [jsdom](https://github.com/jsdom/jsdom).\n\n```javascript\n    const { JSDOM } = require('jsdom');\n    const dom = new JSDOM('\u003c!DOCTYPE html\u003e\u003c/html\u003e');\n    const { document } = dom.window;\n    const Shortcode = require('./shortcode')(document);\n\n    // ...\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdamianc%2Fshortcodejs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdamianc%2Fshortcodejs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdamianc%2Fshortcodejs/lists"}