It's tempting to think this way, but it's a performance/complexity nightmare. If
everything is a plugin, then you need ways for different parsers to talk to each other to deal with nested syntax, plus ways for different syntactic transformers to correctly handle nesting of certain things.
For example, if you desired to implement a plugin for "thin arrows", and a plugin for JSX, how would you parse this?
const x = } />
You'd have to have the JSX parser know to invoke the thin arrow parser, then the thin arrow parser has to know how to invoke the JSX parser, then when you emit, you have to do the whole dance over again.
If you're willing to take some trade-offs in the parsing phase, it's OK. But the emit is where you get killed - either every plugin has to be written generically and correctly enough to deal with any arbitrary nesting of syntaxes (including the cases where the semantics of nesting aren't even clear, like where a 'fat' arrow here would capture 'this' from), or you do one tree pass per transformer, which gets very expensive.
There's a reason you don't usually see architectures like that live very long.