How can I configure ESLint to retry fixes without causing duplicate writes?
0 reputation · 14 Jan 2021, 16:58 UTC
0 reputation · 14 Jan 2021, 16:58 UTC
When using ESLint to automatically apply fixes, a custom rule that transforms source code may be invoked multiple times during a retry loop. Each invocation writes the same transformed content back to the file, resulting in duplicate write operations that clutter the version‑control history and can cause unnecessary rebuilds. The desired outcome is for the fix process to be idempotent: after the first successful transformation, subsequent runs should detect that no further changes are needed and skip writing to disk. The rule must remain compatible with ESLint’s built‑in fix mechanism and should not depend on external caching tools. It is unclear whether ESLint already compares the original and fixed output before writing, or if the rule itself must perform that comparison.
Specific questions:
35275 reputation · 15 Jan 2021, 03:51 UTC
ESLint's internal fix mechanism does not provide a configuration option to skip writes based on a content comparison of the final output versus the original source. When you run eslint --fix, the engine applies all suggested fixes and writes the resulting buffer to disk. If a custom rule issues a fix that results in the exact same text as the current source, ESLint may still trigger a write operation depending on the environment and the specific way the fixer is invoked.
By design, ESLint's --fix is a single-pass operation. It does not natively "retry" until convergence; rather, it applies fixes and exits. If you are experiencing duplicate writes, it is likely because you are wrapping the ESLint CLI in an external loop or using a tool that triggers multiple passes. In these scenarios, if a rule is not idempotent—meaning it suggests a fix even when the code already matches the desired state—ESLint will continue to write to the file on every pass.
To prevent redundant writes, the logic for detecting the violation must be strictly decoupled from the logic for applying the fix. A rule should only return a fix function if the current source code actually requires a change.
Follow this pattern within your custom rule implementation:
sourceCode.getText() method to check if the code already conforms to the desired state.fix object in the report call if the verification step confirms a discrepancy.// Example of an idempotent check
context.report({
node,
message: 'Incorrect formatting',
fix(fixer) {
const currentText = sourceCode.getText(node);
const desiredText = transform(currentText);
// Only issue the fix if the transformation actually changes the text
if (currentText === desiredText) {
return null;
}
return fixer.replaceText(node, desiredText);
}
});
To verify if your rules are causing redundant writes, use a version control system to track changes between passes:
eslint --fix .git diffeslint --fix . a second time. If git diff still shows modifications or if the file's "last modified" timestamp updates without content changes, the rule is not idempotent.Missing Diagnostic Detail: Are you using a custom wrapper script to loop the --fix command, or is this behavior occurring within a single execution of the ESLint CLI?
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 14 Jan 2021, 21:36 UTC
When you run eslint --fix ESLint already writes a file only if the output differs from the current content. However, if you repeatedly invoke the CLI (for example, in a retry loop), the same file may be rewritten on each pass. The built‑in --cache option records a checksum and the last‑modified time for every file. On subsequent runs, ESLint checks the cache and skips any file that hasn’t changed, so no write occurs.
eslint . --fix --cache --cache-location .eslintcache
After changing a rule or the configuration, delete the cache (.eslintcache) to force a full re‑analysis.