Rule
prefer-structured-clone (eslint-factory/src/rules/prefer-structured-clone.ts) - first review of this rule; shipped since the last refinement pass and not yet covered by any prior issue.
Summary
The rule flags JSON.parse(JSON.stringify(x)) and suggests replacing it with structuredClone(x). This is presented as a strict improvement, but the two are not semantically equivalent when x can contain a function-valued property: JSON.stringify silently drops function values, while structuredClone throws a synchronous DataCloneError the moment it encounters one. The rule offers the suggestion unconditionally, with no static check for this case.
Grounded live example (not hypothetical)
actions/setup/js/safe_outputs_tools_loader.cjs around line 244:
toolToRegister = JSON.parse(JSON.stringify(tool));
...
if (tool.handler) {
toolToRegister.handler = tool.handler;
}
By the time this line runs, tool.handler has already been set to a live function by attachHandlers() (same file, lines ~130-211). The surrounding code deep-copies with JSON.parse(JSON.stringify(tool)) specifically because that silently strips handler, then re-attaches the original function afterward on purpose.
This exact call expression matches the rule's flagged pattern and receives the structuredClone(tool) suggestion. Applying that suggestion would replace working code with code that throws DataCloneError synchronously on every call.
By contrast, actions/setup/js/generate_safe_outputs_tools.cjs around line 280 (enhancedTool = JSON.parse(JSON.stringify(tool))) is a genuinely safe application of the suggestion: there, tool comes from a static JSON file on disk, so it can never contain a function. Both sites match the rule identically today, but only one is safe to rewrite.
Why this matters
hasSuggestions: true means editors/agents can apply this suggestion directly; it looks like a safe mechanical improvement but silently changes drop-on-serialize semantics into throw-on-clone semantics.
- The rule's docs treat 'drops functions' purely as a JSON.stringify shortcoming that structuredClone fixes, without acknowledging that some code intentionally relies on that drop-and-reattach idiom.
Suggested fix (pick one or combine)
- Keep the diagnostic report but drop the
suggest array (report-only, no autofix), since 'is this object JSON-safe' is not always statically decidable.
- Add a conservative static guard that skips the suggestion when the cloned expression is an Identifier that has a property assigned a function value (FunctionExpression/ArrowFunctionExpression) anywhere before the clone site in the same scope - matching the safe_outputs_tools_loader.cjs shape.
- At minimum, add a regression test reproducing this shape and update rule docs / README to call out the function-property hazard explicitly.
Acceptance criteria
Scope: eslint-factory/** only (rule logic + tests + docs). No changes to actions/setup/js/** app code are in scope for this issue.
Generated by 🤖 ESLint Refiner · agent · 231.1 AIC · ⌖ 43.7 AIC · ⊞ 4.9K · ◷
Rule
prefer-structured-clone(eslint-factory/src/rules/prefer-structured-clone.ts) - first review of this rule; shipped since the last refinement pass and not yet covered by any prior issue.Summary
The rule flags
JSON.parse(JSON.stringify(x))and suggests replacing it withstructuredClone(x). This is presented as a strict improvement, but the two are not semantically equivalent whenxcan contain a function-valued property:JSON.stringifysilently drops function values, whilestructuredClonethrows a synchronous DataCloneError the moment it encounters one. The rule offers the suggestion unconditionally, with no static check for this case.Grounded live example (not hypothetical)
actions/setup/js/safe_outputs_tools_loader.cjs around line 244:
By the time this line runs,
tool.handlerhas already been set to a live function byattachHandlers()(same file, lines ~130-211). The surrounding code deep-copies with JSON.parse(JSON.stringify(tool)) specifically because that silently stripshandler, then re-attaches the original function afterward on purpose.This exact call expression matches the rule's flagged pattern and receives the
structuredClone(tool)suggestion. Applying that suggestion would replace working code with code that throws DataCloneError synchronously on every call.By contrast, actions/setup/js/generate_safe_outputs_tools.cjs around line 280 (
enhancedTool = JSON.parse(JSON.stringify(tool))) is a genuinely safe application of the suggestion: there,toolcomes from a static JSON file on disk, so it can never contain a function. Both sites match the rule identically today, but only one is safe to rewrite.Why this matters
hasSuggestions: truemeans editors/agents can apply this suggestion directly; it looks like a safe mechanical improvement but silently changes drop-on-serialize semantics into throw-on-clone semantics.Suggested fix (pick one or combine)
suggestarray (report-only, no autofix), since 'is this object JSON-safe' is not always statically decidable.Acceptance criteria
Scope: eslint-factory/** only (rule logic + tests + docs). No changes to actions/setup/js/** app code are in scope for this issue.