-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
As developers of tools built on PostCSS (like Stylelint), we often need to perform complex transformations on the AST. A key challenge arises in "generating fixes" scenarios where multiple independent rules might attempt to modify the same node.
Currently, to prevent conflicting writes, we generate only a single fix even if more than one rule targets the same node. This is suboptimal because many of these fixes might not actually conflict. A more powerful approach would be to "try" a fix, analyze its result, and then potentially "undo" or "revert" it if they overlap. (See stylelint/stylelint#8639 (comment))
A potential solution could be the addition of an API in PostCSS for reverting a node to a previous state. This could take several forms, some ideas include:
Snapshot/Revert mechanism: An explicit API to save and restore a node's state.
const snapshot = node.saveState();
// ... perform transformations on 'node' ...
// If we decide the transformation was incorrect:
node.revertTo(snapshot);
Safe cloning for reversal: One idea, discussed in the context of a Stylelint issue, is to clone a node before mutation and replace the mutated node with the clone to achieve a rollback.
const nodeClone = node.clone();
// ... perform transformations on 'node' ...
// To revert:
node.replaceWith(nodeClone);
However, it's currently unclear if this is a guaranteed "no-op" that is free of side effects (e.g., incorrect handling of parent pointers, raws information, or other internal state). Formalizing this pattern and ensuring its safety would be a viable solution.
A Transactional API: A higher-level API that handles the state management automatically (Like CSTTransformer in Python's LibCST).
const transaction = postcss.transaction(node);
if (isConflict) {
transaction.rollback();
} else {
transaction.commit(); // (or this is the default)
}