@jskit-ai/config-eslint 0.1.243 → 0.1.244
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/package.json +1 -1
- package/plugin/rules/actionExecuteShape.js +2 -7
- package/plugin/rules/collaboratorProps.js +5 -9
- package/plugin/rules/fixedResultShape.js +1 -5
- package/plugin/rules/noDualShape.js +1 -5
- package/plugin/rules/noFactorySpread.js +3 -7
- package/plugin/rules/requiredCollaborators.js +3 -2
- package/plugin/support.js +12 -0
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createReporter, isActionExecute, keyName, ruleMeta } from "../support.js";
|
|
1
|
+
import { createReporter, isActionExecute, keyName, ruleMeta, unwrapAwait, unwrapChain } from "../support.js";
|
|
2
2
|
|
|
3
3
|
// A callee a reader follows in one step: a name or a member chain, with no
|
|
4
4
|
// call inside it.
|
|
@@ -9,11 +9,6 @@ function isPlainCallee(node) {
|
|
|
9
9
|
return node.type === "MemberExpression" && isPlainCallee(node.object);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
function unwrapCall(node) {
|
|
13
|
-
const value = node.type === "AwaitExpression" ? node.argument : node;
|
|
14
|
-
return value.type === "ChainExpression" ? value.expression : value;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
12
|
// The shape problem of an action's execute, or null for
|
|
18
13
|
// `execute: (input, context) => service.method(…)`. Its parameters may
|
|
19
14
|
// destructure what must not reach the service (`({ workspaceSlug, ...payload },
|
|
@@ -34,7 +29,7 @@ function shapeProblem(value) {
|
|
|
34
29
|
if (value.type !== "ArrowFunctionExpression") {
|
|
35
30
|
return "notArrow";
|
|
36
31
|
}
|
|
37
|
-
const body =
|
|
32
|
+
const body = unwrapChain(unwrapAwait(value.body));
|
|
38
33
|
if (body.type !== "CallExpression" || !isPlainCallee(body.callee)) {
|
|
39
34
|
return "notOneCall";
|
|
40
35
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ABSENT_DEFAULT, CLIENT_GUIDE_URL, compactText, createReporter, keyName, ruleMeta } from "../support.js";
|
|
1
|
+
import { ABSENT_DEFAULT, CLIENT_GUIDE_URL, compactText, createReporter, keyName, ruleMeta, unwrapChain } from "../support.js";
|
|
2
2
|
|
|
3
3
|
// Prop types whose values are data: a call on one (`items.map()`) is not a call on a collaborator.
|
|
4
4
|
const DATA_TYPES = new Set(["Array", "String", "Number", "Boolean", "Date", "RegExp", "Symbol", "BigInt"]);
|
|
@@ -21,26 +21,22 @@ function declaredProps(node) {
|
|
|
21
21
|
return null;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
function unchain(node) {
|
|
25
|
-
return node?.type === "ChainExpression" ? node.expression : node;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
24
|
// The prop a call reaches through, or "": `props.x()`, `props.x.y()` or `props.x?.y()` in the script, `x()` or
|
|
29
25
|
// `x.y()` in the template.
|
|
30
26
|
function calledProp(callee, propsBinding, inTemplate) {
|
|
31
|
-
const target =
|
|
27
|
+
const target = unwrapChain(callee);
|
|
32
28
|
if (inTemplate) {
|
|
33
|
-
const root = target.type === "MemberExpression" ?
|
|
29
|
+
const root = target.type === "MemberExpression" ? unwrapChain(target.object) : target;
|
|
34
30
|
return root.type === "Identifier" ? root.name : "";
|
|
35
31
|
}
|
|
36
32
|
if (target.type !== "MemberExpression") {
|
|
37
33
|
return "";
|
|
38
34
|
}
|
|
39
|
-
const owner =
|
|
35
|
+
const owner = unwrapChain(target.object);
|
|
40
36
|
if (owner.type === "Identifier" && owner.name === propsBinding) {
|
|
41
37
|
return target.computed ? "" : target.property.name;
|
|
42
38
|
}
|
|
43
|
-
const root = owner.type === "MemberExpression" && !owner.computed ?
|
|
39
|
+
const root = owner.type === "MemberExpression" && !owner.computed ? unwrapChain(owner.object) : null;
|
|
44
40
|
return root?.type === "Identifier" && root.name === propsBinding ? owner.property.name : "";
|
|
45
41
|
}
|
|
46
42
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FUNCTION_TYPES, definedName, definitionOf, enclosingFunction } from "../factoryResults.js";
|
|
2
|
-
import { CLIENT_GUIDE_URL, createReporter, keyName, ruleMeta } from "../support.js";
|
|
2
|
+
import { CLIENT_GUIDE_URL, createReporter, keyName, ruleMeta, unwrapAwait } from "../support.js";
|
|
3
3
|
|
|
4
4
|
const RESULT_FACTORY = /^(create|use)[A-Z]/u;
|
|
5
5
|
|
|
@@ -25,10 +25,6 @@ function addsBehaviour(sourceCode, value) {
|
|
|
25
25
|
return definition?.type === "FunctionName" || (definition?.type === "Variable" && FUNCTION_TYPES.has(definition.node.init?.type));
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
function unwrapAwait(node) {
|
|
29
|
-
return node?.type === "AwaitExpression" ? node.argument : node;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
28
|
// The create*/use* call a wrapper's callback builds its result with, or null:
|
|
33
29
|
// `app.runWithContext(() => createRuntime(readers))` returns that runtime.
|
|
34
30
|
function callbackFactoryCall(call) {
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import { createReporter, ruleMeta } from "../support.js";
|
|
1
|
+
import { createReporter, ruleMeta, unwrapChain } from "../support.js";
|
|
2
2
|
|
|
3
3
|
const REFERENCE_TYPES = new Set(["Identifier", "MemberExpression", "ThisExpression"]);
|
|
4
4
|
|
|
5
|
-
function unwrapChain(node) {
|
|
6
|
-
return node?.type === "ChainExpression" ? node.expression : node;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
5
|
// A reference's text with optional links read as plain ones, so `a?.b` and
|
|
10
6
|
// `a.b` name the same value.
|
|
11
7
|
function referenceText(sourceCode, node) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CREATE_NAME, FUNCTION_TYPES, definedName, definitionOf, enclosingFunction, holdsBehaviour, localFunction, returnsOnlyData } from "../factoryResults.js";
|
|
2
|
-
import { createReporter, isClientLint, isFreezeCall, ruleMeta } from "../support.js";
|
|
2
|
+
import { createReporter, isClientLint, isFreezeCall, ruleMeta, unwrapAwait } from "../support.js";
|
|
3
3
|
|
|
4
4
|
// A decorator over the JSKIT CRUD service or repository spreads it: its
|
|
5
5
|
// members are the contract's.
|
|
@@ -7,17 +7,13 @@ const CRUD_DECORATOR = /^decorate\w*(?:Service|Repository)$/u;
|
|
|
7
7
|
// In client code a composable's result is an API too.
|
|
8
8
|
const CLIENT_FACTORY_NAME = /^(create|use)[A-Z]/u;
|
|
9
9
|
|
|
10
|
-
function unwrap(node) {
|
|
11
|
-
return node?.type === "AwaitExpression" ? node.argument : node;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
10
|
// The create* call a spread argument comes from: the call itself, or the call
|
|
15
11
|
// that initialised the variable it reads.
|
|
16
12
|
function factoryCall(sourceCode, argument) {
|
|
17
|
-
const value =
|
|
13
|
+
const value = unwrapAwait(argument);
|
|
18
14
|
if (value.type === "Identifier") {
|
|
19
15
|
const definition = definitionOf(sourceCode, value);
|
|
20
|
-
const init =
|
|
16
|
+
const init = unwrapAwait(definition?.type === "Variable" ? definition.node.init : null);
|
|
21
17
|
return init?.type === "CallExpression" ? { call: init, via: value.name } : null;
|
|
22
18
|
}
|
|
23
19
|
return value.type === "CallExpression" ? { call: value, via: "" } : null;
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
isFactory,
|
|
8
8
|
receivingFunction,
|
|
9
9
|
ruleMeta,
|
|
10
|
+
unwrapChain,
|
|
10
11
|
walk
|
|
11
12
|
} from "../support.js";
|
|
12
13
|
|
|
@@ -100,7 +101,7 @@ const requiredCollaborators = Object.freeze({
|
|
|
100
101
|
}
|
|
101
102
|
function checkProbe(node) {
|
|
102
103
|
const probed = probedArgument(node);
|
|
103
|
-
const argument = probed
|
|
104
|
+
const argument = unwrapChain(probed);
|
|
104
105
|
const receiver = argument?.type === "Identifier" ? receivingFunction(context, node, argument.name) : null;
|
|
105
106
|
if (argument?.type === "MemberExpression" || (receiver && isFactory(receiver, client))) {
|
|
106
107
|
report(node, "method-probe", "methodProbe", { probe: sourceCode.getText(probed) });
|
|
@@ -109,7 +110,7 @@ const requiredCollaborators = Object.freeze({
|
|
|
109
110
|
// A template has no parameters of its own, so only member probes are read there.
|
|
110
111
|
function checkTemplateProbe(node) {
|
|
111
112
|
const probed = probedArgument(node);
|
|
112
|
-
const argument = probed
|
|
113
|
+
const argument = unwrapChain(probed);
|
|
113
114
|
if (argument?.type === "MemberExpression") {
|
|
114
115
|
report(node, "method-probe", "methodProbe", { probe: sourceCode.getText(probed) });
|
|
115
116
|
}
|
package/plugin/support.js
CHANGED
|
@@ -94,6 +94,16 @@ function keyName(property) {
|
|
|
94
94
|
return property?.key?.name || property?.key?.value;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
// The expression an optional chain wraps, so `a?.b` reads as `a.b`; any other node as it is.
|
|
98
|
+
function unwrapChain(node) {
|
|
99
|
+
return node?.type === "ChainExpression" ? node.expression : node;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// The value an `await` waits for, so `await x` reads as `x`; any other node as it is.
|
|
103
|
+
function unwrapAwait(node) {
|
|
104
|
+
return node?.type === "AwaitExpression" ? node.argument : node;
|
|
105
|
+
}
|
|
106
|
+
|
|
97
107
|
// The node a reader sees as the function: a method's property or class member,
|
|
98
108
|
// otherwise the function itself.
|
|
99
109
|
function functionSite(fn) {
|
|
@@ -373,5 +383,7 @@ export {
|
|
|
373
383
|
keyName,
|
|
374
384
|
receivingFunction,
|
|
375
385
|
ruleMeta,
|
|
386
|
+
unwrapAwait,
|
|
387
|
+
unwrapChain,
|
|
376
388
|
walk
|
|
377
389
|
};
|