{
    "componentChunkName": "component---src-templates-post-js",
    "path": "/writing-codemods-for-mdx/",
    "result": {"data":{"mdx":{"body":"var _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"title\": \"Codemods for MDX\",\n  \"date\": \"2021-07-26T00:00:00.000Z\",\n  \"summary\": \"Codebases evolve and documentation inevitably changes. In this post, we look at using a simple Node script to rewrite docs and example code from Storybooks into a custom format.\",\n  \"tags\": [\"javascript\", \"documentation\", \"jsdoc\"]\n};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, \"If you\\u2019ve never heard of a codemod, it basically means taking a portion of code and changing its contents, usually by way of \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://en.wikipedia.org/wiki/Abstract_syntax_tree\"\n  }, \"AST\"), \" transformation. We can do this for any code that has an AST, including Markdown and MDX.\"), mdx(\"p\", null, \"The burden of maintaing docs can start to sink in once you have many docs scattered throughout your codebase. This is where codemods shine, instead of trying to write a fancy regex search and replace we can write some simple JavaScript operations and rewrite our file however we desire.\"), mdx(\"h2\", {\n    \"id\": \"unified\"\n  }, \"Unified\"), mdx(\"p\", null, \"We\\u2019ll start by introducing the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://unifiedjs.com/\"\n  }, \"Unified\"), \" library. This library will be responsible for taking in our MD(X) content allowing us to transform it and turn it back into either format. Since we want to rewrite MDX we can start with their \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://unifiedjs.com/explore/package/remark-mdx/#use\"\n  }, \"boilerplate\"), \" and make some modifications:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-js\"\n  }, \"import glob from 'fast-glob'\\nimport fs from 'fs'\\nimport path from 'path'\\nimport frontmatter from 'remark-frontmatter'\\nimport mdx from 'remark-mdx'\\nimport markdown from 'remark-parse'\\nimport stringify from 'remark-stringify'\\nimport { unified } from 'unified'\\n\\nconst processor = unified()\\n  .use(markdown)\\n  .use(stringify)\\n  .use(mdx)\\n  .use(frontmatter)\\n\\nasync function program() {\\n  const paths = await glob(['packages/library/**/*.stories.mdx'])\\n\\n  paths.forEach((filePath) => {\\n    const tree = processor.parse(fs.readFileSync(filePath))\\n    let category = null\\n    let parsedMarkdown = processor.stringify({\\n      type: 'root',\\n      children: tree.children.reduce((children, child) => {\\n        const isImport = child.type === 'mdxjsEsm'\\n        const isStorybooksComponent =\\n          child.type === 'mdxJsxFlowElement' &&\\n          ['Meta', 'Props', 'ArgsTable'].includes(child.name)\\n        const isPropsHeading =\\n          child.type === 'heading' &&\\n          child.children.some((child) => child.value === 'Props')\\n\\n        if (child.name === 'Meta') {\\n          const title = child.attributes.find(\\n            (child) => child.name === 'title'\\n          ).value\\n          category = title.split('/')[0]\\n        }\\n\\n        // Filter out elements we no longer need\\n        if (isImport || isStorybooksComponent || isPropsHeading) {\\n          return children\\n        }\\n\\n        return [...children, child]\\n      }, []),\\n    })\\n\\n    parsedMarkdown = `\\n---\\ncategory: ${category}\\n---\\n${parsedMarkdown}\\n      `.trimStart()\\n\\n    const basePath = path.dirname(filePath)\\n    fs.writeFileSync(\\n      path.resolve(\\n        basePath.includes('stories')\\n          ? basePath.replace('/stories', '')\\n          : basePath,\\n        'README.mdx'\\n      ),\\n      parsedMarkdown\\n    )\\n  })\\n}\\n\\nprogram()\\n\")), mdx(\"h2\", {\n    \"id\": \"finding-docs\"\n  }, \"Finding docs\"), mdx(\"h2\", {\n    \"id\": \"rewriting\"\n  }, \"Rewriting\"), mdx(\"h3\", {\n    \"id\": \"removing-preceding-heading\"\n  }, \"Removing preceding heading\"), mdx(\"p\", null, \"This is where the power of reducers shine. Since we need to not only include the props component we know there is a heading preceding the component so we can remove that if that\\u2019s the case.\"), mdx(\"p\", null, \"We can even be extra cautious here and check to make sure it\\u2019s a heading preceding and not some other content. You can also throw console statements here or inject a greppable string to help identify and fix outlying cases.\"), mdx(\"h3\", {\n    \"id\": \"inserting-frontmatter\"\n  }, \"Inserting Frontmatter\"), mdx(\"p\", null, \"Now you might be asking what is the syntax for frontmatter? You can view the AST Explorer to easily find this out by writing out some example code.\"), mdx(\"h2\", {\n    \"id\": \"conclusion\"\n  }, \"Conclusion\"));\n}\n;\nMDXContent.isMDXComponent = true;","excerpt":"If you've never heard of a codemod, it basically means taking a portion of code and changing its contents, usually by way of  AST…","fields":{"readingTime":{"text":"3 min read"},"slug":"/writing-codemods-for-mdx/"},"frontmatter":{"date":"07/26/2021","summary":"Codebases evolve and documentation inevitably changes. In this post, we look at using a simple Node script to rewrite docs and example code from Storybooks into a custom format.","tags":["javascript","documentation","jsdoc"],"title":"Codemods for MDX","image":null}},"previous":null,"next":null},"pageContext":{"id":"30c0b0f2-94c3-5169-8081-d1bd958c28c5"}},
    "staticQueryHashes": ["3764592887"]}