<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Daniele Tortora</title>
    <description>The latest articles on DEV Community by Daniele Tortora (@floroz).</description>
    <link>https://dev.to/floroz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F146481%2F1d3beaba-5330-43ff-b0c0-0ffb1bd1fafa.JPG</url>
      <title>DEV Community: Daniele Tortora</title>
      <link>https://dev.to/floroz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/floroz"/>
    <language>en</language>
    <item>
      <title>How to create a custom lint rule for Markdown and MDX using remark and ESLint</title>
      <dc:creator>Daniele Tortora</dc:creator>
      <pubDate>Wed, 07 Apr 2021 08:53:44 +0000</pubDate>
      <link>https://dev.to/floroz/how-to-create-a-custom-lint-rule-for-markdown-and-mdx-using-remark-and-eslint-2jim</link>
      <guid>https://dev.to/floroz/how-to-create-a-custom-lint-rule-for-markdown-and-mdx-using-remark-and-eslint-2jim</guid>
      <description>&lt;p&gt;Everyone loves Markdown. It's an exceptional tool to create text documents, blog posts, documentation articles, and it allows us to do so without having to worry about formatting, font styles, or having to set up HTML boilerplate.&lt;/p&gt;

&lt;p&gt;There is a myriad of solutions out there to convert our Markdown into HTML pages or to scaffold entire websites out of our documents.&lt;/p&gt;

&lt;p&gt;In the last years, modern web development architectures based on client-side JavaScript, reusable APIs and prebuilt Markup (&lt;a href="https://jamstack.org/what-is-jamstack/"&gt;JAMstack&lt;/a&gt;), and new web frameworks (&lt;a href="https://github.com/gatsbyjs/gatsby"&gt;Gatsby&lt;/a&gt;, &lt;a href="https://github.com/gridsome/gridsome"&gt;Gridsome&lt;/a&gt; or &lt;a href="https://github.com/vercel/next.js"&gt;Next.js&lt;/a&gt;), have gained increased popularity amongst developers, and even allowed us to start using JSX within our Markdown (&lt;a href="https://mdxjs.com/"&gt;MDX&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;As these solutions scale, and more content writers and developers start contributing to these documents, teams are encouraged to adopt linting programs to shape best practices around markdown and MDX, and enforcing styles and conventions.&lt;/p&gt;

&lt;p&gt;In this article, we'll go through how to setup your own custom lint rule for a JavaScript project using Markdown and MDX, starting from scratch.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Lets' get started!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Set up the project&lt;/li&gt;
&lt;li&gt;Set up remark&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;no-invalid-gif&lt;/code&gt; rule&lt;/li&gt;
&lt;li&gt;Create the custom rule&lt;/li&gt;
&lt;li&gt;Rule arguments&lt;/li&gt;
&lt;li&gt;Rule implementation&lt;/li&gt;
&lt;li&gt;Import the rule in your remark config&lt;/li&gt;
&lt;li&gt;Apply the rule on the Markdown file&lt;/li&gt;
&lt;li&gt;Markdown to MDX&lt;/li&gt;
&lt;li&gt;ESlint MDX and Remark&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fork this &lt;a href="https://github.com/floroz/blog-posts/tree/main/how-to-create-custom-lint-rule-markdown-mdx"&gt;repository&lt;/a&gt; with the complete tutorial, if you don't want to start from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up the project
&lt;/h2&gt;

&lt;p&gt;Create a new folder and enter it from your terminal. For this example I will be using Unix commands (macOS and Linux compatible).&lt;br&gt;
Now we can generate our &lt;code&gt;package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="nb"&gt;mkdir &lt;/span&gt;my-custom-rule

 &lt;span class="nb"&gt;cd &lt;/span&gt;my-custom-rule

 npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can start installing our dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; npm &lt;span class="nb"&gt;install &lt;/span&gt;remark-lint remark-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/remarkjs/remark-lint"&gt;&lt;code&gt;remark-lint&lt;/code&gt;&lt;/a&gt;: Core lint plugin&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/remarkjs/remark/tree/main/packages/remark-cli"&gt;&lt;code&gt;remark-cli&lt;/code&gt;&lt;/a&gt;: Command-line interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will also need some utilities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; npm &lt;span class="nb"&gt;install &lt;/span&gt;unified-lint-rule unist-util-generated unist-util-visit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These will help us creating and managing our custom rules.&lt;/p&gt;

&lt;p&gt;Back to Top&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up remark
&lt;/h2&gt;

&lt;p&gt;With everything installed, we can now create a &lt;code&gt;.remarkrc.js&lt;/code&gt; that will contain the plugins we’ll use.&lt;/p&gt;

&lt;p&gt;For more info on configuration, see &lt;a href="https://github.com/remarkjs/remark-lint#configuring-remark-lint"&gt;Configuring &lt;code&gt;remark-lint&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="nb"&gt;touch&lt;/span&gt; .remarkrc.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// .remarkrc.js&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in our &lt;code&gt;package.json&lt;/code&gt;, let's add the following script, which will process all the markdown file within our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"remark ."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's create a &lt;code&gt;doc.md&lt;/code&gt;, the markdown file we want to lint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="nb"&gt;touch &lt;/span&gt;doc.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...and copy/paste the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Best pets! &amp;lt;3&lt;/span&gt;

Some funny images of our favorite pets

&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;a funny cat&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;funny-cat.gif&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;a lovely dog&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;lovely-dog.png&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, we have a working &lt;code&gt;remark&lt;/code&gt; configuration and a markdown file in the project.&lt;/p&gt;

&lt;p&gt;If we run &lt;code&gt;npm run lint&lt;/code&gt; we should expect to see in our terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; doc.md: no issues found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All good, the file has been processed, and because we haven't specified any plugins nor lint rule, no issues are found.&lt;/p&gt;

&lt;p&gt;Back to Top&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;no-invalid-gif&lt;/code&gt; rule
&lt;/h2&gt;

&lt;p&gt;Let’s imagine we want to write a rule that checks whether a &lt;code&gt;.gif&lt;/code&gt; file is used as an image.&lt;/p&gt;

&lt;p&gt;Given the content of our &lt;code&gt;doc.md&lt;/code&gt; file declared above, we would expect an &lt;em&gt;error&lt;/em&gt; or &lt;em&gt;warning&lt;/em&gt; pointing to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;a funny cat&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;funny-cat.gif&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the file extension &lt;code&gt;.gif&lt;/code&gt; in the image tag violates our rule.&lt;/p&gt;

&lt;p&gt;Back to Top&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the custom rule
&lt;/h2&gt;

&lt;p&gt;Let's create a new folder &lt;code&gt;rules&lt;/code&gt; under the root directory, where we will place all of our custom rules, and create a new file in it named &lt;code&gt;no-gif-allowed.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="nb"&gt;mkdir &lt;/span&gt;rules
 &lt;span class="nb"&gt;cd &lt;/span&gt;rules
 &lt;span class="nb"&gt;touch &lt;/span&gt;no-gif-allowed.js
 &lt;span class="nb"&gt;cd&lt;/span&gt; .. &lt;span class="c"&gt;# return to project root&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: the name of folders and files, and where to place them within your project, is up to you.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;./rules/no-gif-allowed.js&lt;/code&gt;, let's import &lt;code&gt;unified-lint-rule&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We then export the result of calling &lt;code&gt;rule&lt;/code&gt; by providing the &lt;em&gt;namespace and rule name&lt;/em&gt; (&lt;code&gt;remark-lint:no-gif-allowed&lt;/code&gt;) as the first argument, and our implementation of the rule (&lt;code&gt;noGifAllowed&lt;/code&gt;) as the second argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// rules/no-gif-allowed.js&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;rule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unified-lint-rule&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;noGifAllowed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// rule implementation&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remark-lint:no-gif-allowed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;noGifAllowed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's say you want all your custom rules to be defined as part of your project namespace. If your project was named &lt;code&gt;my-project&lt;/code&gt;, then you can export your rule as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-project-name:no-gif-allowed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;noGifAllowed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// or&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-npm-published-package:no-gif-allowed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;noGifAllowed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can help you when wanting to create a group of rules under the same &lt;em&gt;namespace&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Back to Top&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule arguments
&lt;/h2&gt;

&lt;p&gt;Your rule function will receive three arguments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;noGifAllowed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tree&lt;/code&gt; (&lt;em&gt;required&lt;/em&gt;): &lt;a href="https://github.com/syntax-tree/mdast"&gt;mdast&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;file&lt;/code&gt; (&lt;em&gt;required&lt;/em&gt;): &lt;a href="https://github.com/vfile/vfile"&gt;virtual file&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;options&lt;/code&gt; (&lt;em&gt;optional&lt;/em&gt;): additional information passed to the rule by users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Back to Top&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule implementation
&lt;/h2&gt;

&lt;p&gt;Because we will be inspecting &lt;a href="https://github.com/syntax-tree/mdast"&gt;mdast&lt;/a&gt;, which is a markdown abstract syntax tree built upon &lt;a href="https://github.com/syntax-tree/unist"&gt;unist&lt;/a&gt;, we can take advantage of the many existing &lt;a href="https://github.com/syntax-tree/unist#utilities"&gt;unist utilities&lt;/a&gt; to inspect our tree’s nodes.&lt;/p&gt;

&lt;p&gt;For this example, we will use &lt;a href="https://github.com/syntax-tree/unist-util-visit"&gt;&lt;code&gt;unist-util-visit&lt;/code&gt;&lt;/a&gt; to recursively inspect all the image nodes, and &lt;a href="https://github.com/syntax-tree/unist-util-generated"&gt;&lt;code&gt;unist-util-generated&lt;/code&gt;&lt;/a&gt; to ensure we are not inspecting nodes that we have generated ourselves and do not belong to the &lt;code&gt;doc.md&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unified-lint-rule&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unist-visit-util&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unist-util-generated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;isValidNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Here we check whether the given node violates our rule.&lt;/span&gt;
  &lt;span class="c1"&gt;// Implementation details are not relevant to the scope of this example.&lt;/span&gt;
  &lt;span class="c1"&gt;// This is an overly simplified solution for demonstration purposes&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.gif&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;noGifAllowed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;visitor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;visitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;generated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// This is an extremely simplified example of how to structure&lt;/span&gt;
      &lt;span class="c1"&gt;// the logic to check whether a node violates your rule.&lt;/span&gt;
      &lt;span class="c1"&gt;// You have complete freedom over how to visit/inspect the tree,&lt;/span&gt;
      &lt;span class="c1"&gt;//and on how to implement the validation logic for your node.&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isValidNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Remember to provide the node as second argument to the message,&lt;/span&gt;
        &lt;span class="c1"&gt;// in order to obtain the position and column where the violation occurred.&lt;/span&gt;
        &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="s2"&gt;`Invalid image file extentions. Please do not use gifs`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;node&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remark-lint:no-gif-allowed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;noGifAllowed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Back to Top&lt;/p&gt;

&lt;h2&gt;
  
  
  Import the rule in your remark config
&lt;/h2&gt;

&lt;p&gt;Now that our custom rule is defined, and ready to be used, we need to add it to our &lt;code&gt;remark&lt;/code&gt; configuration.&lt;/p&gt;

&lt;p&gt;You can do that by importing your rule and adding it in &lt;code&gt;plugins&lt;/code&gt; array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// .remarkrc.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;noGifAllowed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./rules/no-gif-allowed.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;noGifAllowed&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Back to Top&lt;/p&gt;

&lt;h2&gt;
  
  
  Apply the rule on the Markdown file
&lt;/h2&gt;

&lt;p&gt;If you run &lt;code&gt;npm lint&lt;/code&gt;, you should see the following message in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; 5:1-5:30  warning  Invalid image file extentions. Please &lt;span class="k"&gt;do &lt;/span&gt;not use gifs  no-gif-allowed  remark-lint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rule works, congratulations!&lt;/p&gt;

&lt;p&gt;Back to Top&lt;/p&gt;

&lt;h2&gt;
  
  
   Markdown to MDX
&lt;/h2&gt;

&lt;p&gt;Hold on, we are now told that we need to start supporting into our project also MDX files, and that our rules must apply to those as well.&lt;/p&gt;

&lt;p&gt;A new file is created in the project, &lt;code&gt;doc.mdx&lt;/code&gt;,to start using our new &lt;code&gt;ParagraphComponent&lt;/code&gt; inside MDX.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Best pets! &amp;lt;3&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ParagraphComponent&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;"I am a new paragraph"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

Some funny images of our favourite pets

&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;a funny cat&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;funny-cat.gif&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;a lovely dog&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;lovely-dog.png&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fine, we now run our &lt;code&gt;npm run lint&lt;/code&gt; again and check the terminal output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;doc.md
  5:1-5:30  warning  Invalid image file extentions. Please &lt;span class="k"&gt;do &lt;/span&gt;not use gifs  no-gif-allowed  remark-lint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ouch! it seems our &lt;code&gt;.mdx&lt;/code&gt; file is not seen or parsed by &lt;code&gt;remark&lt;/code&gt; and the rule is not applied! Lets' take care of that.&lt;/p&gt;

&lt;p&gt;Back to Top&lt;/p&gt;

&lt;h2&gt;
  
  
  ESlint MDX and Remark
&lt;/h2&gt;

&lt;p&gt;In order to correctly parse and lint MDX files, we will need a parser. A great solution for this is &lt;code&gt;eslint-mdx&lt;/code&gt;, so let's install it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  npm &lt;span class="nb"&gt;install &lt;/span&gt;eslint eslint-plugin-mdx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/eslint/eslint"&gt;ESLint&lt;/a&gt;: the most popular tool for linting JavaScript code.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mdx-js/eslint-mdx"&gt;ESLint MDX&lt;/a&gt;: an ESLint plugin/parser for MDX files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will need to create a ESLint config to pass the settings for MDX and configure the plugin.&lt;/p&gt;

&lt;p&gt;Let's create a &lt;code&gt;.eslintrc.js&lt;/code&gt; in the root of our project,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="nb"&gt;touch&lt;/span&gt; .eslintrc.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;extends the &lt;code&gt;eslint-plugin-mdx&lt;/code&gt; settings, and enable the &lt;code&gt;mdx/remark&lt;/code&gt; rule.&lt;/p&gt;

&lt;p&gt;ESLint will use the MDX plugin to parse and process our markdown/mdx files, and will also pull in any &lt;code&gt;remark&lt;/code&gt; configuration we have declared in our project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugin:mdx/recommended&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;parserOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;ecmaVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2015&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Integration with remark-lint plugins,&lt;/span&gt;
    &lt;span class="c1"&gt;// it will read remark's configuration automatically via .remarkrc.js&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mdx/remark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, now it's time to update our &lt;code&gt;package.json&lt;/code&gt; with a new &lt;code&gt;lint&lt;/code&gt; script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eslint . --ext md,mdx"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are configuring ESLint to parse and process all the files in our project with either a &lt;code&gt;.md&lt;/code&gt; or &lt;code&gt;.mdx&lt;/code&gt; extension.&lt;/p&gt;

&lt;p&gt;If we now run &lt;code&gt;npm run lint&lt;/code&gt; we should see in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; eslint &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--ext&lt;/span&gt; md,mdx

doc.md
  5:1  warning  Invalid image file extentions. Please &lt;span class="k"&gt;do &lt;/span&gt;not use gifs  remark-lint-no-gif-allowed

doc.mdx
  7:1  warning  Invalid image file extentions. Please &lt;span class="k"&gt;do &lt;/span&gt;not use gifs  remark-lint-no-gif-allowed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Congratulation!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your custom rule has been correctly applied both to Markdown and MDX!&lt;/p&gt;

&lt;p&gt;Back to Top&lt;/p&gt;

</description>
      <category>markdown</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>writing</category>
    </item>
  </channel>
</rss>
