eslint-plugin-runtime-cleanup 1.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +117 -0
  4. package/dist/_internal/ast-node.d.ts +19 -0
  5. package/dist/_internal/ast-node.d.ts.map +1 -0
  6. package/dist/_internal/ast-node.js +42 -0
  7. package/dist/_internal/ast-node.js.map +1 -0
  8. package/dist/_internal/bounded-cache.d.ts +37 -0
  9. package/dist/_internal/bounded-cache.d.ts.map +1 -0
  10. package/dist/_internal/bounded-cache.js +63 -0
  11. package/dist/_internal/bounded-cache.js.map +1 -0
  12. package/dist/_internal/cycle-safe-linked-search.d.ts +48 -0
  13. package/dist/_internal/cycle-safe-linked-search.d.ts.map +1 -0
  14. package/dist/_internal/cycle-safe-linked-search.js +70 -0
  15. package/dist/_internal/cycle-safe-linked-search.js.map +1 -0
  16. package/dist/_internal/expression-boolean-memoizer.d.ts +17 -0
  17. package/dist/_internal/expression-boolean-memoizer.d.ts.map +1 -0
  18. package/dist/_internal/expression-boolean-memoizer.js +22 -0
  19. package/dist/_internal/expression-boolean-memoizer.js.map +1 -0
  20. package/dist/_internal/filter-callback.d.ts +52 -0
  21. package/dist/_internal/filter-callback.d.ts.map +1 -0
  22. package/dist/_internal/filter-callback.js +108 -0
  23. package/dist/_internal/filter-callback.js.map +1 -0
  24. package/dist/_internal/floating-resource.d.ts +29 -0
  25. package/dist/_internal/floating-resource.d.ts.map +1 -0
  26. package/dist/_internal/floating-resource.js +114 -0
  27. package/dist/_internal/floating-resource.js.map +1 -0
  28. package/dist/_internal/member-call.d.ts +53 -0
  29. package/dist/_internal/member-call.d.ts.map +1 -0
  30. package/dist/_internal/member-call.js +61 -0
  31. package/dist/_internal/member-call.js.map +1 -0
  32. package/dist/_internal/normalize-expression-text.d.ts +21 -0
  33. package/dist/_internal/normalize-expression-text.d.ts.map +1 -0
  34. package/dist/_internal/normalize-expression-text.js +186 -0
  35. package/dist/_internal/normalize-expression-text.js.map +1 -0
  36. package/dist/_internal/nullish-comparison.d.ts +44 -0
  37. package/dist/_internal/nullish-comparison.d.ts.map +1 -0
  38. package/dist/_internal/nullish-comparison.js +162 -0
  39. package/dist/_internal/nullish-comparison.js.map +1 -0
  40. package/dist/_internal/plugin-settings.d.ts +30 -0
  41. package/dist/_internal/plugin-settings.d.ts.map +1 -0
  42. package/dist/_internal/plugin-settings.js +90 -0
  43. package/dist/_internal/plugin-settings.js.map +1 -0
  44. package/dist/_internal/report-adapter.d.ts +24 -0
  45. package/dist/_internal/report-adapter.d.ts.map +1 -0
  46. package/dist/_internal/report-adapter.js +35 -0
  47. package/dist/_internal/report-adapter.js.map +1 -0
  48. package/dist/_internal/rule-catalog.d.ts +47 -0
  49. package/dist/_internal/rule-catalog.d.ts.map +1 -0
  50. package/dist/_internal/rule-catalog.js +97 -0
  51. package/dist/_internal/rule-catalog.js.map +1 -0
  52. package/dist/_internal/rule-docs-metadata.d.ts +35 -0
  53. package/dist/_internal/rule-docs-metadata.d.ts.map +1 -0
  54. package/dist/_internal/rule-docs-metadata.js +172 -0
  55. package/dist/_internal/rule-docs-metadata.js.map +1 -0
  56. package/dist/_internal/rule-docs-url.d.ts +15 -0
  57. package/dist/_internal/rule-docs-url.d.ts.map +1 -0
  58. package/dist/_internal/rule-docs-url.js +15 -0
  59. package/dist/_internal/rule-docs-url.js.map +1 -0
  60. package/dist/_internal/rules-registry.d.ts +11 -0
  61. package/dist/_internal/rules-registry.d.ts.map +1 -0
  62. package/dist/_internal/rules-registry.js +53 -0
  63. package/dist/_internal/rules-registry.js.map +1 -0
  64. package/dist/_internal/runtime-cleanup-config-references.d.ts +38 -0
  65. package/dist/_internal/runtime-cleanup-config-references.d.ts.map +1 -0
  66. package/dist/_internal/runtime-cleanup-config-references.js +78 -0
  67. package/dist/_internal/runtime-cleanup-config-references.js.map +1 -0
  68. package/dist/_internal/safe-type-operation.d.ts +89 -0
  69. package/dist/_internal/safe-type-operation.d.ts.map +1 -0
  70. package/dist/_internal/safe-type-operation.js +147 -0
  71. package/dist/_internal/safe-type-operation.js.map +1 -0
  72. package/dist/_internal/scope-variable.d.ts +17 -0
  73. package/dist/_internal/scope-variable.d.ts.map +1 -0
  74. package/dist/_internal/scope-variable.js +30 -0
  75. package/dist/_internal/scope-variable.js.map +1 -0
  76. package/dist/_internal/type-checker.d.ts +11 -0
  77. package/dist/_internal/type-checker.d.ts.map +1 -0
  78. package/dist/_internal/type-checker.js +25 -0
  79. package/dist/_internal/type-checker.js.map +1 -0
  80. package/dist/_internal/type-predicate-autofix-safety.d.ts +16 -0
  81. package/dist/_internal/type-predicate-autofix-safety.d.ts.map +1 -0
  82. package/dist/_internal/type-predicate-autofix-safety.js +54 -0
  83. package/dist/_internal/type-predicate-autofix-safety.js.map +1 -0
  84. package/dist/_internal/type-reference-node.d.ts +23 -0
  85. package/dist/_internal/type-reference-node.d.ts.map +1 -0
  86. package/dist/_internal/type-reference-node.js +41 -0
  87. package/dist/_internal/type-reference-node.js.map +1 -0
  88. package/dist/_internal/typed-rule.d.ts +91 -0
  89. package/dist/_internal/typed-rule.d.ts.map +1 -0
  90. package/dist/_internal/typed-rule.js +121 -0
  91. package/dist/_internal/typed-rule.js.map +1 -0
  92. package/dist/_internal/value-rewrite-autofix-safety.d.ts +29 -0
  93. package/dist/_internal/value-rewrite-autofix-safety.d.ts.map +1 -0
  94. package/dist/_internal/value-rewrite-autofix-safety.js +108 -0
  95. package/dist/_internal/value-rewrite-autofix-safety.js.map +1 -0
  96. package/dist/plugin.cjs +3693 -0
  97. package/dist/plugin.cjs.map +7 -0
  98. package/dist/plugin.d.cts +75 -0
  99. package/dist/plugin.d.ts +75 -0
  100. package/dist/plugin.d.ts.map +1 -0
  101. package/dist/plugin.js +223 -0
  102. package/dist/plugin.js.map +1 -0
  103. package/dist/rules/no-floating-abort-controllers.d.ts +9 -0
  104. package/dist/rules/no-floating-abort-controllers.d.ts.map +1 -0
  105. package/dist/rules/no-floating-abort-controllers.js +144 -0
  106. package/dist/rules/no-floating-abort-controllers.js.map +1 -0
  107. package/dist/rules/no-floating-audio-contexts.d.ts +9 -0
  108. package/dist/rules/no-floating-audio-contexts.d.ts.map +1 -0
  109. package/dist/rules/no-floating-audio-contexts.js +95 -0
  110. package/dist/rules/no-floating-audio-contexts.js.map +1 -0
  111. package/dist/rules/no-floating-broadcast-channels.d.ts +9 -0
  112. package/dist/rules/no-floating-broadcast-channels.d.ts.map +1 -0
  113. package/dist/rules/no-floating-broadcast-channels.js +151 -0
  114. package/dist/rules/no-floating-broadcast-channels.js.map +1 -0
  115. package/dist/rules/no-floating-child-processes.d.ts +9 -0
  116. package/dist/rules/no-floating-child-processes.d.ts.map +1 -0
  117. package/dist/rules/no-floating-child-processes.js +259 -0
  118. package/dist/rules/no-floating-child-processes.js.map +1 -0
  119. package/dist/rules/no-floating-disposable-stacks.d.ts +9 -0
  120. package/dist/rules/no-floating-disposable-stacks.d.ts.map +1 -0
  121. package/dist/rules/no-floating-disposable-stacks.js +177 -0
  122. package/dist/rules/no-floating-disposable-stacks.js.map +1 -0
  123. package/dist/rules/no-floating-file-watchers.d.ts +9 -0
  124. package/dist/rules/no-floating-file-watchers.d.ts.map +1 -0
  125. package/dist/rules/no-floating-file-watchers.js +241 -0
  126. package/dist/rules/no-floating-file-watchers.js.map +1 -0
  127. package/dist/rules/no-floating-geolocation-watches.d.ts +9 -0
  128. package/dist/rules/no-floating-geolocation-watches.d.ts.map +1 -0
  129. package/dist/rules/no-floating-geolocation-watches.js +156 -0
  130. package/dist/rules/no-floating-geolocation-watches.js.map +1 -0
  131. package/dist/rules/no-floating-infinite-animations.d.ts +9 -0
  132. package/dist/rules/no-floating-infinite-animations.d.ts.map +1 -0
  133. package/dist/rules/no-floating-infinite-animations.js +131 -0
  134. package/dist/rules/no-floating-infinite-animations.js.map +1 -0
  135. package/dist/rules/no-floating-media-streams.d.ts +9 -0
  136. package/dist/rules/no-floating-media-streams.d.ts.map +1 -0
  137. package/dist/rules/no-floating-media-streams.js +175 -0
  138. package/dist/rules/no-floating-media-streams.js.map +1 -0
  139. package/dist/rules/no-floating-message-channels.d.ts +9 -0
  140. package/dist/rules/no-floating-message-channels.d.ts.map +1 -0
  141. package/dist/rules/no-floating-message-channels.js +150 -0
  142. package/dist/rules/no-floating-message-channels.js.map +1 -0
  143. package/dist/rules/no-floating-network-connections.d.ts +9 -0
  144. package/dist/rules/no-floating-network-connections.d.ts.map +1 -0
  145. package/dist/rules/no-floating-network-connections.js +170 -0
  146. package/dist/rules/no-floating-network-connections.js.map +1 -0
  147. package/dist/rules/no-floating-object-urls.d.ts +9 -0
  148. package/dist/rules/no-floating-object-urls.d.ts.map +1 -0
  149. package/dist/rules/no-floating-object-urls.js +83 -0
  150. package/dist/rules/no-floating-object-urls.js.map +1 -0
  151. package/dist/rules/no-floating-observers.d.ts +9 -0
  152. package/dist/rules/no-floating-observers.d.ts.map +1 -0
  153. package/dist/rules/no-floating-observers.js +160 -0
  154. package/dist/rules/no-floating-observers.js.map +1 -0
  155. package/dist/rules/no-floating-servers.d.ts +9 -0
  156. package/dist/rules/no-floating-servers.d.ts.map +1 -0
  157. package/dist/rules/no-floating-servers.js +282 -0
  158. package/dist/rules/no-floating-servers.js.map +1 -0
  159. package/dist/rules/no-floating-streams.d.ts +9 -0
  160. package/dist/rules/no-floating-streams.d.ts.map +1 -0
  161. package/dist/rules/no-floating-streams.js +222 -0
  162. package/dist/rules/no-floating-streams.js.map +1 -0
  163. package/dist/rules/no-floating-timers.d.ts +9 -0
  164. package/dist/rules/no-floating-timers.d.ts.map +1 -0
  165. package/dist/rules/no-floating-timers.js +145 -0
  166. package/dist/rules/no-floating-timers.js.map +1 -0
  167. package/dist/rules/no-floating-wake-locks.d.ts +9 -0
  168. package/dist/rules/no-floating-wake-locks.d.ts.map +1 -0
  169. package/dist/rules/no-floating-wake-locks.js +159 -0
  170. package/dist/rules/no-floating-wake-locks.js.map +1 -0
  171. package/dist/rules/no-floating-web-stream-locks.d.ts +9 -0
  172. package/dist/rules/no-floating-web-stream-locks.d.ts.map +1 -0
  173. package/dist/rules/no-floating-web-stream-locks.js +87 -0
  174. package/dist/rules/no-floating-web-stream-locks.js.map +1 -0
  175. package/dist/rules/no-floating-workers.d.ts +9 -0
  176. package/dist/rules/no-floating-workers.d.ts.map +1 -0
  177. package/dist/rules/no-floating-workers.js +185 -0
  178. package/dist/rules/no-floating-workers.js.map +1 -0
  179. package/dist/rules/no-unmanaged-event-listeners.d.ts +9 -0
  180. package/dist/rules/no-unmanaged-event-listeners.d.ts.map +1 -0
  181. package/dist/rules/no-unmanaged-event-listeners.js +210 -0
  182. package/dist/rules/no-unmanaged-event-listeners.js.map +1 -0
  183. package/docs/rules/getting-started.md +29 -0
  184. package/docs/rules/guides/adoption-checklist.md +31 -0
  185. package/docs/rules/guides/preset-selection-strategy.md +24 -0
  186. package/docs/rules/guides/rollout-and-fix-safety.md +42 -0
  187. package/docs/rules/guides/snapshot-testing.md +20 -0
  188. package/docs/rules/guides/type-aware-linting-readiness.md +20 -0
  189. package/docs/rules/no-floating-abort-controllers.md +126 -0
  190. package/docs/rules/no-floating-audio-contexts.md +104 -0
  191. package/docs/rules/no-floating-broadcast-channels.md +105 -0
  192. package/docs/rules/no-floating-child-processes.md +123 -0
  193. package/docs/rules/no-floating-disposable-stacks.md +118 -0
  194. package/docs/rules/no-floating-file-watchers.md +111 -0
  195. package/docs/rules/no-floating-geolocation-watches.md +95 -0
  196. package/docs/rules/no-floating-infinite-animations.md +110 -0
  197. package/docs/rules/no-floating-media-streams.md +113 -0
  198. package/docs/rules/no-floating-message-channels.md +114 -0
  199. package/docs/rules/no-floating-network-connections.md +116 -0
  200. package/docs/rules/no-floating-object-urls.md +102 -0
  201. package/docs/rules/no-floating-observers.md +108 -0
  202. package/docs/rules/no-floating-servers.md +127 -0
  203. package/docs/rules/no-floating-streams.md +120 -0
  204. package/docs/rules/no-floating-timers.md +120 -0
  205. package/docs/rules/no-floating-wake-locks.md +109 -0
  206. package/docs/rules/no-floating-web-stream-locks.md +105 -0
  207. package/docs/rules/no-floating-workers.md +123 -0
  208. package/docs/rules/no-unmanaged-event-listeners.md +143 -0
  209. package/docs/rules/overview.md +44 -0
  210. package/docs/rules/presets/all.md +35 -0
  211. package/docs/rules/presets/experimental.md +44 -0
  212. package/docs/rules/presets/index.md +54 -0
  213. package/docs/rules/presets/minimal.md +17 -0
  214. package/docs/rules/presets/recommended-type-checked.md +43 -0
  215. package/docs/rules/presets/recommended.md +34 -0
  216. package/docs/rules/presets/strict.md +36 -0
  217. package/package.json +323 -0
