{"id":18997697,"url":"https://github.com/s0/remark-code-extra","last_synced_at":"2025-04-22T14:24:30.574Z","repository":{"id":47228347,"uuid":"194368925","full_name":"s0/remark-code-extra","owner":"s0","description":"Add to or transform the HTML output of markdown code blocks using remark","archived":false,"fork":false,"pushed_at":"2022-12-03T21:17:30.000Z","size":891,"stargazers_count":25,"open_issues_count":13,"forks_count":4,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-04-11T07:23:57.610Z","etag":null,"topics":["markdown","remark","remark-plugin"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/s0.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2019-06-29T05:41:24.000Z","updated_at":"2024-12-17T09:15:18.000Z","dependencies_parsed_at":"2023-01-23T14:31:23.261Z","dependency_job_id":null,"html_url":"https://github.com/s0/remark-code-extra","commit_stats":null,"previous_names":["samlanning/remark-code-extra"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s0%2Fremark-code-extra","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s0%2Fremark-code-extra/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s0%2Fremark-code-extra/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s0%2Fremark-code-extra/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/s0","download_url":"https://codeload.github.com/s0/remark-code-extra/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249273882,"owners_count":21241986,"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":["markdown","remark","remark-plugin"],"created_at":"2024-11-08T17:42:12.117Z","updated_at":"2025-04-16T20:31:35.798Z","avatar_url":"https://github.com/s0.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# remark-code-extra\n\n[![Build Status](https://dev.azure.com/samlanning/general/_apis/build/status/remark-code-extra?branchName=master)](https://dev.azure.com/samlanning/general/_build/latest?definitionId=7\u0026branchName=master) [![Total alerts](https://img.shields.io/lgtm/alerts/g/samlanning/remark-code-extra.svg?logo=lgtm\u0026logoWidth=18)](https://lgtm.com/projects/g/samlanning/remark-code-extra/alerts/) [![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/samlanning/remark-code-extra.svg?logo=lgtm\u0026logoWidth=18)](https://lgtm.com/projects/g/samlanning/remark-code-extra/context:javascript) [![](https://img.shields.io/npm/v/remark-code-extra.svg)](https://www.npmjs.com/package/remark-code-extra)\n\nAdd to or transform the HTML output of markdown code blocks using [remark][].\n\nFor example, you can add dedicated links to code snippets that copy the code, or link to a live demo etc...\n\nThis plugin is compatible with most [remark][] syntax highlighting plugins,\nincluding [`remark-midas`](https://github.com/remarkjs/remark-midas),\n[`remark-tree-sitter`](https://github.com/samlanning/tree-sitter) and\n[`remark-highlight.js`](https://github.com/remarkjs/remark-highlight.js).\nJust make sure that you use this plugin *after* the highlighting plugins.\n\n## Install\n\n[npm][]:\n\n```sh\nnpm install remark-code-extra\n```\n\n## Use\n\nSay we have the following Markdown file, `example.md`:\n\n```markdown\nWe'll transform this one:\n\n~~~java https://stackoverflow.com/questions/4042434/converting-arrayliststring-to-string-in-java\nList\u003cString\u003e list = ..;\nString[] array = list.toArray(new String[0]);\n~~~\n\nBut leave this the same:\n\n~~~java\nList\u003cString\u003e list = ..;\nString[] array = list.toArray(new String[0]);\n~~~\n```\n\nAnd our script, `example.js`, looks as follows:\n\n```js\nconst vfile = require('to-vfile')\nconst report = require('vfile-reporter')\nconst unified = require('unified')\nconst markdown = require('remark-parse')\nconst html = require('remark-html')\nconst highlight = require('remark-highlight.js')\nconst codeExtra = require('remark-code-extra');\n\nunified()\n  .use(markdown)\n  .use(highlight)\n  .use(codeExtra, {\n    // Add a link to stackoverflow if there is one in the meta\n    transform: node =\u003e node.meta ? ({\n      after: [\n        {\n          type: 'element',\n          tagName: 'a',\n          properties: {\n            href: node.meta\n          },\n          children: [{\n            type: 'text',\n            value: 'View on Stack Overflow'\n          }]\n        }\n      ]\n    }) : null\n  })\n  .use(html)\n  .process(vfile.readSync('example.md'), (err, file) =\u003e {\n    console.error(report(err || file))\n    console.log(String(file))\n  })\n```\n\nNow, running `node example` yields:\n\n```html\n\u003cp\u003eWe'll transform this one:\u003c/p\u003e\n\u003cdiv class=\"code-extra\"\u003e\u003cpre\u003e\u003ccode class=\"hljs language-java\"\u003eList\u0026#x3C;String\u003e list = ..;\nString[] array = list.toArray(\u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e String[\u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e]);\u003c/code\u003e\u003c/pre\u003e\u003ca href=\"https://stackoverflow.com/questions/4042434/converting-arrayliststring-to-string-in-java\"\u003eView on Stack Overflow\u003c/a\u003e\u003c/div\u003e\n\u003cp\u003eBut leave this the same:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs language-java\"\u003eList\u0026#x3C;String\u003e list = ..;\nString[] array = list.toArray(\u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e String[\u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e]);\u003c/code\u003e\u003c/pre\u003e\n\n```\n\nNotice how the first codeblock is now wrapped in a `\u003cdiv\u003e` and has a link to stackoverflow added, whereas the second code block has remained unchanged.\n\nFor further examples, please see the [unit tests](tests/src/index.ts).\n\n### Use with [`remark-code-frontmatter`](https://github.com/samlanning/remark-code-frontmatter)\n\nIf you want more detailed options than the `meta` [mdast][] property provides, then you can use\n[`remark-code-frontmatter`](https://github.com/samlanning/remark-code-frontmatter)\nto include frontmatter at the top of your code block and specify detailed options.\nThe processed frontmatter is then made available to use via the `frontmatter` field.\n\nYou must make sure to use the `remark-code-frontmatter` plugin **before** using `remark-code-extra`.\n\nFor example, if you had the following markdown:\n\n````markdown\n```\n---\nbefore: Some header text\n---\nCode block with a header\n```\n\n```\n---\nafter: Some footer text\n---\nCode block with a footer\n```\n\n```\n---\nbefore: Some header text\nafter: Some footer text\n---\nCode block with a header and footer\n```\n\n```\nCode block with no header or footer\n```\n````\n\nAnd the following unified processor:\n\n```js\n// other imports\nconst codeFrontmatter = require('remark-code-frontmatter');\nconst codeExtra = require('remark-code-extra');\n\nconst processor = remark()\n  .use(codeFrontmatter)\n  .use(codeExtra, {\n    transform: node =\u003e node.frontmatter.before || node.frontmatter.after ? {\n      before: node.frontmatter.before \u0026\u0026 [{\n        type: 'text',\n        value: node.frontmatter.before\n      }],\n      after: node.frontmatter.after \u0026\u0026 [{\n        type: 'text',\n        value: node.frontmatter.after\n      }]\n    } : null\n  })\n  .use(html);\n```\n\nThen this would output the following HTML:\n\n```html\n\u003cdiv class=\"code-extra\"\u003eSome header text\u003cpre\u003e\u003ccode\u003eCode block with a header\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"code-extra\"\u003e\u003cpre\u003e\u003ccode\u003eCode block with a footer\u003c/code\u003e\u003c/pre\u003eSome footer text\u003c/div\u003e\n\u003cdiv class=\"code-extra\"\u003eSome header text\u003cpre\u003e\u003ccode\u003eCode block with a header and footer\u003c/code\u003e\u003c/pre\u003eSome footer text\u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003eCode block with no header or footer\n\u003c/code\u003e\u003c/pre\u003e\n```\n\n*Note: If you're using `remark-code-frontmatter` alongside a plugin that does code highlighting,\nmake sure you use the frontmatter plugin **before** the highlighting plugin.*\n\n## API\n\n### `remark().use(codeExtra, options)`\n\n`options` is a required parameter, and you must always specify `transform`.\n\n#### `options.transform`\n\nEither a `TransformResults` object, a function that returns a `TransformResults` object, or a function that returns a promise that eventually resolves to a `TransformResults` object.\n\nIf it is object (as opposed to a function),\nevery code block will always be \"transformed\".\nThat is, it will be wrapped in a `\u003cdiv\u003e`,\nand further plugins that interact with MDAST code blocks will not see them.\n\ne.g:\n\n```js\n{\n  transform: { \n    before: [ /* ... */ ],\n    after: [ /* ... */ ]\n  }\n}\n```\n\nIf instead it is a function,\nthen a code block will be \"transformed\"\nonly if you return a `TransformResults`.\nIf you return nothing, or `undefined` or `null` etc... \nthen the code block will remain unmodified.\n\nThe function is passed the [mdast][] node for the code block as a parameter,\nso you can transform the code block based on its markdown information.\n\n**Examples:**\n\n```js\n// Always transform\n{\n  transform: node =\u003e ({ /* TransformResults object */ })\n}\n\n// Only transform when the node has metadata\n{\n  transform: node =\u003e node.meta ? { /* TransformResults object */ } : null\n}\n\n// Asyncronously determine if and how a node should be transformed\n{\n  transform: async node =\u003e ({ /* TransformResults object */ })\n}\n```\n\n### `TransformResults`\n\nAn object that specifies how a code block should be transformed.\n\n#### `TransformResults.before`\n\n(optional) An array of [hast][] elements (or a `Promise` returning such an `Array`) to add to the top of the HTML for this code block.\n\n#### `TransformResults.after`\n\n(optional) An array of [hast][] elements (or a `Promise` returning such an `Array`) to add to the bottom of the HTML for this code block.\n\n#### `TransformResults.transform`\n\n(optional) A function that applies arbitrary changes to the [mdast][] node for this code block (after it has already been changed to a `code-extra` node and prepared as a `\u003cdiv\u003e`).\nIf this function has asyncronous operations, then it must return a `Promise`.\n\n**Example:**\n\n```js\nunified()\n  .use(markdown)\n  .use(highlight)\n  .use(codeExtra, {\n    transform: node =\u003e node.meta ? ({\n      before: [\n        {\n          type: 'text',\n          value: 'This code block has meta!'\n        }\n      ],\n      after: [\n        {\n          type: 'text',\n          value: node.meta\n        }\n      ],\n      transform: node =\u003e {\n        // Add a class to it\n        node.data.hProperties.className.push('has-meta');\n      }\n    }) : null\n  })\n```\n\n\n## Related\n\n*   [`remark-code-frontmatter`](https://github.com/samlanning/remark-code-frontmatter)\n    — Extract frontmatter from markdown code blocks\n*   [`remark-rehype`](https://github.com/remarkjs/remark-rehype)\n    — Transform Markdown to HTML\n*   [`remark-midas`](https://github.com/remarkjs/remark-midas)\n    — Highlight CSS code blocks with midas (rehype compatible)\n*   [`remark-tree-sitter`](https://github.com/samlanning/remark-tree-sitter)\n    — Highlight code with tree-sitter (rehype compatible)\n*   [`remark-highlight.js`](https://github.com/remarkjs/remark-highlight.js)\n    — Highlight code with highlight.js (via lowlight)\n*   [`rehype-highlight`](https://github.com/rehypejs/rehype-highlight)\n    — [rehype][] plugin to highlight code (via lowlight)\n*   [`rehype-prism`](https://github.com/mapbox/rehype-prism)\n    — [rehype][] plugin to highlight code (via refractor)\n*   [`rehype-shiki`](https://github.com/rsclarke/rehype-shiki)\n    — [rehype][] plugin to highlight code with shiki\n\n\u003c!-- Definitions --\u003e\n\n[hast]: https://github.com/syntax-tree/hast\n\n[mdast]: https://github.com/syntax-tree/mdast\n\n[npm]: https://docs.npmjs.com/cli/install\n\n[remark]: https://github.com/remarkjs/remark\n\n[rehype]: https://github.com/rehypejs/rehype","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fs0%2Fremark-code-extra","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fs0%2Fremark-code-extra","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fs0%2Fremark-code-extra/lists"}