eslint-plugin-react-web-api
Advanced tools
Comparing version
@@ -1,33 +0,10 @@ | ||
'use strict'; | ||
import { getDocsUrl, DEFAULT_ESLINT_REACT_SETTINGS } from '@eslint-react/shared'; | ||
import * as AST from '@eslint-react/ast'; | ||
import * as ER4 from '@eslint-react/core'; | ||
import { unit, or } from '@eslint-react/eff'; | ||
import * as VAR from '@eslint-react/var'; | ||
import { ESLintUtils, AST_NODE_TYPES } from '@typescript-eslint/utils'; | ||
import { match, isMatching, P } from 'ts-pattern'; | ||
import { AST_NODE_TYPES as AST_NODE_TYPES$1 } from '@typescript-eslint/types'; | ||
var shared = require('@eslint-react/shared'); | ||
var AST = require('@eslint-react/ast'); | ||
var ER4 = require('@eslint-react/core'); | ||
var eff = require('@eslint-react/eff'); | ||
var VAR = require('@eslint-react/var'); | ||
var utils = require('@typescript-eslint/utils'); | ||
var tsPattern = require('ts-pattern'); | ||
function _interopNamespace(e) { | ||
if (e && e.__esModule) return e; | ||
var n = Object.create(null); | ||
if (e) { | ||
Object.keys(e).forEach(function (k) { | ||
if (k !== 'default') { | ||
var d = Object.getOwnPropertyDescriptor(e, k); | ||
Object.defineProperty(n, k, d.get ? d : { | ||
enumerable: true, | ||
get: function () { return e[k]; } | ||
}); | ||
} | ||
}); | ||
} | ||
n.default = e; | ||
return Object.freeze(n); | ||
} | ||
var AST__namespace = /*#__PURE__*/_interopNamespace(AST); | ||
var ER4__namespace = /*#__PURE__*/_interopNamespace(ER4); | ||
var VAR__namespace = /*#__PURE__*/_interopNamespace(VAR); | ||
var __defProp = Object.defineProperty; | ||
@@ -54,3 +31,3 @@ var __export = (target, all) => { | ||
var settings = { | ||
"react-x": shared.DEFAULT_ESLINT_REACT_SETTINGS | ||
"react-x": DEFAULT_ESLINT_REACT_SETTINGS | ||
}; | ||
@@ -60,7 +37,25 @@ | ||
var name2 = "eslint-plugin-react-web-api"; | ||
var version = "1.52.3-next.6"; | ||
var createRule = utils.ESLintUtils.RuleCreator(shared.getDocsUrl("web-api")); | ||
var version = "2.0.0-beta.0"; | ||
var createRule = ESLintUtils.RuleCreator(getDocsUrl("web-api")); | ||
function getPhaseKindOfFunction(node) { | ||
return tsPattern.match(node).when(ER4__namespace.isFunctionOfUseEffectSetup, () => "setup").when(ER4__namespace.isFunctionOfUseEffectCleanup, () => "cleanup").when(ER4__namespace.isFunctionOfComponentDidMount, () => "mount").when(ER4__namespace.isFunctionOfComponentWillUnmount, () => "unmount").otherwise(() => null); | ||
return match(node).when(isFunctionOfUseEffectSetup, () => "setup").when(isFunctionOfUseEffectCleanup, () => "cleanup").when(isFunctionOfComponentDidMount, () => "mount").when(isFunctionOfComponentWillUnmount, () => "unmount").otherwise(() => null); | ||
} | ||
function isFunctionOfUseEffectSetup(node) { | ||
if (node == null) return false; | ||
return node.parent?.type === AST_NODE_TYPES$1.CallExpression && node.parent.callee !== node && node.parent.callee.type === AST_NODE_TYPES$1.Identifier && node.parent.arguments.at(0) === node && ER4.isUseEffectCallLoose(node.parent); | ||
} | ||
function isFunctionOfUseEffectCleanup(node) { | ||
if (node == null) return false; | ||
const pReturn = AST.findParentNode(node, AST.is(AST_NODE_TYPES$1.ReturnStatement)); | ||
const pFunction = AST.findParentNode(node, AST.isFunction); | ||
const pFunctionOfReturn = AST.findParentNode(pReturn, AST.isFunction); | ||
if (pFunction !== pFunctionOfReturn) return false; | ||
return isFunctionOfUseEffectSetup(pFunction); | ||
} | ||
function isFunctionOfComponentDidMount(node) { | ||
return AST.isFunction(node) && ER4.isComponentDidMount(node.parent) && node.parent.value === node; | ||
} | ||
function isFunctionOfComponentWillUnmount(node) { | ||
return AST.isFunction(node) && ER4.isComponentWillUnmount(node.parent) && node.parent.value === node; | ||
} | ||
@@ -73,9 +68,9 @@ // src/rules/no-leaked-event-listener.ts | ||
// once: false, | ||
signal: eff.unit | ||
signal: unit | ||
}; | ||
function getCallKind(node) { | ||
switch (true) { | ||
case (node.callee.type === utils.AST_NODE_TYPES.Identifier && tsPattern.isMatching(tsPattern.P.union("addEventListener", "removeEventListener", "abort"))(node.callee.name)): | ||
case (node.callee.type === AST_NODE_TYPES.Identifier && isMatching(P.union("addEventListener", "removeEventListener", "abort"))(node.callee.name)): | ||
return node.callee.name; | ||
case (node.callee.type === utils.AST_NODE_TYPES.MemberExpression && node.callee.property.type === utils.AST_NODE_TYPES.Identifier && tsPattern.isMatching(tsPattern.P.union("addEventListener", "removeEventListener", "abort"))(node.callee.property.name)): | ||
case (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.property.type === AST_NODE_TYPES.Identifier && isMatching(P.union("addEventListener", "removeEventListener", "abort"))(node.callee.property.name)): | ||
return node.callee.property.name; | ||
@@ -90,11 +85,11 @@ default: | ||
function getSignalValueExpression(node, initialScope) { | ||
if (node == null) return eff.unit; | ||
if (node == null) return unit; | ||
switch (node.type) { | ||
case utils.AST_NODE_TYPES.Identifier: { | ||
return getSignalValueExpression(VAR__namespace.getVariableInitNode(VAR__namespace.findVariable(node, initialScope), 0), initialScope); | ||
case AST_NODE_TYPES.Identifier: { | ||
return getSignalValueExpression(VAR.getVariableInitNode(VAR.findVariable(node, initialScope), 0), initialScope); | ||
} | ||
case utils.AST_NODE_TYPES.MemberExpression: | ||
case AST_NODE_TYPES.MemberExpression: | ||
return node; | ||
default: | ||
return eff.unit; | ||
return unit; | ||
} | ||
@@ -104,10 +99,10 @@ } | ||
function findProp(properties, propName) { | ||
return VAR__namespace.findPropertyInProperties(propName, properties, initialScope); | ||
return VAR.findPropertyInProperties(propName, properties, initialScope); | ||
} | ||
function getPropValue(prop, filter = (a) => true) { | ||
if (prop?.type !== utils.AST_NODE_TYPES.Property) return eff.unit; | ||
if (prop?.type !== AST_NODE_TYPES.Property) return unit; | ||
const { value } = prop; | ||
let v = value; | ||
switch (value.type) { | ||
case utils.AST_NODE_TYPES.Literal: { | ||
case AST_NODE_TYPES.Literal: { | ||
v = value.value; | ||
@@ -117,14 +112,14 @@ break; | ||
default: { | ||
v = VAR__namespace.toStaticValue({ kind: "lazy", node: value, initialScope }).value; | ||
v = VAR.toStaticValue({ kind: "lazy", node: value, initialScope }).value; | ||
break; | ||
} | ||
} | ||
return filter(v) ? v : eff.unit; | ||
return filter(v) ? v : unit; | ||
} | ||
function getOpts(node2) { | ||
switch (node2.type) { | ||
case utils.AST_NODE_TYPES.Identifier: { | ||
const variable = VAR__namespace.findVariable(node2, initialScope); | ||
const variableNode = VAR__namespace.getVariableInitNode(variable, 0); | ||
if (variableNode?.type === utils.AST_NODE_TYPES.ObjectExpression) { | ||
case AST_NODE_TYPES.Identifier: { | ||
const variable = VAR.findVariable(node2, initialScope); | ||
const variableNode = VAR.getVariableInitNode(variable, 0); | ||
if (variableNode?.type === AST_NODE_TYPES.ObjectExpression) { | ||
return getOpts(variableNode); | ||
@@ -134,10 +129,10 @@ } | ||
} | ||
case utils.AST_NODE_TYPES.Literal: { | ||
case AST_NODE_TYPES.Literal: { | ||
return { ...defaultOptions, capture: Boolean(node2.value) }; | ||
} | ||
case utils.AST_NODE_TYPES.ObjectExpression: { | ||
case AST_NODE_TYPES.ObjectExpression: { | ||
const pCapture = findProp(node2.properties, "capture"); | ||
const vCapture = !!getPropValue(pCapture); | ||
const pSignal = findProp(node2.properties, "signal"); | ||
const vSignal = pSignal?.type === utils.AST_NODE_TYPES.Property ? getSignalValueExpression(pSignal.value, initialScope) : eff.unit; | ||
const vSignal = pSignal?.type === AST_NODE_TYPES.Property ? getSignalValueExpression(pSignal.value, initialScope) : unit; | ||
return { capture: vCapture, signal: vSignal }; | ||
@@ -183,4 +178,4 @@ } | ||
switch (true) { | ||
case (a.type === utils.AST_NODE_TYPES.MemberExpression && b.type === utils.AST_NODE_TYPES.MemberExpression): | ||
return AST__namespace.isNodeEqual(a.object, b.object); | ||
case (a.type === AST_NODE_TYPES.MemberExpression && b.type === AST_NODE_TYPES.MemberExpression): | ||
return AST.isNodeEqual(a.object, b.object); | ||
// TODO: Maybe there other cases to consider here. | ||
@@ -194,6 +189,6 @@ default: | ||
const { type: rType, callee: rCallee, capture: rCapture, listener: rListener, phase: rPhase } = rEntry; | ||
if (!ER4__namespace.isInversePhase(aPhase, rPhase)) { | ||
if (!ER4.isInversePhase(aPhase, rPhase)) { | ||
return false; | ||
} | ||
return isSameObject(aCallee, rCallee) && AST__namespace.isNodeEqual(aListener, rListener) && VAR__namespace.isNodeValueEqual(aType, rType, [ | ||
return isSameObject(aCallee, rCallee) && AST.isNodeEqual(aListener, rListener) && VAR.isNodeValueEqual(aType, rType, [ | ||
context.sourceCode.getScope(aType), | ||
@@ -205,3 +200,3 @@ context.sourceCode.getScope(rType) | ||
const listener = node.arguments.at(1); | ||
if (!AST__namespace.isFunction(listener)) { | ||
if (!AST.isFunction(listener)) { | ||
return; | ||
@@ -231,6 +226,6 @@ } | ||
} | ||
if (!ER4__namespace.ComponentPhaseRelevance.has(fKind)) { | ||
if (!ER4.ComponentPhaseRelevance.has(fKind)) { | ||
return; | ||
} | ||
tsPattern.match(getCallKind(node)).with("addEventListener", (callKind) => { | ||
match(getCallKind(node)).with("addEventListener", (callKind) => { | ||
const [type, listener, options] = node.arguments; | ||
@@ -309,5 +304,5 @@ if (type == null || listener == null) { | ||
switch (true) { | ||
case (node.callee.type === utils.AST_NODE_TYPES.Identifier && tsPattern.isMatching(tsPattern.P.union("setInterval", "clearInterval"))(node.callee.name)): | ||
case (node.callee.type === AST_NODE_TYPES.Identifier && isMatching(P.union("setInterval", "clearInterval"))(node.callee.name)): | ||
return node.callee.name; | ||
case (node.callee.type === utils.AST_NODE_TYPES.MemberExpression && node.callee.property.type === utils.AST_NODE_TYPES.Identifier && tsPattern.isMatching(tsPattern.P.union("setInterval", "clearInterval"))(node.callee.property.name)): | ||
case (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.property.type === AST_NODE_TYPES.Identifier && isMatching(P.union("setInterval", "clearInterval"))(node.callee.property.name)): | ||
return node.callee.property.name; | ||
@@ -344,3 +339,3 @@ default: | ||
function isInverseEntry(a, b) { | ||
return ER4__namespace.isInstanceIdEqual(context, a.timerId, b.timerId); | ||
return ER4.isInstanceIdEqual(context, a.timerId, b.timerId); | ||
} | ||
@@ -362,6 +357,6 @@ return { | ||
} | ||
if (!ER4__namespace.ComponentPhaseRelevance.has(fEntry.kind)) { | ||
if (!ER4.ComponentPhaseRelevance.has(fEntry.kind)) { | ||
break; | ||
} | ||
const intervalIdNode = VAR__namespace.getVariableDeclaratorId(node); | ||
const intervalIdNode = VAR.getVariableDeclaratorId(node); | ||
if (intervalIdNode == null) { | ||
@@ -388,3 +383,3 @@ context.report({ | ||
} | ||
if (!ER4__namespace.ComponentPhaseRelevance.has(fEntry.kind)) { | ||
if (!ER4.ComponentPhaseRelevance.has(fEntry.kind)) { | ||
break; | ||
@@ -441,12 +436,12 @@ } | ||
function isNewResizeObserver(node) { | ||
return node?.type === utils.AST_NODE_TYPES.NewExpression && node.callee.type === utils.AST_NODE_TYPES.Identifier && node.callee.name === "ResizeObserver"; | ||
return node?.type === AST_NODE_TYPES.NewExpression && node.callee.type === AST_NODE_TYPES.Identifier && node.callee.name === "ResizeObserver"; | ||
} | ||
function isFromObserver(context, node) { | ||
switch (true) { | ||
case node.type === utils.AST_NODE_TYPES.Identifier: { | ||
case node.type === AST_NODE_TYPES.Identifier: { | ||
const initialScope = context.sourceCode.getScope(node); | ||
const object = VAR__namespace.getVariableInitNode(VAR__namespace.findVariable(node, initialScope), 0); | ||
const object = VAR.getVariableInitNode(VAR.findVariable(node, initialScope), 0); | ||
return isNewResizeObserver(object); | ||
} | ||
case node.type === utils.AST_NODE_TYPES.MemberExpression: | ||
case node.type === AST_NODE_TYPES.MemberExpression: | ||
return isFromObserver(context, node.object); | ||
@@ -459,5 +454,5 @@ default: | ||
switch (true) { | ||
case (node.callee.type === utils.AST_NODE_TYPES.Identifier && tsPattern.isMatching(tsPattern.P.union("observe", "unobserve", "disconnect"))(node.callee.name) && isFromObserver(context, node.callee)): | ||
case (node.callee.type === AST_NODE_TYPES.Identifier && isMatching(P.union("observe", "unobserve", "disconnect"))(node.callee.name) && isFromObserver(context, node.callee)): | ||
return node.callee.name; | ||
case (node.callee.type === utils.AST_NODE_TYPES.MemberExpression && node.callee.property.type === utils.AST_NODE_TYPES.Identifier && tsPattern.isMatching(tsPattern.P.union("observe", "unobserve", "disconnect"))(node.callee.property.name) && isFromObserver(context, node.callee)): | ||
case (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.property.type === AST_NODE_TYPES.Identifier && isMatching(P.union("observe", "unobserve", "disconnect"))(node.callee.property.name) && isFromObserver(context, node.callee)): | ||
return node.callee.property.name; | ||
@@ -507,11 +502,11 @@ default: | ||
["CallExpression"](node) { | ||
if (node.callee.type !== utils.AST_NODE_TYPES.MemberExpression) { | ||
if (node.callee.type !== AST_NODE_TYPES.MemberExpression) { | ||
return; | ||
} | ||
const fKind = fEntries.findLast((x) => x.kind !== "other")?.kind; | ||
if (fKind == null || !ER4__namespace.ComponentPhaseRelevance.has(fKind)) { | ||
if (fKind == null || !ER4.ComponentPhaseRelevance.has(fKind)) { | ||
return; | ||
} | ||
const { object } = node.callee; | ||
tsPattern.match(getCallKind3(context, node)).with("disconnect", () => { | ||
match(getCallKind3(context, node)).with("disconnect", () => { | ||
dEntries.push({ | ||
@@ -558,3 +553,3 @@ kind: "disconnect", | ||
if (fEntry == null) return; | ||
if (!ER4__namespace.ComponentPhaseRelevance.has(fEntry.kind)) { | ||
if (!ER4.ComponentPhaseRelevance.has(fEntry.kind)) { | ||
return; | ||
@@ -565,3 +560,3 @@ } | ||
} | ||
const id = ER4__namespace.getInstanceId(node); | ||
const id = ER4.getInstanceId(node); | ||
if (id == null) { | ||
@@ -583,10 +578,10 @@ context.report({ | ||
for (const { id, node, phaseNode } of observers) { | ||
if (dEntries.some((e) => ER4__namespace.isInstanceIdEqual(context, e.observer, id))) { | ||
if (dEntries.some((e) => ER4.isInstanceIdEqual(context, e.observer, id))) { | ||
continue; | ||
} | ||
const oentries = oEntries.filter((e) => ER4__namespace.isInstanceIdEqual(context, e.observer, id)); | ||
const uentries = uEntries.filter((e) => ER4__namespace.isInstanceIdEqual(context, e.observer, id)); | ||
const isDynamic = (node2) => node2?.type === utils.AST_NODE_TYPES.CallExpression || AST__namespace.isConditional(node2); | ||
const oentries = oEntries.filter((e) => ER4.isInstanceIdEqual(context, e.observer, id)); | ||
const uentries = uEntries.filter((e) => ER4.isInstanceIdEqual(context, e.observer, id)); | ||
const isDynamic = (node2) => node2?.type === AST_NODE_TYPES.CallExpression || AST.isConditional(node2); | ||
const isPhaseNode = (node2) => node2 === phaseNode; | ||
const hasDynamicallyAdded = oentries.some((e) => !isPhaseNode(AST__namespace.findParentNode(e.node, eff.or(isDynamic, isPhaseNode)))); | ||
const hasDynamicallyAdded = oentries.some((e) => !isPhaseNode(AST.findParentNode(e.node, or(isDynamic, isPhaseNode)))); | ||
if (hasDynamicallyAdded) { | ||
@@ -597,3 +592,3 @@ context.report({ messageId: "expectedDisconnectInControlFlow", node }); | ||
for (const oEntry of oentries) { | ||
if (uentries.some((uEntry) => ER4__namespace.isInstanceIdEqual(context, uEntry.element, oEntry.element))) { | ||
if (uentries.some((uEntry) => ER4.isInstanceIdEqual(context, uEntry.element, oEntry.element))) { | ||
continue; | ||
@@ -611,5 +606,5 @@ } | ||
switch (true) { | ||
case (node.callee.type === utils.AST_NODE_TYPES.Identifier && tsPattern.isMatching(tsPattern.P.union("setTimeout", "clearTimeout"))(node.callee.name)): | ||
case (node.callee.type === AST_NODE_TYPES.Identifier && isMatching(P.union("setTimeout", "clearTimeout"))(node.callee.name)): | ||
return node.callee.name; | ||
case (node.callee.type === utils.AST_NODE_TYPES.MemberExpression && node.callee.property.type === utils.AST_NODE_TYPES.Identifier && tsPattern.isMatching(tsPattern.P.union("setTimeout", "clearTimeout"))(node.callee.property.name)): | ||
case (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.property.type === AST_NODE_TYPES.Identifier && isMatching(P.union("setTimeout", "clearTimeout"))(node.callee.property.name)): | ||
return node.callee.property.name; | ||
@@ -646,3 +641,3 @@ default: | ||
function isInverseEntry(a, b) { | ||
return ER4__namespace.isInstanceIdEqual(context, a.timerId, b.timerId); | ||
return ER4.isInstanceIdEqual(context, a.timerId, b.timerId); | ||
} | ||
@@ -659,3 +654,3 @@ return { | ||
const fEntry = fEntries.findLast((f) => f.kind !== "other"); | ||
if (!ER4__namespace.ComponentPhaseRelevance.has(fEntry?.kind)) { | ||
if (!ER4.ComponentPhaseRelevance.has(fEntry?.kind)) { | ||
return; | ||
@@ -665,3 +660,3 @@ } | ||
case "setTimeout": { | ||
const timeoutIdNode = VAR__namespace.getVariableDeclaratorId(node); | ||
const timeoutIdNode = VAR.getVariableDeclaratorId(node); | ||
if (timeoutIdNode == null) { | ||
@@ -768,2 +763,2 @@ context.report({ | ||
module.exports = index_default; | ||
export { index_default as default }; |
{ | ||
"name": "eslint-plugin-react-web-api", | ||
"version": "1.52.3-next.6", | ||
"version": "2.0.0-beta.0", | ||
"description": "ESLint React's ESLint plugin for interacting with Web APIs", | ||
@@ -25,18 +25,10 @@ "keywords": [ | ||
"sideEffects": false, | ||
"type": "module", | ||
"exports": { | ||
".": { | ||
"import": { | ||
"types": "./dist/index.d.mts", | ||
"default": "./dist/index.mjs" | ||
}, | ||
"require": { | ||
"types": "./dist/index.d.ts", | ||
"default": "./dist/index.js" | ||
} | ||
"types": "./dist/index.d.ts", | ||
"import": "./dist/index.js" | ||
}, | ||
"./package.json": "./package.json" | ||
}, | ||
"main": "dist/index.js", | ||
"module": "dist/index.mjs", | ||
"types": "dist/index.d.ts", | ||
"files": [ | ||
@@ -47,13 +39,13 @@ "dist", | ||
"dependencies": { | ||
"@typescript-eslint/scope-manager": "^8.34.1", | ||
"@typescript-eslint/types": "^8.34.1", | ||
"@typescript-eslint/utils": "^8.34.1", | ||
"@typescript-eslint/scope-manager": "^8.35.0", | ||
"@typescript-eslint/types": "^8.35.0", | ||
"@typescript-eslint/utils": "^8.35.0", | ||
"string-ts": "^2.2.1", | ||
"ts-pattern": "^5.7.1", | ||
"@eslint-react/core": "1.52.3-next.6", | ||
"@eslint-react/ast": "1.52.3-next.6", | ||
"@eslint-react/kit": "1.52.3-next.6", | ||
"@eslint-react/var": "1.52.3-next.6", | ||
"@eslint-react/shared": "1.52.3-next.6", | ||
"@eslint-react/eff": "1.52.3-next.6" | ||
"@eslint-react/ast": "2.0.0-beta.0", | ||
"@eslint-react/core": "2.0.0-beta.0", | ||
"@eslint-react/kit": "2.0.0-beta.0", | ||
"@eslint-react/eff": "2.0.0-beta.0", | ||
"@eslint-react/shared": "2.0.0-beta.0", | ||
"@eslint-react/var": "2.0.0-beta.0" | ||
}, | ||
@@ -67,4 +59,4 @@ "devDependencies": { | ||
"peerDependencies": { | ||
"eslint": "^8.57.0 || ^9.0.0", | ||
"typescript": "^4.9.5 || ^5.3.3" | ||
"eslint": "^9.29.0", | ||
"typescript": "^4.9.5 || ^5.4.5" | ||
}, | ||
@@ -81,3 +73,3 @@ "peerDependenciesMeta": { | ||
"bun": ">=1.0.15", | ||
"node": ">=18.18.0" | ||
"node": ">=20.19.0" | ||
}, | ||
@@ -84,0 +76,0 @@ "publishConfig": { |
Yes
NaN32794
-44.68%5
-28.57%773
-48.05%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed