{"id":14384569,"url":"https://github.com/medfreeman/remark-generic-extensions","last_synced_at":"2025-03-16T13:31:02.018Z","repository":{"id":57117000,"uuid":"91032617","full_name":"medfreeman/remark-generic-extensions","owner":"medfreeman","description":"!Extension[Content](Argument){Properties} -\u003e :tada: — commonmark generic directive extension for remark","archived":false,"fork":false,"pushed_at":"2020-05-31T00:30:33.000Z","size":7344,"stargazers_count":25,"open_issues_count":39,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-27T09:34:43.163Z","etag":null,"topics":["commonmark","html","markdown","react","remark","remark-plugin"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/medfreeman.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-05-11T23:45:31.000Z","updated_at":"2024-10-28T02:48:59.000Z","dependencies_parsed_at":"2022-08-22T22:20:24.883Z","dependency_job_id":null,"html_url":"https://github.com/medfreeman/remark-generic-extensions","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/medfreeman%2Fremark-generic-extensions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/medfreeman%2Fremark-generic-extensions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/medfreeman%2Fremark-generic-extensions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/medfreeman%2Fremark-generic-extensions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/medfreeman","download_url":"https://codeload.github.com/medfreeman/remark-generic-extensions/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243815579,"owners_count":20352194,"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":["commonmark","html","markdown","react","remark","remark-plugin"],"created_at":"2024-08-28T18:01:28.840Z","updated_at":"2025-03-16T13:31:01.455Z","avatar_url":"https://github.com/medfreeman.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# remark-generic-extensions\n\n[![npm version](https://img.shields.io/npm/v/remark-generic-extensions.svg)](https://www.npmjs.com/package/remark-generic-extensions)\n[![npm](https://img.shields.io/npm/dt/remark-generic-extensions.svg?style=flat-square)](https://npmjs.com/package/remark-generic-extensions)\n[![CircleCI](https://img.shields.io/circleci/project/github/medfreeman/remark-generic-extensions/master.svg)](https://circleci.com/gh/medfreeman/remark-generic-extensions)\n[![Coverage Status](https://img.shields.io/coveralls/medfreeman/remark-generic-extensions/master.svg)](https://coveralls.io/github/medfreeman/remark-generic-extensions?branch=master)\n[![Greenkeeper badge](https://badges.greenkeeper.io/medfreeman/remark-generic-extensions.svg)](https://greenkeeper.io/)\n[![dependencies Status](https://img.shields.io/david/medfreeman/remark-generic-extensions.svg)](https://david-dm.org/medfreeman/remark-generic-extensions)\n[![devDependencies Status](https://img.shields.io/david/dev/medfreeman/remark-generic-extensions.svg)](https://david-dm.org/medfreeman/remark-generic-extensions?type=dev)\n\n[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n\nAllows the use of [commonmark generic directive extension](https://github.com/jgm/CommonMark/wiki/Generic-Directive-Extension-List) in markdown,\ngenerating components through [remark-html](https://github.com/wooorm/remark-html) or [remark-react](https://github.com/mapbox/remark-react).\n\nThis module also works in browser environments.\n\n[📖 **Release Notes**](./CHANGELOG.md)\n\n### Demo\n\nHere's a demo using [remark-react](https://github.com/mapbox/remark-react) and [react-toolbox](https://github.com/react-toolbox/react-toolbox).\nIt is made using [create-react-app](https://github.com/facebookincubator/create-react-app), the [source is here](https://github.com/medfreeman/remark-generic-extensions/tree/master/examples/react-toolbox-icon) and can also be run locally.\n\n[![Edit medfreeman/remark-generic-extensions: react-toolbox-icon](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/medfreeman/remark-generic-extensions/tree/master/examples/react-toolbox-icon)\n\n## Disclaimer\n\nRemember that the following syntax is experimental in regards to the commonmark spec, and will perhaps never be supported officialy.\n\n```\nGeneric Directives is still in active discussion in http://talk.commonmark.org/t/generic-directives-plugins-syntax . But for brainstorming purposes, here is some possible extensions to support, or at least adhere to if not included.\n\nIt might look like !extensionName[](){} for inline\n\nand for block (Current talk page at http://talk.commonmark.org/t/block-directives/802 )\n\nextentionNames: argumentField \n:::\n...BlockContent...\n:::\n{ #id .class key1=value key2=value }\n```\n\nThere is a [known bug in remark-react \u003c 4.0.1](https://github.com/mapbox/remark-react/issues/41), that wrongly coerces non-string values to strings.\n\nMake sure to use at least v4.0.1.\n\n## Syntax\n\n### Inline extensions\n\n`!Extension[Content](Argument){Properties}`\n\n:information_source: The extension syntax is validated through [regexes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp), that you can inspect [here](https://github.com/medfreeman/remark-generic-extensions/blob/master/src/utils/regexes.js) if needed\n\n- `Extension` defines the element you want to use\n\n  It matches the `\\w` character class.\n\n  ```\n  Matches any alphanumeric character from the basic Latin alphabet, including the underscore. Equivalent to [A-Za-z0-9_].\n  ```\n\n- `Content` defines the element content\n\n  It matches everything but the `]` character.\n  \n  It can be mapped to any hast element property or value, see [placeholders](#placeholders).\n\n- `Argument` defines the element argument\n\n  It matches everything but the `)` character.\n  \n  It can be mapped to any hast element property or value, see [placeholders](#placeholders).\n\n- `Properties` defines the element properties\n\n  They can have leading and / or trailing spaces before / after the opening / closing braces.\n  \n  The different properties are separated by spaces, and so each of them match any character but spaces, except for quoted properties.\n\n### Block extensions\n\n```\nExtension: Argument\n:::\n[Content]\n:::\n{Properties}\n```\n\n:information_source: The extension syntax is validated through [regexes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp), that you can inspect [here](https://github.com/medfreeman/remark-generic-extensions/blob/master/src/utils/regexes.js) if needed\n\n- `Extension` defines the element you want to use\n\n  It matches the `\\w` character class.\n\n  ```\n  Matches any alphanumeric character from the basic Latin alphabet, including the underscore. Equivalent to [A-Za-z0-9_].\n  ```\n\n- `Argument` defines the element argument\n\n  It matches everything but a line break.\n  \n  It can be mapped to any hast element property or value, see [placeholders](#placeholders).\n\n- `Content` defines the element content\n\n  It matches everything, and stops at the next `:::` occurence.\n\n  Leading and trailing line breaks will be stripped.\n  \n  It can be mapped to any hast element property or value, see [placeholders](#placeholders).\n\n- `Properties` defines the element properties\n\n  They can have leading and / or trailing spaces before / after the opening / closing braces.\n  \n  The different properties are separated by spaces, and so each of them match any character but spaces, except for quoted properties.\n\n### Available properties\n\n  - id: `#my-id`\n\n    It will be applied to the top-level hast element.\n  - class: `.my-class .my-other-class`\n\n    It will be applied to the top-level hast element.\n  - key / value property: `my-prop=my-value`\n\n    It can be mapped to any hast element property or value, see [placeholders](#placeholders).\n  - key / value quoted property: `my-other-prop=\"my value with spaces\"`\n\n    It can be mapped to any hast element property or value, see [placeholders](#placeholders).\n  - lone property: `my-alone-prop`\n\n    It can be mapped to any hast element property or value, see [placeholders](#placeholders).\n\n## Installation\n\n```bash\nnpm install remark-generic-extensions\n```\n\nOR\n\n```bash\nyarn add remark-generic-extensions\n```\n\n## Usage (es6)\n\n### *with [`remark-react`](https://github.com/mapbox/remark-react)*\n\nSee [demo](#demo)\n\n### *with [`remark-html`](https://github.com/wooorm/remark-html)*\n\nSay we have the following file, `example.md`:\n\n```markdown\n# Alpha\n\n!alert[My message!](my subtext is rad){ #my-alert .custom-alert }\n\nyoutube: C8NAYW-Z54o\n:::\nMy featured video!\n:::\n{ #my-video .custom-video-style spanClassName=custom-span-class }\n\n## Bravo\n\n## Delta\n```\n\nAnd our script, `example.js`, looks as follows:\n\n```javascript\nimport vfile from \"to-vfile\"\nimport remark from \"remark\"\nimport genericExtensions from \"remark-generic-extensions\"\nimport html from \"remark-html\"\n\nremark()\n.use(genericExtensions,\n  {\n    elements: {\n      alert: {\n        html: {\n          tagName: \"span\",\n          children: [\n            {\n              type: \"element\",\n              tagName: \"i\",\n              properties: {\n                className: \"fa fa-exclamation\",\n                ariaHidden: true\n              }\n            },\n            {\n              type: \"element\",\n              tagName: \"span\",\n              children: [\n                {\n                  type: \"text\",\n                  value: \"::content::\"\n                }\n              ]\n            },\n            {\n              type: \"element\",\n              tagName: \"span\",\n              properties: {\n                className: \"subtext\"\n              },\n              children: [\n                {\n                  type: \"text\",\n                  value: \"::argument::\"\n                }\n              ]\n            }\n          ]\n        }\n      }\n    },\n    youtube: {\n      html: {\n        tagName: \"div\",\n        children: [\n          {\n            type: \"element\",\n            tagName: \"iframe\",\n            properties: {\n              width: 420,\n              height: 315,\n              src: \"https://www.youtube.com/embed/::argument::\"\n            }\n          },\n          {\n            tagName: \"span\",\n            properties: {\n              className: \"::prop::spanClassName::\"\n            },\n            children: [\n              {\n                type: \"text\",\n                value: \"::content::\"\n              }\n            ]\n          }\n        ]\n      }\n    }\n  }\n)\n.use(html)\n.process(vfile.readSync('example.md'), (err, file) =\u003e {\n  if (err) throw err\n  console.log(String(file))\n})\n```\n\nNow, running `node example` yields (indented):\n\n```html\n\u003ch1\u003eAlpha\u003c/h1\u003e\n\n\u003cp\u003e\n  \u003cspan id=\"my-alert\" class=\"custom-alert\"\u003e\n    \u003ci class=\"fa fa-exclamation\" aria-hidden=\"true\"\u003e\u003c/i\u003e\n    \u003cspan\u003eMy message!\u003c/span\u003e\n    \u003cspan class=\"subtext\"\u003emy subtext is rad\u003c/span\u003e\n  \u003c/span\u003e\n\u003c/p\u003e\n\n\u003cdiv class=\"custom-video-style\" id=\"my-video\"\u003e\n  \u003ciframe width=\"420\" height=\"315\" src=\"https://www.youtube.com/embed/C8NAYW-Z54o\"\u003e\u003c/iframe\u003e\n  \u003cspan class=\"custom-span-class\"\u003eMy featured video!\u003c/span\u003e\n\u003c/div\u003e\n\n\u003ch2\u003eBravo\u003c/h2\u003e\n\n\u003ch2\u003eDelta\u003c/h2\u003e\n```\n\n## API\n\n### `remark().use(genericExtensions[, options])`\n\nConvert generic extensions in a markdown document to an [hast](https://github.com/syntax-tree/hast) syntax tree,\nsuitable for rendering to html / react.\n\n*   Looks for all inline extensions (if providing elements configuration the extension names are case sensitive)\n*   Tells remark how to interpret them according to the options\n\n#### `options` (object)\n\nAll options are validated through [joi](https://github.com/hapijs/joi).\nYou can find the schema [here](https://github.com/medfreeman/remark-generic-extensions/blob/master/src/utils/optionsSchema.js).\nIn case of error, it will be logged to the console and this module bypassed by remark.\n\n##### Properties\n\n- elements ([`Elements`](#elements-object), optional, default `{}`) - A list of inline elements to support\n    along with their configuration\n\n- placeholderAffix (string, optional, default `\"::\"`) - String that encloses `content`,\n    `argument` and `prop` tokens in properties\n    of the `elements` option, for dynamic replacement with properties specified in the markdown element.\n\n    See [`HastProperties`](#hastproperties-object) for more information.\n\n- debug (boolean, default: `false`) - Whether to show debug messages\n  through [vfile-reporter](https://github.com/vfile/vfile-reporter)\n    \n    See [Logging](#logging) for more information.\n\n---\n\n#### `Elements` (object)\n\nThis object defines the extensions configuration.\n\nThe keys are strings corresponding to the inline extension names (i.e. `Icon`).\n\nYou can define one or more extensions if needed.\n\n##### Properties\n\n- *extensionName* (string): (object)\n  - propsDefaultValues (object, optional)\n    - *propertyName* (string): (any) - default value of the property\n      \n      It will be applied to items that specify\n      the corresponding property without a defined value, i.e.\n\n      \u003cdetails\u003e\u003csummary\u003eexample with `highlight` property on `icon` extension (es6)\u003c/summary\u003e\u003cp\u003e\n\n      ```javascript\n      import remark from \"remark\"\n      import genericExtensions \"remark-generic-extensions\"\n      import html from \"remark-html\"\n\n      remark()\n      .use(genericExtensions,\n        {\n          elements: {\n            icon: {\n              propsDefaultValues: {\n                highlight: true,\n              }\n            }\n          }\n        }\n      )\n      .use(html)\n      .process(\"!icon{highlight}\", (err, file) =\u003e {\n        if (err) throw err\n        console.log(String(file))\n      })\n      ```\n\n      Running this example would yield `\u003cp\u003e\u003cicon highlight=\"true\"\u003e\u003c/icon\u003e\u003c/p\u003e`\n\n      \u003c/p\u003e\u003c/details\u003e\n\n  - html (object, optional, mutually exclusive with `replace`) - html element representation used for rendering the extension\n    - tagName (string, optional, defaults to the extension name) - html5 element tag name\n    - children ([`Hast`](#hast-arrayobject), optional) - the element children\n    - properties ([`HastProperties`](#hastproperties-object), optional) - the element properties\n\n  - replace (function, optional, mutually exclusive with `html`) - function whose return value will be used for rendering the extension\n\n    arguments:\n    - type (enum[string], \"inline-extension\" OR \"block-extension\")\n    - element (object)\n      - *extensionName* (string) - same as above\n      - content (string) - the element content\n      - argument (string) - the element argument\n      - properties (object) - A map of computed properties names / values\n    - warning (function(string)) - VFile warning function\n    - debug (function(string)) - VFile debug function\n\n---\n\n#### `Hast` (array[object])\n\nThis structure is a [hast](https://github.com/syntax-tree/hast) tree, with a few restrictions.\n\nIt is recursive, the `children` property also being of `Hast` type.\n\n##### Properties\n\n- type (enum[string], optional, default `\"element\"`) - hast node type\n  - element\n  - comment\n  - text\n- tagName (string, required when type === \"element\") - html5 element tag name\n- value (string, required when type === (\"comment\" || \"text\")) - comment or text content, supports [placeholders](#placeholders)\n- children ([`Hast`](#hast-arrayobject), optional) - the element children\n- properties ([`HastProperties`](#hastproperties-object)) - the element properties\n\n---\n\n#### `HastProperties` (object)\n\nThis object pairs are mapped to [hast properties](https://github.com/syntax-tree/hast#properties), and thus follow the same rules.\n\n##### Properties\n\n- *propertyName* (string, except \"class\" \u0026\u0026 \"for\"): (enum)\n  - (string) - When a property value is a string,\n    it supports [placeholders](#placeholders) that will be replaced by their corresponding value.\n\n  - (any) - A property value can also be of any other type\n\n:information_source: Any property present in a markdown extension and not referenced by a placeholder will be applied to the top-level element.\n\n:information_source: If the `content` property is not referenced on a block element, it will be applied to a child `text` node of the top-level element.\n\n## Placeholders\n\nThe `value` property and all `properties` members in [`Hast`](#hast-arrayobject) children support placeholders.\n\nThe available placeholders are:\n  - \"::content::\" -\u003e will be replaced by the `content` part of the extension in markdown (the part between `[]`)\n  - \"::argument::\" -\u003e will be replaced by the `argument` part of the extension in markdown (the part between `()`)\n  - \"::prop::*property*::\" -\u003e will be replaced by the corresponding `property` value present in the extension in markdown (in the part between `{}`)\n\n:information_source: the available properties are `id`, `className` or any other property defined in your markdown.\n\nSpecifying the [`placeholderAffix` option](#properties) allows changing the placeholders.\nFor example, using \"||\" would make the available placeholders become \"||content||\", \"||argument||\" and \"||prop||*property*||\".\n\n## Logging\n\nAll logging, except the [options validation](#options-object) that is directly logged to the console, takes place through [vfile-reporter](https://github.com/vfile/vfile-reporter).\n\nIt allows having nice error messages with positional information, and is also the standard way of logging with [unifiedjs](https://github.com/unifiedjs/unified).\n\nBy default, this module logs warnings, but enabling the [`debug` option](#properties) will also log debug messages, useful for troubleshooting.\n\n\u003cdetails\u003e\u003csummary\u003elogging example (es6)\u003c/summary\u003e\u003cp\u003e\n\n```javascript\nimport remark from \"remark\"\nimport genericExtensions \"remark-generic-extensions\"\nimport html from \"remark-html\"\nimport report from \"vfile-reporter\"\n\nremark()\n.use(genericExtensions, {})\n.use(html)\n.process(input, function(err, file) {\n  console.log(report(err || file))\n})\n```\n\n\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003edebugging example (es6)\u003c/summary\u003e\u003cp\u003e\n\n```javascript\nimport remark from \"remark\"\nimport genericExtensions \"remark-generic-extensions\"\nimport html from \"remark-html\"\nimport report from \"vfile-reporter\"\n\nremark()\n.use(genericExtensions, { debug: true })\n.use(html)\n.process(input, function(err, file) {\n  console.log(report(err || file))\n})\n```\n\n\u003c/p\u003e\u003c/details\u003e\n\n---\n\n## CONTRIBUTING\n\n* ⇄ Pull requests and ★ Stars are always welcome.\n* For bugs and feature requests, please create an issue.\n* Pull requests must be accompanied by passing automated tests (`$ yarn test`).\n\n## LICENSE\n\n[Apache License 2.0](./LICENSE)\n\nCopyright (c) Mehdi Lahlou \u003cmlahlou@protonmail.ch\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmedfreeman%2Fremark-generic-extensions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmedfreeman%2Fremark-generic-extensions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmedfreeman%2Fremark-generic-extensions/lists"}