@clipboard-health/oxlint-plugin 1.2.0 → 1.3.0
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.
- package/README.md +15 -0
- package/package.json +3 -3
- package/src/index.d.ts +1 -0
- package/src/index.js +2 -0
- package/src/index.js.map +1 -1
- package/src/lib/rules/no-parallel-mongo-session-ops/index.d.ts +2 -0
- package/src/lib/rules/no-parallel-mongo-session-ops/index.js +262 -0
- package/src/lib/rules/no-parallel-mongo-session-ops/index.js.map +1 -0
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ ESLint.
|
|
|
12
12
|
- `enforce-ts-rest-in-controllers`
|
|
13
13
|
- `no-empty-boolean-call`
|
|
14
14
|
- `no-cross-contract-imports`
|
|
15
|
+
- `no-parallel-mongo-session-ops`
|
|
15
16
|
- `require-contract-fixture-construction`
|
|
16
17
|
- `require-contract-response-parse`
|
|
17
18
|
- `require-http-module-factory`
|
|
@@ -27,3 +28,17 @@ apply the shared controller, module, contract, and cross-contract-import scopes.
|
|
|
27
28
|
`no-empty-boolean-call`, `require-contract-response-parse`, and
|
|
28
29
|
`require-run-validators-with-upsert` are opt-in because their safe adoption scope is
|
|
29
30
|
repository-specific.
|
|
31
|
+
|
|
32
|
+
`no-parallel-mongo-session-ops` is also opt-in. Out of the box it covers `Promise.all`,
|
|
33
|
+
`Promise.allSettled`, `Promise.race`, and `Promise.any`. Repositories with their own
|
|
34
|
+
bounded-concurrency helpers must name them, or those call sites go unchecked:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
"@clipboard-health/no-parallel-mongo-session-ops": [
|
|
38
|
+
"warn",
|
|
39
|
+
{ additionalPrimitives: ["batchPromiseAllWithLimit", "batchPromiseAllSettledWithLimit"] },
|
|
40
|
+
],
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Exclude tests: app-level session objects such as `session.sessionUserId` share the name but are
|
|
44
|
+
unrelated to MongoDB sessions.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clipboard-health/oxlint-plugin",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Clipboard's Oxlint plugin.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"oxlint",
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
"access": "public"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@oxlint/plugins": "1.
|
|
23
|
+
"@oxlint/plugins": "1.79.0",
|
|
24
24
|
"tslib": "2.8.1"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"oxlint": "1.
|
|
27
|
+
"oxlint": "1.79.0"
|
|
28
28
|
},
|
|
29
29
|
"types": "./src/index.d.ts"
|
|
30
30
|
}
|
package/src/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export declare const rules: {
|
|
|
2
2
|
"enforce-ts-rest-in-controllers": import("@oxlint/plugins").Rule;
|
|
3
3
|
"no-empty-boolean-call": import("@oxlint/plugins").Rule;
|
|
4
4
|
"no-cross-contract-imports": import("@oxlint/plugins").Rule;
|
|
5
|
+
"no-parallel-mongo-session-ops": import("@oxlint/plugins").Rule;
|
|
5
6
|
"require-contract-fixture-construction": import("@oxlint/plugins").Rule;
|
|
6
7
|
"require-contract-response-parse": import("@oxlint/plugins").Rule;
|
|
7
8
|
"require-http-module-factory": import("@oxlint/plugins").Rule;
|
package/src/index.js
CHANGED
|
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const enforce_ts_rest_in_controllers_1 = tslib_1.__importDefault(require("./lib/rules/enforce-ts-rest-in-controllers"));
|
|
6
6
|
const no_cross_contract_imports_1 = tslib_1.__importDefault(require("./lib/rules/no-cross-contract-imports"));
|
|
7
7
|
const no_empty_boolean_call_1 = tslib_1.__importDefault(require("./lib/rules/no-empty-boolean-call"));
|
|
8
|
+
const no_parallel_mongo_session_ops_1 = tslib_1.__importDefault(require("./lib/rules/no-parallel-mongo-session-ops"));
|
|
8
9
|
const require_contract_fixture_construction_1 = tslib_1.__importDefault(require("./lib/rules/require-contract-fixture-construction"));
|
|
9
10
|
const require_contract_response_parse_1 = tslib_1.__importDefault(require("./lib/rules/require-contract-response-parse"));
|
|
10
11
|
const require_http_module_factory_1 = tslib_1.__importDefault(require("./lib/rules/require-http-module-factory"));
|
|
@@ -14,6 +15,7 @@ exports.rules = {
|
|
|
14
15
|
"enforce-ts-rest-in-controllers": enforce_ts_rest_in_controllers_1.default,
|
|
15
16
|
"no-empty-boolean-call": no_empty_boolean_call_1.default,
|
|
16
17
|
"no-cross-contract-imports": no_cross_contract_imports_1.default,
|
|
18
|
+
"no-parallel-mongo-session-ops": no_parallel_mongo_session_ops_1.default,
|
|
17
19
|
"require-contract-fixture-construction": require_contract_fixture_construction_1.default,
|
|
18
20
|
"require-contract-response-parse": require_contract_response_parse_1.default,
|
|
19
21
|
"require-http-module-factory": require_http_module_factory_1.default,
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/oxlint-plugin/src/index.ts"],"names":[],"mappings":";;;;AAAA,wHAAoF;AACpF,8GAA2E;AAC3E,sGAAmE;AACnE,sIAAmG;AACnG,0HAAuF;AACvF,kHAA+E;AAC/E,gIAA4F;AAC5F,0HAAsF;AAEzE,QAAA,KAAK,GAAG;IACnB,gCAAgC,EAAE,wCAA0B;IAC5D,uBAAuB,EAAE,+BAAkB;IAC3C,2BAA2B,EAAE,mCAAsB;IACnD,uCAAuC,EAAE,+CAAkC;IAC3E,iCAAiC,EAAE,yCAA4B;IAC/D,6BAA6B,EAAE,qCAAwB;IACvD,oCAAoC,EAAE,4CAA8B;IACpE,iCAAiC,EAAE,yCAA2B;CAC/D,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/oxlint-plugin/src/index.ts"],"names":[],"mappings":";;;;AAAA,wHAAoF;AACpF,8GAA2E;AAC3E,sGAAmE;AACnE,sHAAkF;AAClF,sIAAmG;AACnG,0HAAuF;AACvF,kHAA+E;AAC/E,gIAA4F;AAC5F,0HAAsF;AAEzE,QAAA,KAAK,GAAG;IACnB,gCAAgC,EAAE,wCAA0B;IAC5D,uBAAuB,EAAE,+BAAkB;IAC3C,2BAA2B,EAAE,mCAAsB;IACnD,+BAA+B,EAAE,uCAAyB;IAC1D,uCAAuC,EAAE,+CAAkC;IAC3E,iCAAiC,EAAE,yCAA4B;IAC/D,6BAA6B,EAAE,qCAAwB;IACvD,oCAAoC,EAAE,4CAA8B;IACpE,iCAAiC,EAAE,yCAA2B;CAC/D,CAAC"}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Rule to disallow parallel operations sharing one MongoDB transaction session.
|
|
5
|
+
*
|
|
6
|
+
* The MongoDB driver documents parallel operations inside a transaction as undefined behaviour.
|
|
7
|
+
* From `startTransaction` and `withTransaction` in the driver's `lib/sessions.js`:
|
|
8
|
+
*
|
|
9
|
+
* > Running operations in parallel is not supported during a transaction. The use of
|
|
10
|
+
* > `Promise.all`, `Promise.allSettled`, `Promise.race`, etc to parallelize operations inside a
|
|
11
|
+
* > transaction is undefined behaviour.
|
|
12
|
+
*
|
|
13
|
+
* In practice one branch aborts the transaction and its siblings, still in flight, fail with
|
|
14
|
+
* `Transaction with { txnNumber: N } has been aborted.`
|
|
15
|
+
*
|
|
16
|
+
* The rule reports a concurrency primitive that reaches a session declared *outside* it, meaning
|
|
17
|
+
* every branch shares one session. A session created *inside* the callback gives each branch its
|
|
18
|
+
* own and is not reported, which is the safe way to fan out.
|
|
19
|
+
*
|
|
20
|
+
* Oxlint JS plugins receive no type information, so a session is recognised by binding name or by
|
|
21
|
+
* `.session` member access rather than by the `ClientSession` type. Bindings are resolved through
|
|
22
|
+
* scope analysis, so same-named sessions in different scopes do not collide.
|
|
23
|
+
*
|
|
24
|
+
* Repositories with their own bounded-concurrency helpers should list them in
|
|
25
|
+
* `additionalPrimitives`; the defaults cover only the `Promise` combinators.
|
|
26
|
+
*
|
|
27
|
+
* The invariant is one sentence: a session is per-branch when a `map` callback creates it, and
|
|
28
|
+
* shared otherwise. Everything else follows from that — a callback parameter receives whatever was
|
|
29
|
+
* mapped over, an alias is the same session, a `flatMap` callback runs once per group rather than
|
|
30
|
+
* per task, and a session created in a scope that encloses the fan-out is shared.
|
|
31
|
+
*
|
|
32
|
+
* Known limitations. The rule is a net for the shapes people write, not a soundness proof, and
|
|
33
|
+
* cannot become one without type and dataflow information:
|
|
34
|
+
*
|
|
35
|
+
* - a session forwarded as an opaque options object through a call chain, or held on `this`, is
|
|
36
|
+
* invisible
|
|
37
|
+
* - a session reaching the fan-out through a helper the rule does not model is invisible
|
|
38
|
+
* - recognition is by binding name, so a session under an unlisted name is missed
|
|
39
|
+
*
|
|
40
|
+
* Prefer accepting a miss over reporting safe code: a false positive gets the rule switched off,
|
|
41
|
+
* which costs more than any single missed call site.
|
|
42
|
+
*/
|
|
43
|
+
const plugins_1 = require("@oxlint/plugins");
|
|
44
|
+
const findVariable_1 = require("../../internal/findVariable");
|
|
45
|
+
const SESSION_NAMES = new Set([
|
|
46
|
+
"session",
|
|
47
|
+
"mongoSession",
|
|
48
|
+
"transactionSession",
|
|
49
|
+
"clientSession",
|
|
50
|
+
"dbSession",
|
|
51
|
+
]);
|
|
52
|
+
const PROMISE_COMBINATORS = new Set(["all", "allSettled", "race", "any"]);
|
|
53
|
+
const TASK_LIST_METHODS = new Set(["map", "flatMap"]);
|
|
54
|
+
/**
|
|
55
|
+
* Only a `map` callback runs once per task. A `flatMap` callback runs once per group and can
|
|
56
|
+
* return many operations, so a session created there is shared by all of them.
|
|
57
|
+
*/
|
|
58
|
+
const PER_BRANCH_METHODS = new Set(["map"]);
|
|
59
|
+
function isWithin(inner, outer) {
|
|
60
|
+
return Number(inner[0]) >= Number(outer[0]) && Number(inner[1]) <= Number(outer[1]);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* A call plausibly produces a fresh session; a bare identifier or member expression is an alias of
|
|
64
|
+
* something that already exists.
|
|
65
|
+
*/
|
|
66
|
+
function createsSession(init) {
|
|
67
|
+
const expression = init?.type === "AwaitExpression" ? init.argument : init;
|
|
68
|
+
return expression?.type === "CallExpression" || expression?.type === "NewExpression";
|
|
69
|
+
}
|
|
70
|
+
/** A task list is the only initialiser worth following; anything else is unrelated data. */
|
|
71
|
+
function isTaskList(init) {
|
|
72
|
+
if (!init) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
if (init.type === "ArrayExpression") {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
return (init.type === "CallExpression" &&
|
|
79
|
+
init.callee.type === "MemberExpression" &&
|
|
80
|
+
!init.callee.computed &&
|
|
81
|
+
init.callee.property.type === "Identifier" &&
|
|
82
|
+
TASK_LIST_METHODS.has(init.callee.property.name));
|
|
83
|
+
}
|
|
84
|
+
const rule = (0, plugins_1.defineRule)({
|
|
85
|
+
meta: {
|
|
86
|
+
type: "problem",
|
|
87
|
+
docs: {
|
|
88
|
+
description: "Disallow parallel operations sharing one MongoDB transaction session",
|
|
89
|
+
url: "https://github.com/ClipboardHealth/core-utils/tree/main/packages/oxlint-plugin/src/lib/rules/no-parallel-mongo-session-ops",
|
|
90
|
+
},
|
|
91
|
+
schema: [
|
|
92
|
+
{
|
|
93
|
+
type: "object",
|
|
94
|
+
properties: {
|
|
95
|
+
additionalPrimitives: {
|
|
96
|
+
type: "array",
|
|
97
|
+
items: { type: "string" },
|
|
98
|
+
description: "Names of project-local helpers that run their tasks concurrently, for example a bounded-concurrency wrapper around Promise.all.",
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
additionalProperties: false,
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
messages: {
|
|
105
|
+
parallelSessionOps: "`{{ primitive }}` runs its operations in parallel on the `{{ name }}` transaction session, which the MongoDB driver documents as undefined behaviour. Await them sequentially, or give each branch its own session.",
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
create(context) {
|
|
109
|
+
const [options] = context.options;
|
|
110
|
+
const additionalPrimitives = new Set(options?.additionalPrimitives ?? []);
|
|
111
|
+
const parallelCalls = [];
|
|
112
|
+
const sessionReferences = [];
|
|
113
|
+
const identifierReferences = [];
|
|
114
|
+
const nonReferenceRanges = new Set();
|
|
115
|
+
/** Keyed by resolved binding, so same-named lists in sibling scopes stay distinct. */
|
|
116
|
+
const taskLists = new Map();
|
|
117
|
+
/**
|
|
118
|
+
* Bodies of `map`/`flatMap` callbacks: the only regions that run once per branch. A session
|
|
119
|
+
* created anywhere else inside the primitive, such as in an enclosing IIFE, is created once
|
|
120
|
+
* and shared.
|
|
121
|
+
*/
|
|
122
|
+
const taskCallbackRanges = [];
|
|
123
|
+
function resolve(identifier) {
|
|
124
|
+
return (0, findVariable_1.findVariable)(context.sourceCode, identifier);
|
|
125
|
+
}
|
|
126
|
+
function primitiveName(node) {
|
|
127
|
+
const { callee } = node;
|
|
128
|
+
if (callee.type === "Identifier" && additionalPrimitives.has(callee.name)) {
|
|
129
|
+
return callee.name;
|
|
130
|
+
}
|
|
131
|
+
if (callee.type === "MemberExpression" &&
|
|
132
|
+
!callee.computed &&
|
|
133
|
+
callee.object.type === "Identifier" &&
|
|
134
|
+
callee.object.name === "Promise" &&
|
|
135
|
+
callee.property.type === "Identifier" &&
|
|
136
|
+
PROMISE_COMBINATORS.has(callee.property.name)) {
|
|
137
|
+
return `Promise.${callee.property.name}`;
|
|
138
|
+
}
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* A configured helper taking a concurrency of 1 runs one task at a time, so it is already
|
|
143
|
+
* sequential and safe.
|
|
144
|
+
*/
|
|
145
|
+
function isSequential(node) {
|
|
146
|
+
const { callee } = node;
|
|
147
|
+
if (!(callee.type === "Identifier" && additionalPrimitives.has(callee.name))) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
return node.arguments.some((argument) => "value" in argument && argument.value === 1);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* A session is per-branch only when a task callback *creates* one. Neither declaration scope
|
|
154
|
+
* nor creation alone is proof: a callback parameter receives whatever the caller mapped over,
|
|
155
|
+
* an alias of an outer binding is the very same session, and a session created in a scope
|
|
156
|
+
* that encloses the fan-out is shared by every branch. All three stay reportable.
|
|
157
|
+
*/
|
|
158
|
+
function createsOwnSession(variable, range) {
|
|
159
|
+
return (variable?.defs.some((definition) => {
|
|
160
|
+
if (definition.type !== "Variable" || !isWithin(definition.name.range, range)) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
return (definition.node.type === "VariableDeclarator" && createsSession(definition.node.init));
|
|
164
|
+
}) === true);
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
CallExpression(node) {
|
|
168
|
+
const primitive = primitiveName(node);
|
|
169
|
+
if (primitive !== undefined && !isSequential(node)) {
|
|
170
|
+
parallelCalls.push({ node, primitive });
|
|
171
|
+
}
|
|
172
|
+
const { callee } = node;
|
|
173
|
+
if (callee.type === "MemberExpression" &&
|
|
174
|
+
!callee.computed &&
|
|
175
|
+
callee.property.type === "Identifier" &&
|
|
176
|
+
PER_BRANCH_METHODS.has(callee.property.name)) {
|
|
177
|
+
for (const argument of node.arguments) {
|
|
178
|
+
if (argument.type === "ArrowFunctionExpression" ||
|
|
179
|
+
argument.type === "FunctionExpression") {
|
|
180
|
+
taskCallbackRanges.push(argument.range);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
// A non-shorthand key, as in `{ session: workplaceId }`, is a label rather than a reference.
|
|
186
|
+
Property(node) {
|
|
187
|
+
if (!("key" in node) || !("shorthand" in node)) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (!node.shorthand && !node.computed && node.key.type === "Identifier") {
|
|
191
|
+
nonReferenceRanges.add(node.key.range.join(":"));
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
// `options.session` and `options?.session` carry the session in on an object.
|
|
195
|
+
MemberExpression(node) {
|
|
196
|
+
if (node.type !== "MemberExpression" || node.computed) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (node.property.type !== "Identifier") {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (node.property.name === "session") {
|
|
203
|
+
const object = node.object;
|
|
204
|
+
sessionReferences.push({
|
|
205
|
+
range: node.range,
|
|
206
|
+
variable: object.type === "Identifier" ? resolve(object) : undefined,
|
|
207
|
+
label: object.type === "Identifier" ? object.name : "session",
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
nonReferenceRanges.add(node.property.range.join(":"));
|
|
211
|
+
},
|
|
212
|
+
Identifier(node) {
|
|
213
|
+
const variable = resolve(node);
|
|
214
|
+
identifierReferences.push({ range: node.range, variable });
|
|
215
|
+
if (SESSION_NAMES.has(node.name)) {
|
|
216
|
+
sessionReferences.push({ range: node.range, variable, label: node.name });
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
VariableDeclarator(node) {
|
|
220
|
+
const { id, init } = node;
|
|
221
|
+
if (id.type !== "Identifier" || !isTaskList(init)) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const variable = resolve(id);
|
|
225
|
+
if (variable && init) {
|
|
226
|
+
taskLists.set(variable, init);
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
"Program:exit"() {
|
|
230
|
+
for (const { node, primitive } of parallelCalls) {
|
|
231
|
+
const argumentRanges = node.arguments.map((argument) => argument.range);
|
|
232
|
+
const searchRanges = [node.range];
|
|
233
|
+
// `const tasks = items.map(...)` before `Promise.all(tasks)` keeps the session out of
|
|
234
|
+
// the call site, so search where the list was built too.
|
|
235
|
+
for (const reference of identifierReferences) {
|
|
236
|
+
if (!argumentRanges.some((range) => isWithin(reference.range, range))) {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const taskList = reference.variable && taskLists.get(reference.variable);
|
|
240
|
+
if (taskList && !isWithin(taskList.range, node.range)) {
|
|
241
|
+
searchRanges.push(taskList.range);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// Only callbacks reached by this call can create a per-branch session.
|
|
245
|
+
const perBranchRanges = taskCallbackRanges.filter((callback) => searchRanges.some((range) => isWithin(callback, range)));
|
|
246
|
+
const shared = sessionReferences.find((reference) => searchRanges.some((range) => isWithin(reference.range, range)) &&
|
|
247
|
+
!nonReferenceRanges.has(reference.range.join(":")) &&
|
|
248
|
+
!perBranchRanges.some((range) => createsOwnSession(reference.variable, range)));
|
|
249
|
+
if (shared) {
|
|
250
|
+
context.report({
|
|
251
|
+
node,
|
|
252
|
+
messageId: "parallelSessionOps",
|
|
253
|
+
data: { primitive, name: shared.label },
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
exports.default = rule;
|
|
262
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../packages/oxlint-plugin/src/lib/rules/no-parallel-mongo-session-ops/index.ts"],"names":[],"mappings":"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"}
|