| 1 | import { defineRule, type ESTree } from "@oxlint/plugins"; |
| 2 | |
| 3 | const GLOBAL_OBJECTS = new Set(["globalThis", "window", "self"]); |
| 4 | |
| 5 | function isResizeObserverConstructor(node: ESTree.Node): boolean { |
| 6 | if (node.type === "Identifier") return node.name === "ResizeObserver"; |
| 7 | if (node.type !== "MemberExpression" || node.object.type !== "Identifier") return false; |
| 8 | if (!GLOBAL_OBJECTS.has(node.object.name)) return false; |
| 9 | const { property } = node; |
| 10 | if (!node.computed && property.type === "Identifier") return property.name === "ResizeObserver"; |
| 11 | return property.type === "Literal" && property.value === "ResizeObserver"; |
| 12 | } |
| 13 | |
| 14 | export default defineRule({ |
| 15 | meta: { |
| 16 | type: "problem", |
| 17 | docs: { |
| 18 | description: "Disallow constructing ResizeObserver directly in web code; use observeResize.", |
| 19 | }, |
| 20 | }, |
| 21 | create(context) { |
| 22 | return { |
| 23 | NewExpression(node) { |
| 24 | if (!isResizeObserverConstructor(node.callee)) return; |
| 25 | context.report({ |
| 26 | node: node.callee, |
| 27 | message: |
| 28 | "Use observeResize from ~/lib/observeResize. React commits state set in a raw ResizeObserver callback after the paint, so layout derived from the observed size lands one frame late.", |
| 29 | }); |
| 30 | }, |
| 31 | }; |
| 32 | }, |
| 33 | }); |