@@ -0,0 +1,175 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * Require captured MediaStream handles to be retained so their tracks can be stopped.
4
+ */
5
+ import { AST_NODE_TYPES, } from "@typescript-eslint/utils";
6
+ import { getParentNode } from "../_internal/ast-node.js";
7
+ import { createRuleDocsUrl } from "../_internal/rule-docs-url.js";
8
+ import { getVariableInScopeChain } from "../_internal/scope-variable.js";
9
+ import { createTypedRule, } from "../_internal/typed-rule.js";
10
+ const mediaCaptureFunctionNames = [
11
+ "getDisplayMedia",
12
+ "getUserMedia",
13
+ ];
14
+ const globalNavigatorReceiverNames = ["globalThis", "window"];
15
+ const mediaCaptureFunctionNameSet = new Set(mediaCaptureFunctionNames);
16
+ const globalNavigatorReceiverNameSet = new Set(globalNavigatorReceiverNames);
17
+ const isMediaCaptureFunctionName = (name) => mediaCaptureFunctionNameSet.has(name);
18
+ const getTransparentWrappedExpression = (node) => {
19
+ if (node.type === AST_NODE_TYPES.AwaitExpression) {
20
+ return node.argument;
21
+ }
22
+ if (node.type === AST_NODE_TYPES.ChainExpression) {
23
+ return node.expression;
24
+ }
25
+ if (node.type === AST_NODE_TYPES.TSAsExpression) {
26
+ return node.expression;
27
+ }
28
+ if (node.type === AST_NODE_TYPES.TSNonNullExpression) {
29
+ return node.expression;
30
+ }
31
+ if (node.type === AST_NODE_TYPES.TSSatisfiesExpression) {
32
+ return node.expression;
33
+ }
34
+ if (node.type === AST_NODE_TYPES.TSTypeAssertion) {
35
+ return node.expression;
36
+ }
37
+ return undefined;
38
+ };
39
+ const getStaticPropertyName = (node, computed) => {
40
+ if (!computed && node.type === AST_NODE_TYPES.Identifier) {
41
+ return node.name;
42
+ }
43
+ if (computed &&
44
+ node.type === AST_NODE_TYPES.Literal &&
45
+ typeof node.value === "string") {
46
+ return node.value;
47
+ }
48
+ return undefined;
49
+ };
50
+ const collectStaticMemberPath = (node) => {
51
+ if (node.type === AST_NODE_TYPES.Identifier) {
52
+ return [node.name];
53
+ }
54
+ if (node.type !== AST_NODE_TYPES.MemberExpression || node.optional) {
55
+ return undefined;
56
+ }
57
+ const objectPath = collectStaticMemberPath(node.object);
58
+ const propertyName = getStaticPropertyName(node.property, node.computed);
59
+ return objectPath === undefined || propertyName === undefined
60
+ ? undefined
61
+ : [...objectPath, propertyName];
62
+ };
63
+ const isShadowedNavigatorIdentifier = (context, identifier) => {
64
+ const scope = context.sourceCode.getScope(identifier);
65
+ const variable = getVariableInScopeChain(scope, identifier.name);
66
+ return variable !== null && variable.defs.length > 0;
67
+ };
68
+ const getRootIdentifier = (node) => {
69
+ if (node.type === AST_NODE_TYPES.Identifier) {
70
+ return node;
71
+ }
72
+ return node.type === AST_NODE_TYPES.MemberExpression
73
+ ? getRootIdentifier(node.object)
74
+ : undefined;
75
+ };
76
+ const isNavigatorPathShadowed = (context, callee) => {
77
+ if (callee.type !== AST_NODE_TYPES.MemberExpression) {
78
+ return false;
79
+ }
80
+ const rootIdentifier = getRootIdentifier(callee.object);
81
+ return (rootIdentifier?.name === "navigator" &&
82
+ isShadowedNavigatorIdentifier(context, rootIdentifier));
83
+ };
84
+ const getMediaCaptureNameFromPath = (path) => {
85
+ const captureName = path.at(-1);
86
+ if (captureName === undefined || !isMediaCaptureFunctionName(captureName)) {
87
+ return undefined;
88
+ }
89
+ if (path.length === 3 &&
90
+ path[0] === "navigator" &&
91
+ path[1] === "mediaDevices") {
92
+ return captureName;
93
+ }
94
+ if (path.length === 4 &&
95
+ globalNavigatorReceiverNameSet.has(path[0] ?? "") &&
96
+ path[1] === "navigator" &&
97
+ path[2] === "mediaDevices") {
98
+ return captureName;
99
+ }
100
+ return undefined;
101
+ };
102
+ const getMediaCaptureFunctionName = (context, callee) => {
103
+ if (callee.type !== AST_NODE_TYPES.MemberExpression ||
104
+ isNavigatorPathShadowed(context, callee)) {
105
+ return undefined;
106
+ }
107
+ const path = collectStaticMemberPath(callee);
108
+ return path === undefined ? undefined : getMediaCaptureNameFromPath(path);
109
+ };
110
+ const isDiscardedMediaStreamRequest = (node) => {
111
+ let current = node;
112
+ let parent = getParentNode(current);
113
+ while (parent !== undefined) {
114
+ const wrappedExpression = getTransparentWrappedExpression(parent);
115
+ if (wrappedExpression === current) {
116
+ current = parent;
117
+ parent = getParentNode(current);
118
+ continue;
119
+ }
120
+ if (parent.type === AST_NODE_TYPES.ExpressionStatement &&
121
+ parent.expression === current) {
122
+ return true;
123
+ }
124
+ if (parent.type === AST_NODE_TYPES.UnaryExpression &&
125
+ parent.operator === "void" &&
126
+ parent.argument === current) {
127
+ const unaryParent = getParentNode(parent);
128
+ return unaryParent?.type === AST_NODE_TYPES.ExpressionStatement;
129
+ }
130
+ return false;
131
+ }
132
+ return false;
133
+ };
134
+ /** Rule implementation for `runtime-cleanup/no-floating-media-streams`. */
135
+ const noFloatingMediaStreams = createTypedRule({
136
+ create(context) {
137
+ return {
138
+ CallExpression(node) {
139
+ const captureName = getMediaCaptureFunctionName(context, node.callee);
140
+ if (captureName === undefined ||
141
+ !isDiscardedMediaStreamRequest(node)) {
142
+ return;
143
+ }
144
+ context.report({
145
+ data: { captureName },
146
+ messageId: "floatingMediaStream",
147
+ node,
148
+ });
149
+ },
150
+ };
151
+ },
152
+ defaultOptions: [],
153
+ meta: {
154
+ docs: {
155
+ description: "require captured MediaStream handles to be retained so their tracks can be stopped.",
156
+ recommended: true,
157
+ requiresTypeChecking: false,
158
+ runtimeCleanupConfigs: [
159
+ "runtime-cleanup.configs.recommended",
160
+ "runtime-cleanup.configs.recommended-type-checked",
161
+ "runtime-cleanup.configs.strict",
162
+ "runtime-cleanup.configs.all",
163
+ ],
164
+ url: createRuleDocsUrl("no-floating-media-streams"),
165
+ },
166
+ messages: {
167
+ floatingMediaStream: "Store or return the MediaStream from {{captureName}} so its tracks can be stopped during cleanup.",
168
+ },
169
+ schema: [],
170
+ type: "problem",
171
+ },
172
+ name: "no-floating-media-streams",
173
+ });
174
+ export default noFloatingMediaStreams;
175
+ //# sourceMappingURL=no-floating-media-streams.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-floating-media-streams.js","sourceRoot":"","sources":["../../src/rules/no-floating-media-streams.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * Require MessageChannel ports to be retained so they can be closed.
4
+ */
5
+ import { type TSESLint } from "@typescript-eslint/utils";
6
+ /** Rule implementation for `runtime-cleanup/no-floating-message-channels`. */
7
+ declare const noFloatingMessageChannels: TSESLint.RuleModule<"floatingMessageChannel", readonly []>;
8
+ export default noFloatingMessageChannels;
9
+ //# sourceMappingURL=no-floating-message-channels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-floating-message-channels.d.ts","sourceRoot":"","sources":["../../src/rules/no-floating-message-channels.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAEH,KAAK,QAAQ,EAEhB,MAAM,0BAA0B,CAAC;AAyLlC,8EAA8E;AAC9E,QAAA,MAAM,yBAAyB,EAAE,QAAQ,CAAC,UAAU,CAChD,wBAAwB,EACxB,SAAS,EAAE,CA2Cb,CAAC;AAEH,eAAe,yBAAyB,CAAC"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * Require MessageChannel ports to be retained so they can be closed.
4
+ */
5
+ import { AST_NODE_TYPES, } from "@typescript-eslint/utils";
6
+ import { getParentNode } from "../_internal/ast-node.js";
7
+ import { createRuleDocsUrl } from "../_internal/rule-docs-url.js";
8
+ import { getVariableInScopeChain } from "../_internal/scope-variable.js";
9
+ import { createTypedRule, } from "../_internal/typed-rule.js";
10
+ const messageChannelConstructorName = "MessageChannel";
11
+ const messagePortPropertyNames = ["port1", "port2"];
12
+ const globalReceiverNames = [
13
+ "globalThis",
14
+ "self",
15
+ "window",
16
+ ];
17
+ const globalReceiverNameSet = new Set(globalReceiverNames);
18
+ const messagePortPropertyNameSet = new Set(messagePortPropertyNames);
19
+ const isGlobalReceiverName = (name) => globalReceiverNameSet.has(name);
20
+ const isMessagePortPropertyName = (name) => messagePortPropertyNameSet.has(name);
21
+ const getTransparentWrappedExpression = (node) => {
22
+ if (node.type === AST_NODE_TYPES.ChainExpression) {
23
+ return node.expression;
24
+ }
25
+ if (node.type === AST_NODE_TYPES.TSAsExpression) {
26
+ return node.expression;
27
+ }
28
+ if (node.type === AST_NODE_TYPES.TSNonNullExpression) {
29
+ return node.expression;
30
+ }
31
+ if (node.type === AST_NODE_TYPES.TSSatisfiesExpression) {
32
+ return node.expression;
33
+ }
34
+ if (node.type === AST_NODE_TYPES.TSTypeAssertion) {
35
+ return node.expression;
36
+ }
37
+ return undefined;
38
+ };
39
+ const getStaticPropertyName = (node, computed) => {
40
+ if (!computed && node.type === AST_NODE_TYPES.Identifier) {
41
+ return node.name;
42
+ }
43
+ if (computed &&
44
+ node.type === AST_NODE_TYPES.Literal &&
45
+ typeof node.value === "string") {
46
+ return node.value;
47
+ }
48
+ return undefined;
49
+ };
50
+ const isShadowedMessageChannelIdentifier = (context, identifier) => {
51
+ const scope = context.sourceCode.getScope(identifier);
52
+ const variable = getVariableInScopeChain(scope, identifier.name);
53
+ return variable !== null && variable.defs.length > 0;
54
+ };
55
+ const isDirectMessageChannelConstructor = (context, callee) => callee.type === AST_NODE_TYPES.Identifier &&
56
+ callee.name === messageChannelConstructorName &&
57
+ !isShadowedMessageChannelIdentifier(context, callee);
58
+ const isMemberMessageChannelConstructor = (callee) => callee.type === AST_NODE_TYPES.MemberExpression &&
59
+ !callee.optional &&
60
+ callee.object.type === AST_NODE_TYPES.Identifier &&
61
+ isGlobalReceiverName(callee.object.name) &&
62
+ getStaticPropertyName(callee.property, callee.computed) ===
63
+ messageChannelConstructorName;
64
+ const isMessageChannelConstructor = (context, callee) => isDirectMessageChannelConstructor(context, callee) ||
65
+ isMemberMessageChannelConstructor(callee);
66
+ const isDiscardedMessageChannel = (node) => {
67
+ let current = node;
68
+ let parent = getParentNode(current);
69
+ while (parent !== undefined) {
70
+ const wrappedExpression = getTransparentWrappedExpression(parent);
71
+ if (wrappedExpression === current) {
72
+ current = parent;
73
+ parent = getParentNode(current);
74
+ continue;
75
+ }
76
+ if (parent.type === AST_NODE_TYPES.ExpressionStatement &&
77
+ parent.expression === current) {
78
+ return true;
79
+ }
80
+ if (parent.type === AST_NODE_TYPES.UnaryExpression &&
81
+ parent.operator === "void" &&
82
+ parent.argument === current) {
83
+ const unaryParent = getParentNode(parent);
84
+ return unaryParent?.type === AST_NODE_TYPES.ExpressionStatement;
85
+ }
86
+ return false;
87
+ }
88
+ return false;
89
+ };
90
+ const isImmediateMessagePortAccess = (node) => {
91
+ let current = node;
92
+ let parent = getParentNode(current);
93
+ while (parent !== undefined) {
94
+ const wrappedExpression = getTransparentWrappedExpression(parent);
95
+ if (wrappedExpression === current) {
96
+ current = parent;
97
+ parent = getParentNode(current);
98
+ continue;
99
+ }
100
+ if (parent.type !== AST_NODE_TYPES.MemberExpression ||
101
+ parent.object !== current ||
102
+ parent.optional) {
103
+ return false;
104
+ }
105
+ const propertyName = getStaticPropertyName(parent.property, parent.computed);
106
+ return (propertyName !== undefined && isMessagePortPropertyName(propertyName));
107
+ }
108
+ return false;
109
+ };
110
+ /** Rule implementation for `runtime-cleanup/no-floating-message-channels`. */
111
+ const noFloatingMessageChannels = createTypedRule({
112
+ create(context) {
113
+ return {
114
+ NewExpression(node) {
115
+ if (!isMessageChannelConstructor(context, node.callee) ||
116
+ (!isDiscardedMessageChannel(node) &&
117
+ !isImmediateMessagePortAccess(node))) {
118
+ return;
119
+ }
120
+ context.report({
121
+ messageId: "floatingMessageChannel",
122
+ node,
123
+ });
124
+ },
125
+ };
126
+ },
127
+ defaultOptions: [],
128
+ meta: {
129
+ docs: {
130
+ description: "require MessageChannel ports to be retained so they can be closed.",
131
+ recommended: true,
132
+ requiresTypeChecking: false,
133
+ runtimeCleanupConfigs: [
134
+ "runtime-cleanup.configs.recommended",
135
+ "runtime-cleanup.configs.recommended-type-checked",
136
+ "runtime-cleanup.configs.strict",
137
+ "runtime-cleanup.configs.all",
138
+ ],
139
+ url: createRuleDocsUrl("no-floating-message-channels"),
140
+ },
141
+ messages: {
142
+ floatingMessageChannel: "Store or return the MessageChannel handle or both MessagePort handles so the ports can be closed during cleanup.",
143
+ },
144
+ schema: [],
145
+ type: "problem",
146
+ },
147
+ name: "no-floating-message-channels",
148
+ });
149
+ export default noFloatingMessageChannels;
150
+ //# sourceMappingURL=no-floating-message-channels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-floating-message-channels.js","sourceRoot":"","sources":["../../src/rules/no-floating-message-channels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * Require browser network connection handles to be retained so they can be closed.
4
+ */
5
+ import { type TSESLint } from "@typescript-eslint/utils";
6
+ /** Rule implementation for `runtime-cleanup/no-floating-network-connections`. */
7
+ declare const noFloatingNetworkConnections: TSESLint.RuleModule<"floatingNetworkConnection", readonly []>;
8
+ export default noFloatingNetworkConnections;
9
+ //# sourceMappingURL=no-floating-network-connections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-floating-network-connections.d.ts","sourceRoot":"","sources":["../../src/rules/no-floating-network-connections.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAEH,KAAK,QAAQ,EAEhB,MAAM,0BAA0B,CAAC;AAwNlC,iFAAiF;AACjF,QAAA,MAAM,4BAA4B,EAAE,QAAQ,CAAC,UAAU,CACnD,2BAA2B,EAC3B,SAAS,EAAE,CAiDb,CAAC;AAEH,eAAe,4BAA4B,CAAC"}
@@ -0,0 +1,170 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * Require browser network connection handles to be retained so they can be closed.
4
+ */
5
+ import { AST_NODE_TYPES, } from "@typescript-eslint/utils";
6
+ import { getParentNode } from "../_internal/ast-node.js";
7
+ import { createRuleDocsUrl } from "../_internal/rule-docs-url.js";
8
+ import { getVariableInScopeChain } from "../_internal/scope-variable.js";
9
+ import { createTypedRule, } from "../_internal/typed-rule.js";
10
+ const networkConnectionConstructorNames = [
11
+ "EventSource",
12
+ "WebSocket",
13
+ ];
14
+ const globalReceiverNames = [
15
+ "globalThis",
16
+ "self",
17
+ "window",
18
+ ];
19
+ const networkConnectionConstructorNameSet = new Set(networkConnectionConstructorNames);
20
+ const globalReceiverNameSet = new Set(globalReceiverNames);
21
+ const isNetworkConnectionConstructorName = (name) => networkConnectionConstructorNameSet.has(name);
22
+ const isGlobalReceiverName = (name) => globalReceiverNameSet.has(name);
23
+ const getTransparentWrappedExpression = (node) => {
24
+ if (node.type === AST_NODE_TYPES.ChainExpression) {
25
+ return node.expression;
26
+ }
27
+ if (node.type === AST_NODE_TYPES.TSAsExpression) {
28
+ return node.expression;
29
+ }
30
+ if (node.type === AST_NODE_TYPES.TSNonNullExpression) {
31
+ return node.expression;
32
+ }
33
+ if (node.type === AST_NODE_TYPES.TSSatisfiesExpression) {
34
+ return node.expression;
35
+ }
36
+ if (node.type === AST_NODE_TYPES.TSTypeAssertion) {
37
+ return node.expression;
38
+ }
39
+ return undefined;
40
+ };
41
+ const getStaticPropertyName = (node, computed) => {
42
+ if (!computed && node.type === AST_NODE_TYPES.Identifier) {
43
+ return node.name;
44
+ }
45
+ if (computed &&
46
+ node.type === AST_NODE_TYPES.Literal &&
47
+ typeof node.value === "string") {
48
+ return node.value;
49
+ }
50
+ return undefined;
51
+ };
52
+ const isShadowedNetworkConnectionIdentifier = (context, identifier) => {
53
+ const scope = context.sourceCode.getScope(identifier);
54
+ const variable = getVariableInScopeChain(scope, identifier.name);
55
+ return variable !== null && variable.defs.length > 0;
56
+ };
57
+ const getDirectNetworkConnectionConstructorName = (context, callee) => {
58
+ if (callee.type !== AST_NODE_TYPES.Identifier ||
59
+ !isNetworkConnectionConstructorName(callee.name) ||
60
+ isShadowedNetworkConnectionIdentifier(context, callee)) {
61
+ return undefined;
62
+ }
63
+ return callee.name;
64
+ };
65
+ const getMemberNetworkConnectionConstructorName = (callee) => {
66
+ if (callee.type !== AST_NODE_TYPES.MemberExpression ||
67
+ callee.optional ||
68
+ callee.object.type !== AST_NODE_TYPES.Identifier ||
69
+ !isGlobalReceiverName(callee.object.name)) {
70
+ return undefined;
71
+ }
72
+ const constructorName = getStaticPropertyName(callee.property, callee.computed);
73
+ return constructorName !== undefined &&
74
+ isNetworkConnectionConstructorName(constructorName)
75
+ ? constructorName
76
+ : undefined;
77
+ };
78
+ const getNetworkConnectionConstructorName = (context, callee) => getDirectNetworkConnectionConstructorName(context, callee) ??
79
+ getMemberNetworkConnectionConstructorName(callee);
80
+ const isDiscardedNetworkConnection = (node) => {
81
+ let current = node;
82
+ let parent = getParentNode(current);
83
+ while (parent !== undefined) {
84
+ const wrappedExpression = getTransparentWrappedExpression(parent);
85
+ if (wrappedExpression === current) {
86
+ current = parent;
87
+ parent = getParentNode(current);
88
+ continue;
89
+ }
90
+ if (parent.type === AST_NODE_TYPES.ExpressionStatement &&
91
+ parent.expression === current) {
92
+ return true;
93
+ }
94
+ if (parent.type === AST_NODE_TYPES.UnaryExpression &&
95
+ parent.operator === "void" &&
96
+ parent.argument === current) {
97
+ const unaryParent = getParentNode(parent);
98
+ return unaryParent?.type === AST_NODE_TYPES.ExpressionStatement;
99
+ }
100
+ return false;
101
+ }
102
+ return false;
103
+ };
104
+ const isImmediateNetworkConnectionMethodReceiver = (node) => {
105
+ let current = node;
106
+ let parent = getParentNode(current);
107
+ while (parent !== undefined) {
108
+ const wrappedExpression = getTransparentWrappedExpression(parent);
109
+ if (wrappedExpression === current) {
110
+ current = parent;
111
+ parent = getParentNode(current);
112
+ continue;
113
+ }
114
+ if (parent.type !== AST_NODE_TYPES.MemberExpression ||
115
+ parent.object !== current ||
116
+ parent.optional) {
117
+ return false;
118
+ }
119
+ if (getStaticPropertyName(parent.property, parent.computed) === "close") {
120
+ return false;
121
+ }
122
+ const callExpression = getParentNode(parent);
123
+ return (callExpression?.type === AST_NODE_TYPES.CallExpression &&
124
+ callExpression.callee === parent);
125
+ }
126
+ return false;
127
+ };
128
+ /** Rule implementation for `runtime-cleanup/no-floating-network-connections`. */
129
+ const noFloatingNetworkConnections = createTypedRule({
130
+ create(context) {
131
+ return {
132
+ NewExpression(node) {
133
+ const connectionName = getNetworkConnectionConstructorName(context, node.callee);
134
+ if (connectionName === undefined ||
135
+ (!isDiscardedNetworkConnection(node) &&
136
+ !isImmediateNetworkConnectionMethodReceiver(node))) {
137
+ return;
138
+ }
139
+ context.report({
140
+ data: { connectionName },
141
+ messageId: "floatingNetworkConnection",
142
+ node,
143
+ });
144
+ },
145
+ };
146
+ },
147
+ defaultOptions: [],
148
+ meta: {
149
+ docs: {
150
+ description: "require browser network connection handles to be retained so they can be closed.",
151
+ recommended: true,
152
+ requiresTypeChecking: false,
153
+ runtimeCleanupConfigs: [
154
+ "runtime-cleanup.configs.recommended",
155
+ "runtime-cleanup.configs.recommended-type-checked",
156
+ "runtime-cleanup.configs.strict",
157
+ "runtime-cleanup.configs.all",
158
+ ],
159
+ url: createRuleDocsUrl("no-floating-network-connections"),
160
+ },
161
+ messages: {
162
+ floatingNetworkConnection: "Store or return the {{connectionName}} handle so close() can release the connection during cleanup.",
163
+ },
164
+ schema: [],
165
+ type: "problem",
166
+ },
167
+ name: "no-floating-network-connections",
168
+ });
169
+ export default noFloatingNetworkConnections;
170
+ //# sourceMappingURL=no-floating-network-connections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-floating-network-connections.js","sourceRoot":"","sources":["../../src/rules/no-floating-network-connections.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * Require object URLs to be retained so they can be revoked.
4
+ */
5
+ import { type TSESLint } from "@typescript-eslint/utils";
6
+ /** Rule implementation for `runtime-cleanup/no-floating-object-urls`. */
7
+ declare const noFloatingObjectUrls: TSESLint.RuleModule<"floatingObjectUrl", readonly []>;
8
+ export default noFloatingObjectUrls;
9
+ //# sourceMappingURL=no-floating-object-urls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-floating-object-urls.d.ts","sourceRoot":"","sources":["../../src/rules/no-floating-object-urls.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAEH,KAAK,QAAQ,EAEhB,MAAM,0BAA0B,CAAC;AAyElC,yEAAyE;AACzE,QAAA,MAAM,oBAAoB,EAAE,QAAQ,CAAC,UAAU,CAC3C,mBAAmB,EACnB,SAAS,EAAE,CA0Cb,CAAC;AAEH,eAAe,oBAAoB,CAAC"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * Require object URLs to be retained so they can be revoked.
4
+ */
5
+ import { AST_NODE_TYPES, } from "@typescript-eslint/utils";
6
+ import { collectStaticMemberPath, isDiscardedResourceExpression, } from "../_internal/floating-resource.js";
7
+ import { createRuleDocsUrl } from "../_internal/rule-docs-url.js";
8
+ import { getVariableInScopeChain } from "../_internal/scope-variable.js";
9
+ import { createTypedRule, } from "../_internal/typed-rule.js";
10
+ const globalUrlReceiverNames = ["globalThis", "self", "window"];
11
+ const globalUrlReceiverNameSet = new Set(globalUrlReceiverNames);
12
+ const getRootIdentifier = (node) => {
13
+ if (node.type === AST_NODE_TYPES.Identifier) {
14
+ return node;
15
+ }
16
+ return node.type === AST_NODE_TYPES.MemberExpression
17
+ ? getRootIdentifier(node.object)
18
+ : undefined;
19
+ };
20
+ const isShadowedIdentifier = (context, identifier) => {
21
+ const scope = context.sourceCode.getScope(identifier);
22
+ const variable = getVariableInScopeChain(scope, identifier.name);
23
+ return variable !== null && variable.defs.length > 0;
24
+ };
25
+ const isDirectUrlPath = (path) => path.length === 2 &&
26
+ path[0] === "URL" &&
27
+ path[1] === "createObjectURL";
28
+ const isGlobalUrlPath = (path) => path.length === 3 &&
29
+ globalUrlReceiverNameSet.has(path[0] ?? "") &&
30
+ path[1] === "URL" &&
31
+ path[2] === "createObjectURL";
32
+ const isObjectUrlCreateCall = (context, callee) => {
33
+ if (callee.type !== AST_NODE_TYPES.MemberExpression || callee.optional) {
34
+ return false;
35
+ }
36
+ const path = collectStaticMemberPath(callee);
37
+ if (path === undefined || (!isDirectUrlPath(path) && !isGlobalUrlPath(path))) {
38
+ return false;
39
+ }
40
+ const rootIdentifier = getRootIdentifier(callee.object);
41
+ return (rootIdentifier?.name !== "URL" ||
42
+ !isShadowedIdentifier(context, rootIdentifier));
43
+ };
44
+ /** Rule implementation for `runtime-cleanup/no-floating-object-urls`. */
45
+ const noFloatingObjectUrls = createTypedRule({
46
+ create(context) {
47
+ return {
48
+ CallExpression(node) {
49
+ if (!isObjectUrlCreateCall(context, node.callee) ||
50
+ !isDiscardedResourceExpression(node)) {
51
+ return;
52
+ }
53
+ context.report({
54
+ messageId: "floatingObjectUrl",
55
+ node,
56
+ });
57
+ },
58
+ };
59
+ },
60
+ defaultOptions: [],
61
+ meta: {
62
+ docs: {
63
+ description: "require object URLs to be retained so they can be revoked.",
64
+ recommended: true,
65
+ requiresTypeChecking: false,
66
+ runtimeCleanupConfigs: [
67
+ "runtime-cleanup.configs.recommended",
68
+ "runtime-cleanup.configs.recommended-type-checked",
69
+ "runtime-cleanup.configs.strict",
70
+ "runtime-cleanup.configs.all",
71
+ ],
72
+ url: createRuleDocsUrl("no-floating-object-urls"),
73
+ },
74
+ messages: {
75
+ floatingObjectUrl: "Store or return the object URL so URL.revokeObjectURL() can release the Blob or File when cleanup runs.",
76
+ },
77
+ schema: [],
78
+ type: "problem",
79
+ },
80
+ name: "no-floating-object-urls",
81
+ });
82
+ export default noFloatingObjectUrls;
83
+ //# sourceMappingURL=no-floating-object-urls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-floating-object-urls.js","sourceRoot":"","sources":["../../src/rules/no-floating-object-urls.ts"],"names":[],"mappings":"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"}