Conversation
This allows plugins to define what type of tree they can process in their transformer. It does not prevent misuse of those plugins (such as a rehype plugin and then a remark plugin). Nor does it handle parser or compiler plugins.
This allows plugins to define what type of tree they yield in their transformer. It does not prevent misuse of those plugins (such as a rehype plugin and then a remark plugin). Nor does it handle parser or compiler plugins.
|
/cc @remcohaszing |
There was a problem hiding this comment.
🤔 I like the idea of checking input and output AST types. 👍
In an ideal world, unified could do chained type checking, ensuring the output of a transform aligns with the input of the next transform.
parser and compiler plugins will always be a bit funky since their order is independent of transformers, but checking just the transformers could add value. 👍
This seems to be a bit different from what is described above though.
It allows Plugins to set a generic for their input and output, but this doesn't appear to be checked by unified to ensure the unified.use chain is valid?
Is this intended? (from your description it appear so?) If so, could you expand a bit on the value of adding the generics if they are not checked by unified.use?
Correct.
So that plugins can start defining what input/output they receive/yield.
A future idea I have:
Perhaps this could be includes in this PR. The last step is checking whether the Though, most people will probably chain? |
Follow up question on this added at syntax-tree/unist-util-visit-parents#10 (comment)
A fair point.
That's what I was thinking as well
Each of these |
|
Working on it! |
This comment has been minimized.
This comment has been minimized.
|
I’ve implemented parsers, compilers, etc for plugins. Now they:
I have not implemented errors of some sort when misconfiguring plugins.
I’m quite okay with not throwing on |
ChristianMurphy
left a comment
There was a problem hiding this comment.
It is fine to only define transform plugins on a processor
I'm not sure I follow, there is a CurrentTree which I assume is the current tree, as output the most recent plugin?
We can assert that it should match the Input of the next Plugin?
several parser plugins / several compiler plugins could be used, overwriting what came before
This impacts parsers and compilers, but transformers should still be fine?
code is already used a lot in the wild
It is, but these errors would be things which never worked
the complexity of it all
Most of the complexity seems to come from conditionals to infer, would matching the generics add a lot more complexity?
| type UsePlugin< | ||
| ParseTree extends Node, | ||
| CurrentTree extends Node, | ||
| CompileTree extends Node, | ||
| CompileResult, | ||
| Input, | ||
| Output | ||
| > = Output extends Node | ||
| ? Input extends string | ||
| ? // If `Input` is `string` and `Output` is `Node`, then this plugin | ||
| // defines a parser, so set `ParseTree`. | ||
| // This also assumes that this is the first plugin (so no current tree is | ||
| // or compile tree is defined yet), so set those too. | ||
| Processor<Output, Output, Output, CompileResult> | ||
| : Input extends Node | ||
| ? // If `Input` is `Node` and `Output` is `Node`, then this plugin defines a | ||
| // transformer, its output defines the input of the next, so set | ||
| // `CurrentTree`. | ||
| Processor<ParseTree, Output, CompileTree, CompileResult> | ||
| : // Else, `Input` is something else and `Output` is `Node`: | ||
| never | ||
| : Input extends Node | ||
| ? // If `Input` is `Node` and `Output` is not a `Node`, then this plugin | ||
| // defines a compiler, so set `CompileTree` and `CompileResult` | ||
| Processor<ParseTree, CurrentTree, Input, Output> | ||
| : // Else, `Input` is not a `Node` and `Output` is not a `Node`. | ||
| // Maybe it’s untyped, or the plugin throws an error (`never`), so lets | ||
| // just keep it as it was. | ||
| Processor<ParseTree, CurrentTree, CompileTree, CompileResult> |
There was a problem hiding this comment.
interesting use of inference to extract generics.
Is this approach used to overcome quirks in JSDoc generics?
Are there other benefits?
There was a problem hiding this comment.
How else could it be done?
There was a problem hiding this comment.
Would Plugin<Input, Output = Input> work?
Letting TS infer when a transformer is provided, otherwise pass through the input?
There was a problem hiding this comment.
that’s done in:
export type Plugin<
PluginParameters extends any[] = any[],
Input = Node,
Output = Input
> = (And the use overloads:
use<
PluginParameters extends any[] = any[],
Input = Specific<Node, CurrentTree>,
Output = Input
>…but this conditional makes a processor, based on how one is currently configured, and applying those Input / Output from a plugin
| export type Pluggable<PluginParameters extends any[] = any[]> = | ||
| | PluginTuple<PluginParameters> | ||
| | Plugin<PluginParameters> | ||
| | PluginTuple<PluginParameters, any, any> | ||
| | Plugin<PluginParameters, any, any> |
There was a problem hiding this comment.
would it make sense/add value to carry the generics through this type as well, rather then anys?
We could, but existing plugins can be untyped, not typed with input/output, or implicit. I think it’ll cause way to many errors. I’ll check again but what I tried yesterday resulted in 100s of errors in this code base
Wrong code never worked (rehype plugin before remark plugin without rehype-remark), but I’m not worried about that. |
* Clean `VFileWithOutput` * Add generics to `Parser`, `Compiler` * Smarter defaults for `ParserTree`, `CurrentTree`, `CompilerTree` * Be smarter about parse/compile trees if only parse/compile plugins are used * Add smarter type of `this` in parse/transform/compile plugins. * Add docs for type parameters
|
Made the types smarter. |
Co-authored-by: Christian Murphy <christian.murphy.42@gmail.com>
Initial checklist
Description of changes
This allows plugins to define what type of tree they receive and yield in their transformer.
It does not prevent misuse of those plugins (such as a rehype plugin and then a remark plugin). Nor does it handle parser or compiler plugins.