Tom MacWright

2025@macwright.com

An ast-grep rule to ban bad HTML nesting in React

Today I fixed a bug in Val Town in which we had some bad nesting. This happens if you have something like this:

function Component() {
  return <a href="https://google.com">
    Google
    <a href="https://yahoo.com/">Yahoo</a>
  </a>;
}

This is not allowed in HTML and React will produce a warning when it happens. It's pretty easy to catch in a one-off case, but in a large codebase, this kind of bug will sneak in.

We didn't have any way to automatically flag this kind of bug. I've been using ast-grep to build custom rules against bugs like this. The learning curve is steep, and the documentation could be a lot better, but the power of ast-grep is significant: it's both extremely flexible and lightning-fast, so you can run your ast-grep rules in git hooks without ever noticing a slowdown.

I cooked up a rule to catch this violation:

id: no-nested-links
language: tsx
severity: error
rule:
  pattern: <a $$$>$$$A</a>
  has:
    pattern: <a $$$>$$$</a>
    stopBy: end

And can be pretty confident that this kind of bug won't crop up again.

In the most naive version of course! If you were to have a component that rendered an <a> element and included {children}, then you could easily trigger this bug. But at least the most common, simple case is covered.