@trebired/code-discipline 3.4.0 → 3.4.2
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/CHANGELOG.md +12 -0
- package/README.md +13 -4
- package/dist/checks/rules/dry/behavior/conditions.d.ts +6 -0
- package/dist/checks/rules/dry/behavior/conditions.d.ts.map +1 -0
- package/dist/checks/rules/dry/behavior/conditions.js +171 -0
- package/dist/checks/rules/dry/behavior/conditions.js.map +1 -0
- package/dist/checks/rules/dry/behavior/expressions.d.ts +5 -0
- package/dist/checks/rules/dry/behavior/expressions.d.ts.map +1 -0
- package/dist/checks/rules/dry/behavior/expressions.js +179 -0
- package/dist/checks/rules/dry/behavior/expressions.js.map +1 -0
- package/dist/checks/rules/dry/behavior/index.d.ts +6 -0
- package/dist/checks/rules/dry/behavior/index.d.ts.map +1 -0
- package/dist/checks/rules/dry/behavior/index.js +32 -0
- package/dist/checks/rules/dry/behavior/index.js.map +1 -0
- package/dist/checks/rules/dry/behavior/model.d.ts +29 -0
- package/dist/checks/rules/dry/behavior/model.d.ts.map +1 -0
- package/dist/checks/rules/dry/behavior/model.js +185 -0
- package/dist/checks/rules/dry/behavior/model.js.map +1 -0
- package/dist/checks/rules/dry/behavior/statements.d.ts +6 -0
- package/dist/checks/rules/dry/behavior/statements.d.ts.map +1 -0
- package/dist/checks/rules/dry/behavior/statements.js +74 -0
- package/dist/checks/rules/dry/behavior/statements.js.map +1 -0
- package/dist/checks/rules/dry/candidates.d.ts +2 -1
- package/dist/checks/rules/dry/candidates.d.ts.map +1 -1
- package/dist/checks/rules/dry/candidates.js +3 -2
- package/dist/checks/rules/dry/candidates.js.map +1 -1
- package/dist/checks/rules/dry/fingerprint.d.ts +2 -0
- package/dist/checks/rules/dry/fingerprint.d.ts.map +1 -1
- package/dist/checks/rules/dry/fingerprint.js +4 -0
- package/dist/checks/rules/dry/fingerprint.js.map +1 -1
- package/dist/checks/rules/dry/index.js +1 -1
- package/dist/checks/rules/dry/index.js.map +1 -1
- package/dist/checks/rules/dry/matching.d.ts +3 -2
- package/dist/checks/rules/dry/matching.d.ts.map +1 -1
- package/dist/checks/rules/dry/matching.js +28 -18
- package/dist/checks/rules/dry/matching.js.map +1 -1
- package/dist/checks/rules/dry/model.d.ts +1 -0
- package/dist/checks/rules/dry/model.d.ts.map +1 -1
- package/dist/checks/rules/dry/model.js.map +1 -1
- package/dist/checks/rules/dry/similarity.d.ts +2 -2
- package/dist/checks/rules/dry/similarity.d.ts.map +1 -1
- package/dist/checks/rules/dry/similarity.js +4 -5
- package/dist/checks/rules/dry/similarity.js.map +1 -1
- package/dist/checks/types.d.ts +2 -0
- package/dist/checks/types.d.ts.map +1 -1
- package/dist/config/normalize/rule-options.d.ts.map +1 -1
- package/dist/config/normalize/rule-options.js +12 -0
- package/dist/config/normalize/rule-options.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@trebired/code-discipline` will be documented here.
|
|
4
4
|
|
|
5
|
+
## 3.4.2
|
|
6
|
+
|
|
7
|
+
- Added normalized behavioral fingerprints for simple pure `dry` functions, so equivalent implementations can be grouped despite different names, parameters, locals, formatting, or expression-vs-block structure.
|
|
8
|
+
- Normalized common equivalent helper forms including nullish fallbacks, const-then-return wrappers, branch returns, finite number guards, and object guard checks while preserving behavior-changing distinctions.
|
|
9
|
+
- Added the `normalized-behavior` DRY signal and fixtures covering representative text, number, clamp, and object helpers without hardcoding project-specific names or paths.
|
|
10
|
+
|
|
11
|
+
## 3.4.1
|
|
12
|
+
|
|
13
|
+
- Added `dry.minDuplicateCharacters`, defaulting to `0`, so DRY duplicate detection no longer has a hidden minimum function size.
|
|
14
|
+
- Applied the configurable threshold consistently across exact-normalized, matching-name, and similar-structure DRY signals.
|
|
15
|
+
- Documented the new DRY threshold and kept this repository's own self-check threshold explicit at `300`.
|
|
16
|
+
|
|
5
17
|
## 3.4.0
|
|
6
18
|
|
|
7
19
|
- Rendered `dry` duplicate groups in CLI output with the duplicated function names, file paths, line numbers, confidence, and `signals: ...` metadata.
|
package/README.md
CHANGED
|
@@ -162,7 +162,9 @@ export default defineCodeDisciplineConfig({
|
|
|
162
162
|
aliasPrefix: "#",
|
|
163
163
|
},
|
|
164
164
|
},
|
|
165
|
-
dry: {
|
|
165
|
+
dry: {
|
|
166
|
+
minDuplicateCharacters: 0,
|
|
167
|
+
},
|
|
166
168
|
},
|
|
167
169
|
});
|
|
168
170
|
```
|
|
@@ -438,20 +440,27 @@ code-discipline fix remove-comments
|
|
|
438
440
|
Reports duplicate function groups across the configured source tree.
|
|
439
441
|
|
|
440
442
|
- exact normalized structure is reported with 100% confidence
|
|
443
|
+
- equivalent normalized behavior in simple pure functions is reported with 100% confidence
|
|
441
444
|
- matching function names are reported with 100% confidence
|
|
442
445
|
- highly similar normalized function structure is reported as a likely duplicate
|
|
443
|
-
-
|
|
446
|
+
- `minDuplicateCharacters` defaults to `0`; raise it if you only want larger duplicate functions
|
|
447
|
+
- whitespace, comments, function names, parameter names, and local identifier names do not matter
|
|
448
|
+
- expression bodies, single-return blocks, simple const-then-return blocks, nullish fallback forms, finite number guards, and object guard branches are normalized when their behavior matches
|
|
444
449
|
- reports are neutral groups, not "file A duplicates file B"
|
|
445
450
|
- `dry` is check-only
|
|
446
451
|
|
|
447
452
|
```ts
|
|
448
|
-
dry: {
|
|
453
|
+
dry: {
|
|
454
|
+
minDuplicateCharacters: 0,
|
|
455
|
+
}
|
|
449
456
|
```
|
|
450
457
|
|
|
451
458
|
Example output:
|
|
452
459
|
|
|
453
460
|
```txt
|
|
454
|
-
dry
|
|
461
|
+
dry duplicate function group: 2 functions, confidence 1, signals: exact-normalized, normalized-behavior, similar-structure
|
|
462
|
+
- src/one.ts:1 buildUserLabel
|
|
463
|
+
- src/two.ts:1 formatUserLabel
|
|
455
464
|
```
|
|
456
465
|
|
|
457
466
|
## Lifecycle Hooks
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import type { BehaviorContext, BehaviorExpression } from "./model.js";
|
|
3
|
+
declare function normalizeCondition(node: ts.Node, context: BehaviorContext, sourceFile: ts.SourceFile): BehaviorExpression | undefined;
|
|
4
|
+
declare function normalizeConditional(condition: BehaviorExpression, whenTrue: BehaviorExpression, whenFalse: BehaviorExpression): BehaviorExpression;
|
|
5
|
+
export { normalizeCondition, normalizeConditional };
|
|
6
|
+
//# sourceMappingURL=conditions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conditions.d.ts","sourceRoot":"","sources":["../../../../../src/checks/rules/dry/behavior/conditions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAkBtE,iBAAS,kBAAkB,CACzB,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,OAAO,EAAE,eAAe,EACxB,UAAU,EAAE,EAAE,CAAC,UAAU,GACxB,kBAAkB,GAAG,SAAS,CAkBhC;AA+DD,iBAAS,oBAAoB,CAC3B,SAAS,EAAE,kBAAkB,EAC7B,QAAQ,EAAE,kBAAkB,EAC5B,SAAS,EAAE,kBAAkB,GAC5B,kBAAkB,CASpB;AAyID,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,CAAC"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { expressionsEqual, flattenBinary, inferSingleReplacement, invertCondition, isBooleanExpression, isComparisonOperator, isEqualityOperator, isTagged, normalizeAnd, normalizeComparison, positiveEqualityOperator, reduceExpression, replaceExpression, } from "./model.js";
|
|
3
|
+
import { normalizeExpression } from "./expressions.js";
|
|
4
|
+
function normalizeCondition(node, context, sourceFile) {
|
|
5
|
+
const unwrapped = unwrapCondition(node);
|
|
6
|
+
if (unwrapped !== node)
|
|
7
|
+
return normalizeCondition(unwrapped, context, sourceFile);
|
|
8
|
+
if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.ExclamationToken) {
|
|
9
|
+
const operand = normalizeCondition(node.operand, context, sourceFile);
|
|
10
|
+
return operand === undefined ? undefined : invertCondition(operand);
|
|
11
|
+
}
|
|
12
|
+
const nullishGroup = normalizeNullishGroup(node, context, sourceFile);
|
|
13
|
+
if (nullishGroup !== undefined)
|
|
14
|
+
return nullishGroup;
|
|
15
|
+
if (ts.isBinaryExpression(node)) {
|
|
16
|
+
return normalizeBinaryCondition(node, context, sourceFile);
|
|
17
|
+
}
|
|
18
|
+
const expression = normalizeExpression(node, context, sourceFile);
|
|
19
|
+
return expression === undefined || isBooleanExpression(expression) ? expression : ["truthy", expression];
|
|
20
|
+
}
|
|
21
|
+
function unwrapCondition(node) {
|
|
22
|
+
if (ts.isParenthesizedExpression(node)
|
|
23
|
+
|| ts.isAsExpression(node)
|
|
24
|
+
|| ts.isTypeAssertionExpression(node)
|
|
25
|
+
|| ts.isNonNullExpression(node)
|
|
26
|
+
|| ts.isSatisfiesExpression(node)) {
|
|
27
|
+
return node.expression;
|
|
28
|
+
}
|
|
29
|
+
return node;
|
|
30
|
+
}
|
|
31
|
+
function normalizeBinaryCondition(node, context, sourceFile) {
|
|
32
|
+
if (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) {
|
|
33
|
+
return normalizeLogicalAnd(node, context, sourceFile);
|
|
34
|
+
}
|
|
35
|
+
if (node.operatorToken.kind === ts.SyntaxKind.BarBarToken) {
|
|
36
|
+
return normalizeLogicalOr(node, context, sourceFile);
|
|
37
|
+
}
|
|
38
|
+
if (isEqualityOperator(node.operatorToken.kind)) {
|
|
39
|
+
return normalizeEqualityCondition(node, context, sourceFile);
|
|
40
|
+
}
|
|
41
|
+
if (isComparisonOperator(node.operatorToken.kind)) {
|
|
42
|
+
const left = normalizeExpression(node.left, context, sourceFile);
|
|
43
|
+
const right = normalizeExpression(node.right, context, sourceFile);
|
|
44
|
+
return left === undefined || right === undefined
|
|
45
|
+
? undefined
|
|
46
|
+
: ["compare", ts.tokenToString(node.operatorToken.kind) ?? String(node.operatorToken.kind), left, right];
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
function normalizeLogicalAnd(node, context, sourceFile) {
|
|
51
|
+
const terms = flattenBinary(node, ts.SyntaxKind.AmpersandAmpersandToken)
|
|
52
|
+
.map((term) => normalizeCondition(term, context, sourceFile));
|
|
53
|
+
return terms.some((term) => term === undefined) ? undefined : normalizeAnd(terms);
|
|
54
|
+
}
|
|
55
|
+
function normalizeLogicalOr(node, context, sourceFile) {
|
|
56
|
+
const terms = flattenBinary(node, ts.SyntaxKind.BarBarToken)
|
|
57
|
+
.map((term) => normalizeCondition(term, context, sourceFile));
|
|
58
|
+
if (terms.some((term) => term === undefined))
|
|
59
|
+
return undefined;
|
|
60
|
+
return invertCondition(normalizeAnd(terms.map(invertCondition)));
|
|
61
|
+
}
|
|
62
|
+
function normalizeConditional(condition, whenTrue, whenFalse) {
|
|
63
|
+
if (isTagged(condition, "not")) {
|
|
64
|
+
return normalizeConditional(condition[1], whenFalse, whenTrue);
|
|
65
|
+
}
|
|
66
|
+
const coalesce = normalizeCoalesceConditional(condition, whenTrue, whenFalse);
|
|
67
|
+
if (coalesce)
|
|
68
|
+
return coalesce;
|
|
69
|
+
return reduceExpression(["conditional", condition, whenTrue, whenFalse]);
|
|
70
|
+
}
|
|
71
|
+
function normalizeCoalesceConditional(condition, whenTrue, whenFalse) {
|
|
72
|
+
if (!isTagged(condition, "nullish"))
|
|
73
|
+
return undefined;
|
|
74
|
+
const checked = condition[1];
|
|
75
|
+
const fallback = inferCoalesceFallback(checked, whenTrue, whenFalse);
|
|
76
|
+
if (fallback !== undefined)
|
|
77
|
+
return reduceExpression(replaceExpression(whenFalse, checked, ["coalesce", checked, fallback]));
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
function inferCoalesceFallback(checked, whenNullish, whenPresent) {
|
|
81
|
+
if (expressionsEqual(checked, whenPresent))
|
|
82
|
+
return whenNullish;
|
|
83
|
+
const structural = inferSingleReplacement(whenPresent, whenNullish, checked);
|
|
84
|
+
if (structural !== undefined)
|
|
85
|
+
return structural;
|
|
86
|
+
const foldedNullishResult = reduceExpression(replaceExpression(whenPresent, checked, whenNullish));
|
|
87
|
+
return expressionsEqual(foldedNullishResult, whenNullish) ? whenNullish : undefined;
|
|
88
|
+
}
|
|
89
|
+
function normalizeEqualityCondition(node, context, sourceFile) {
|
|
90
|
+
const nullish = normalizeNullishGroup(node, context, sourceFile);
|
|
91
|
+
if (nullish !== undefined)
|
|
92
|
+
return nullish;
|
|
93
|
+
const left = normalizeExpression(node.left, context, sourceFile);
|
|
94
|
+
const right = normalizeExpression(node.right, context, sourceFile);
|
|
95
|
+
if (left === undefined || right === undefined)
|
|
96
|
+
return undefined;
|
|
97
|
+
const equality = normalizeComparison(positiveEqualityOperator(node.operatorToken.kind), left, right);
|
|
98
|
+
return node.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken
|
|
99
|
+
|| node.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken
|
|
100
|
+
? invertCondition(equality)
|
|
101
|
+
: equality;
|
|
102
|
+
}
|
|
103
|
+
function normalizeNullishGroup(node, context, sourceFile) {
|
|
104
|
+
if (!ts.isBinaryExpression(node))
|
|
105
|
+
return undefined;
|
|
106
|
+
if (node.operatorToken.kind === ts.SyntaxKind.EqualsEqualsToken || node.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken) {
|
|
107
|
+
const equality = normalizeNullishEquality(node, context, sourceFile);
|
|
108
|
+
if (!equality)
|
|
109
|
+
return undefined;
|
|
110
|
+
return node.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken ? invertCondition(equality) : equality;
|
|
111
|
+
}
|
|
112
|
+
if (node.operatorToken.kind !== ts.SyntaxKind.BarBarToken && node.operatorToken.kind !== ts.SyntaxKind.AmpersandAmpersandToken) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
return normalizeStrictNullishGroup(node, context, sourceFile);
|
|
116
|
+
}
|
|
117
|
+
function normalizeStrictNullishGroup(node, context, sourceFile) {
|
|
118
|
+
const parts = flattenBinary(node, node.operatorToken.kind)
|
|
119
|
+
.map((part) => normalizeStrictNullishEquality(part, context, sourceFile));
|
|
120
|
+
if (parts.some((part) => part === undefined))
|
|
121
|
+
return undefined;
|
|
122
|
+
const first = parts[0];
|
|
123
|
+
const sameExpression = parts.every((part) => expressionsEqual(part.expression, first.expression));
|
|
124
|
+
const hasNull = parts.some((part) => part.kind === "null");
|
|
125
|
+
const hasUndefined = parts.some((part) => part.kind === "undefined");
|
|
126
|
+
if (!sameExpression || !hasNull || !hasUndefined)
|
|
127
|
+
return undefined;
|
|
128
|
+
const isNullish = node.operatorToken.kind === ts.SyntaxKind.BarBarToken && parts.every((part) => !part.negated);
|
|
129
|
+
const isNotNullish = node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken && parts.every((part) => part.negated);
|
|
130
|
+
if (!isNullish && !isNotNullish)
|
|
131
|
+
return undefined;
|
|
132
|
+
const nullish = ["nullish", first.expression];
|
|
133
|
+
return isNotNullish ? invertCondition(nullish) : nullish;
|
|
134
|
+
}
|
|
135
|
+
function normalizeNullishEquality(node, context, sourceFile) {
|
|
136
|
+
const leftNull = isNullLiteral(node.left);
|
|
137
|
+
const rightNull = isNullLiteral(node.right);
|
|
138
|
+
if (!leftNull && !rightNull)
|
|
139
|
+
return undefined;
|
|
140
|
+
const expression = normalizeExpression(leftNull ? node.right : node.left, context, sourceFile);
|
|
141
|
+
return expression === undefined ? undefined : ["nullish", expression];
|
|
142
|
+
}
|
|
143
|
+
function normalizeStrictNullishEquality(node, context, sourceFile) {
|
|
144
|
+
if (!ts.isBinaryExpression(node) || !isEqualityOperator(node.operatorToken.kind))
|
|
145
|
+
return undefined;
|
|
146
|
+
const leftKind = nullishLiteralKind(node.left);
|
|
147
|
+
const rightKind = nullishLiteralKind(node.right);
|
|
148
|
+
if (!leftKind && !rightKind)
|
|
149
|
+
return undefined;
|
|
150
|
+
const expression = normalizeExpression(leftKind ? node.right : node.left, context, sourceFile);
|
|
151
|
+
if (expression === undefined)
|
|
152
|
+
return undefined;
|
|
153
|
+
return {
|
|
154
|
+
expression,
|
|
155
|
+
kind: leftKind ?? rightKind,
|
|
156
|
+
negated: node.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken
|
|
157
|
+
|| node.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function isNullLiteral(node) {
|
|
161
|
+
return node.kind === ts.SyntaxKind.NullKeyword;
|
|
162
|
+
}
|
|
163
|
+
function nullishLiteralKind(node) {
|
|
164
|
+
if (node.kind === ts.SyntaxKind.NullKeyword)
|
|
165
|
+
return "null";
|
|
166
|
+
if (ts.isIdentifier(node) && node.text === "undefined")
|
|
167
|
+
return "undefined";
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
export { normalizeCondition, normalizeConditional };
|
|
171
|
+
//# sourceMappingURL=conditions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conditions.js","sourceRoot":"","sources":["../../../../../src/checks/rules/dry/behavior/conditions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAG5B,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,QAAQ,EACR,YAAY,EACZ,mBAAmB,EACnB,wBAAwB,EACxB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,SAAS,kBAAkB,CACzB,IAAa,EACb,OAAwB,EACxB,UAAyB;IAEzB,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,kBAAkB,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAElF,IAAI,EAAE,CAAC,uBAAuB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,KAAK,EAAE,CAAC,UAAU,CAAC,gBAAgB,EAAE,CAAC;QACzF,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QACtE,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,YAAY,GAAG,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACtE,IAAI,YAAY,KAAK,SAAS;QAAE,OAAO,YAAY,CAAC;IAEpD,IAAI,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,OAAO,wBAAwB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC7D,CAAC;IAED,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAClE,OAAO,UAAU,KAAK,SAAS,IAAI,mBAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;AAC3G,CAAC;AAED,SAAS,eAAe,CAAC,IAAa;IACpC,IAAI,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC;WACjC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC;WACvB,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC;WAClC,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC;WAC5B,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,wBAAwB,CAC/B,IAAyB,EACzB,OAAwB,EACxB,UAAyB;IAEzB,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,uBAAuB,EAAE,CAAC;QACtE,OAAO,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACxD,CAAC;IAED,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;QAC1D,OAAO,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,OAAO,0BAA0B,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC/D,CAAC;IAED,IAAI,oBAAoB,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QACjE,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QACnE,OAAO,IAAI,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS;YAC9C,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAC7G,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,mBAAmB,CAC1B,IAAyB,EACzB,OAAwB,EACxB,UAAyB;IAEzB,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,uBAAuB,CAAC;SACrE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;IAChE,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,KAA6B,CAAC,CAAC;AAC5G,CAAC;AAED,SAAS,kBAAkB,CACzB,IAAyB,EACzB,OAAwB,EACxB,UAAyB;IAEzB,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC;SACzD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;IAChE,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/D,OAAO,eAAe,CAAC,YAAY,CAAE,KAA8B,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED,SAAS,oBAAoB,CAC3B,SAA6B,EAC7B,QAA4B,EAC5B,SAA6B;IAE7B,IAAI,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,oBAAoB,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,QAAQ,GAAG,4BAA4B,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC9E,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,OAAO,gBAAgB,CAAC,CAAC,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,SAAS,4BAA4B,CACnC,SAA6B,EAC7B,QAA4B,EAC5B,SAA6B;IAE7B,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAEtD,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,QAAQ,GAAG,qBAAqB,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IACrE,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,gBAAgB,CAAC,iBAAiB,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAE5H,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,qBAAqB,CAC5B,OAA2B,EAC3B,WAA+B,EAC/B,WAA+B;IAE/B,IAAI,gBAAgB,CAAC,OAAO,EAAE,WAAW,CAAC;QAAE,OAAO,WAAW,CAAC;IAE/D,MAAM,UAAU,GAAG,sBAAsB,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IAC7E,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,UAAU,CAAC;IAEhD,MAAM,mBAAmB,GAAG,gBAAgB,CAAC,iBAAiB,CAAC,WAAW,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;IACnG,OAAO,gBAAgB,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;AACtF,CAAC;AAED,SAAS,0BAA0B,CACjC,IAAyB,EACzB,OAAwB,EACxB,UAAyB;IAEzB,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACjE,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IAE1C,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACjE,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACnE,IAAI,IAAI,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAEhE,MAAM,QAAQ,GAAG,mBAAmB,CAAC,wBAAwB,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACrG,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,4BAA4B;WACxE,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,sBAAsB;QACnE,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC;QAC3B,CAAC,CAAC,QAAQ,CAAC;AACf,CAAC;AAED,SAAS,qBAAqB,CAC5B,IAAa,EACb,OAAwB,EACxB,UAAyB;IAEzB,IAAI,CAAC,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAEnD,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,iBAAiB,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,sBAAsB,EAAE,CAAC;QACpI,MAAM,QAAQ,GAAG,wBAAwB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QACrE,IAAI,CAAC,QAAQ;YAAE,OAAO,SAAS,CAAC;QAChC,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IACjH,CAAC;IAED,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,uBAAuB,EAAE,CAAC;QAC/H,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,2BAA2B,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,2BAA2B,CAClC,IAAyB,EACzB,OAAwB,EACxB,UAAyB;IAEzB,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;SACvD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,8BAA8B,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;IAC5E,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAE/D,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;IACxB,MAAM,cAAc,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IACnG,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;IAC5D,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAK,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;IACtE,IAAI,CAAC,cAAc,IAAI,CAAC,OAAO,IAAI,CAAC,YAAY;QAAE,OAAO,SAAS,CAAC;IAEnE,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAK,CAAC,OAAO,CAAC,CAAC;IACjH,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,uBAAuB,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAK,CAAC,OAAO,CAAC,CAAC;IAC/H,IAAI,CAAC,SAAS,IAAI,CAAC,YAAY;QAAE,OAAO,SAAS,CAAC;IAElD,MAAM,OAAO,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC9C,OAAO,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AAC3D,CAAC;AAED,SAAS,wBAAwB,CAC/B,IAAyB,EACzB,OAAwB,EACxB,UAAyB;IAEzB,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,IAAI,CAAC,QAAQ,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IAE9C,MAAM,UAAU,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC/F,OAAO,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,8BAA8B,CACrC,IAAa,EACb,OAAwB,EACxB,UAAyB;IAEzB,IAAI,CAAC,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAEnG,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjD,IAAI,CAAC,QAAQ,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IAE9C,MAAM,UAAU,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC/F,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAE/C,OAAO;QACL,UAAU;QACV,IAAI,EAAE,QAAQ,IAAI,SAAU;QAC5B,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,4BAA4B;eAC1E,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,sBAAsB;KACtE,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,IAAa;IAClC,OAAO,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC;AACjD,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAa;IACvC,IAAI,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW;QAAE,OAAO,MAAM,CAAC;IAC3D,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,WAAW,CAAC;IAC3E,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import type { BehaviorContext, BehaviorExpression } from "./model.js";
|
|
3
|
+
declare function normalizeExpression(node: ts.Node | undefined, context: BehaviorContext, sourceFile: ts.SourceFile): BehaviorExpression | undefined;
|
|
4
|
+
export { normalizeExpression };
|
|
5
|
+
//# sourceMappingURL=expressions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expressions.d.ts","sourceRoot":"","sources":["../../../../../src/checks/rules/dry/behavior/expressions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAG5B,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAQtE,iBAAS,mBAAmB,CAC1B,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,SAAS,EACzB,OAAO,EAAE,eAAe,EACxB,UAAU,EAAE,EAAE,CAAC,UAAU,GACxB,kBAAkB,GAAG,SAAS,CAgBhC;AA6ND,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { SAFE_GLOBAL_IDENTIFIERS } from "../serialize/context.js";
|
|
3
|
+
import { isComparisonOperator, isLogicalOperator, isNamedGlobal, } from "./model.js";
|
|
4
|
+
import { normalizeCondition, normalizeConditional } from "./conditions.js";
|
|
5
|
+
function normalizeExpression(node, context, sourceFile) {
|
|
6
|
+
if (!node)
|
|
7
|
+
return undefined;
|
|
8
|
+
const wrapped = normalizeWrappedExpression(node, context, sourceFile);
|
|
9
|
+
if (wrapped !== undefined)
|
|
10
|
+
return wrapped;
|
|
11
|
+
const primitive = normalizePrimitiveExpression(node, context);
|
|
12
|
+
if (primitive !== undefined)
|
|
13
|
+
return primitive;
|
|
14
|
+
const container = normalizeContainerExpression(node, context, sourceFile);
|
|
15
|
+
if (container !== undefined)
|
|
16
|
+
return container;
|
|
17
|
+
const access = normalizeAccessExpression(node, context, sourceFile);
|
|
18
|
+
if (access !== undefined)
|
|
19
|
+
return access;
|
|
20
|
+
return normalizeOperatorExpression(node, context, sourceFile);
|
|
21
|
+
}
|
|
22
|
+
function normalizeWrappedExpression(node, context, sourceFile) {
|
|
23
|
+
if (ts.isParenthesizedExpression(node)
|
|
24
|
+
|| ts.isAsExpression(node)
|
|
25
|
+
|| ts.isTypeAssertionExpression(node)
|
|
26
|
+
|| ts.isNonNullExpression(node)
|
|
27
|
+
|| ts.isSatisfiesExpression(node)) {
|
|
28
|
+
return normalizeExpression(node.expression, context, sourceFile);
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
function normalizePrimitiveExpression(node, context) {
|
|
33
|
+
if (ts.isIdentifier(node))
|
|
34
|
+
return normalizeIdentifier(node, context);
|
|
35
|
+
if (node.kind === ts.SyntaxKind.TrueKeyword)
|
|
36
|
+
return ["literal", "boolean", true];
|
|
37
|
+
if (node.kind === ts.SyntaxKind.FalseKeyword)
|
|
38
|
+
return ["literal", "boolean", false];
|
|
39
|
+
if (node.kind === ts.SyntaxKind.NullKeyword)
|
|
40
|
+
return ["literal", "null"];
|
|
41
|
+
if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node))
|
|
42
|
+
return ["literal", "string", node.text];
|
|
43
|
+
if (ts.isNumericLiteral(node))
|
|
44
|
+
return ["literal", "number", node.text];
|
|
45
|
+
if (ts.isBigIntLiteral(node))
|
|
46
|
+
return ["literal", "bigint", node.text];
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
function normalizeIdentifier(node, context) {
|
|
50
|
+
const parameter = context.parameters.get(node.text);
|
|
51
|
+
if (parameter)
|
|
52
|
+
return ["param", parameter];
|
|
53
|
+
const local = context.locals.get(node.text);
|
|
54
|
+
if (local !== undefined)
|
|
55
|
+
return local;
|
|
56
|
+
if (node.text === "undefined")
|
|
57
|
+
return ["literal", "undefined"];
|
|
58
|
+
if (SAFE_GLOBAL_IDENTIFIERS.has(node.text))
|
|
59
|
+
return ["global", node.text];
|
|
60
|
+
return ["outer", node.text];
|
|
61
|
+
}
|
|
62
|
+
function normalizeContainerExpression(node, context, sourceFile) {
|
|
63
|
+
if (ts.isArrayLiteralExpression(node))
|
|
64
|
+
return normalizeArrayLiteral(node, context, sourceFile);
|
|
65
|
+
if (ts.isObjectLiteralExpression(node))
|
|
66
|
+
return normalizeObjectLiteral(node, context, sourceFile);
|
|
67
|
+
if (ts.isTemplateExpression(node))
|
|
68
|
+
return normalizeTemplateExpression(node, context, sourceFile);
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
function normalizeArrayLiteral(node, context, sourceFile) {
|
|
72
|
+
const elements = node.elements.map((element) => (ts.isSpreadElement(element)
|
|
73
|
+
? ["spread", normalizeExpression(element.expression, context, sourceFile)]
|
|
74
|
+
: normalizeExpression(element, context, sourceFile)));
|
|
75
|
+
return elements.some((element) => element === undefined || (Array.isArray(element) && element[1] === undefined))
|
|
76
|
+
? undefined
|
|
77
|
+
: ["array", elements];
|
|
78
|
+
}
|
|
79
|
+
function normalizeObjectLiteral(node, context, sourceFile) {
|
|
80
|
+
const properties = [];
|
|
81
|
+
for (const property of node.properties) {
|
|
82
|
+
const normalized = normalizeObjectProperty(property, context, sourceFile);
|
|
83
|
+
if (normalized === undefined)
|
|
84
|
+
return undefined;
|
|
85
|
+
properties.push(normalized);
|
|
86
|
+
}
|
|
87
|
+
return ["object", properties];
|
|
88
|
+
}
|
|
89
|
+
function normalizeObjectProperty(property, context, sourceFile) {
|
|
90
|
+
if (ts.isPropertyAssignment(property)) {
|
|
91
|
+
const value = normalizeExpression(property.initializer, context, sourceFile);
|
|
92
|
+
return value === undefined ? undefined : ["property", property.name.getText(sourceFile), value];
|
|
93
|
+
}
|
|
94
|
+
if (ts.isShorthandPropertyAssignment(property)) {
|
|
95
|
+
return ["property", property.name.text, normalizeIdentifier(property.name, context)];
|
|
96
|
+
}
|
|
97
|
+
if (ts.isSpreadAssignment(property)) {
|
|
98
|
+
const value = normalizeExpression(property.expression, context, sourceFile);
|
|
99
|
+
return value === undefined ? undefined : ["spread", value];
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
function normalizeTemplateExpression(node, context, sourceFile) {
|
|
104
|
+
const spans = node.templateSpans.map((span) => [
|
|
105
|
+
normalizeExpression(span.expression, context, sourceFile),
|
|
106
|
+
span.literal.text,
|
|
107
|
+
]);
|
|
108
|
+
return spans.some(([expression]) => expression === undefined) ? undefined : ["template", node.head.text, spans];
|
|
109
|
+
}
|
|
110
|
+
function normalizeAccessExpression(node, context, sourceFile) {
|
|
111
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
112
|
+
const target = normalizeExpression(node.expression, context, sourceFile);
|
|
113
|
+
return target === undefined ? undefined : ["member", target, node.name.text];
|
|
114
|
+
}
|
|
115
|
+
if (ts.isElementAccessExpression(node)) {
|
|
116
|
+
const target = normalizeExpression(node.expression, context, sourceFile);
|
|
117
|
+
const argument = normalizeExpression(node.argumentExpression, context, sourceFile);
|
|
118
|
+
return target === undefined || argument === undefined ? undefined : ["element", target, argument];
|
|
119
|
+
}
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
function normalizeOperatorExpression(node, context, sourceFile) {
|
|
123
|
+
if (ts.isCallExpression(node))
|
|
124
|
+
return normalizeCallExpression(node, context, sourceFile);
|
|
125
|
+
if (ts.isConditionalExpression(node))
|
|
126
|
+
return normalizeConditionalExpression(node, context, sourceFile);
|
|
127
|
+
if (ts.isPrefixUnaryExpression(node))
|
|
128
|
+
return normalizePrefixUnaryExpression(node, context, sourceFile);
|
|
129
|
+
if (ts.isBinaryExpression(node))
|
|
130
|
+
return normalizeBinaryExpression(node, context, sourceFile);
|
|
131
|
+
if (ts.isTypeOfExpression(node))
|
|
132
|
+
return normalizeTypeOfExpression(node, context, sourceFile);
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
function normalizeCallExpression(node, context, sourceFile) {
|
|
136
|
+
const callee = normalizeExpression(node.expression, context, sourceFile);
|
|
137
|
+
const args = node.arguments.map((argument) => normalizeExpression(argument, context, sourceFile));
|
|
138
|
+
if (callee === undefined || args.some((arg) => arg === undefined))
|
|
139
|
+
return undefined;
|
|
140
|
+
if (isNamedGlobal(callee, "Boolean") && args.length === 1) {
|
|
141
|
+
return ["truthy", args[0]];
|
|
142
|
+
}
|
|
143
|
+
return ["call", callee, args];
|
|
144
|
+
}
|
|
145
|
+
function normalizeConditionalExpression(node, context, sourceFile) {
|
|
146
|
+
const condition = normalizeCondition(node.condition, context, sourceFile);
|
|
147
|
+
const whenTrue = normalizeExpression(node.whenTrue, context, sourceFile);
|
|
148
|
+
const whenFalse = normalizeExpression(node.whenFalse, context, sourceFile);
|
|
149
|
+
return condition === undefined || whenTrue === undefined || whenFalse === undefined
|
|
150
|
+
? undefined
|
|
151
|
+
: normalizeConditional(condition, whenTrue, whenFalse);
|
|
152
|
+
}
|
|
153
|
+
function normalizePrefixUnaryExpression(node, context, sourceFile) {
|
|
154
|
+
if (node.operator === ts.SyntaxKind.ExclamationToken)
|
|
155
|
+
return normalizeCondition(node, context, sourceFile);
|
|
156
|
+
const operand = normalizeExpression(node.operand, context, sourceFile);
|
|
157
|
+
return operand === undefined ? undefined : ["prefix", ts.tokenToString(node.operator) ?? String(node.operator), operand];
|
|
158
|
+
}
|
|
159
|
+
function normalizeBinaryExpression(node, context, sourceFile) {
|
|
160
|
+
if (isComparisonOperator(node.operatorToken.kind)) {
|
|
161
|
+
return normalizeCondition(node, context, sourceFile);
|
|
162
|
+
}
|
|
163
|
+
const left = normalizeExpression(node.left, context, sourceFile);
|
|
164
|
+
const right = normalizeExpression(node.right, context, sourceFile);
|
|
165
|
+
if (left === undefined || right === undefined)
|
|
166
|
+
return undefined;
|
|
167
|
+
if (isLogicalOperator(node.operatorToken.kind)) {
|
|
168
|
+
return ["logical", ts.tokenToString(node.operatorToken.kind) ?? String(node.operatorToken.kind), left, right];
|
|
169
|
+
}
|
|
170
|
+
return node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken
|
|
171
|
+
? ["coalesce", left, right]
|
|
172
|
+
: ["binary", ts.tokenToString(node.operatorToken.kind) ?? String(node.operatorToken.kind), left, right];
|
|
173
|
+
}
|
|
174
|
+
function normalizeTypeOfExpression(node, context, sourceFile) {
|
|
175
|
+
const expression = normalizeExpression(node.expression, context, sourceFile);
|
|
176
|
+
return expression === undefined ? undefined : ["typeof", expression];
|
|
177
|
+
}
|
|
178
|
+
export { normalizeExpression };
|
|
179
|
+
//# sourceMappingURL=expressions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expressions.js","sourceRoot":"","sources":["../../../../../src/checks/rules/dry/behavior/expressions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAElE,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAE3E,SAAS,mBAAmB,CAC1B,IAAyB,EACzB,OAAwB,EACxB,UAAyB;IAEzB,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAE5B,MAAM,OAAO,GAAG,0BAA0B,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACtE,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IAE1C,MAAM,SAAS,GAAG,4BAA4B,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC9D,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAE9C,MAAM,SAAS,GAAG,4BAA4B,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC1E,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAE9C,MAAM,MAAM,GAAG,yBAAyB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACpE,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IAExC,OAAO,2BAA2B,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,0BAA0B,CACjC,IAAa,EACb,OAAwB,EACxB,UAAyB;IAEzB,IAAI,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC;WACjC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC;WACvB,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC;WAClC,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC;WAC5B,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,OAAO,mBAAmB,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACnE,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,4BAA4B,CAAC,IAAa,EAAE,OAAwB;IAC3E,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC;QAAE,OAAO,mBAAmB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACrE,IAAI,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW;QAAE,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IACjF,IAAI,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,YAAY;QAAE,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IACnF,IAAI,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW;QAAE,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACxE,IAAI,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,+BAA+B,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAClH,IAAI,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACvE,IAAI,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAmB,EAAE,OAAwB;IACxE,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpD,IAAI,SAAS;QAAE,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAE3C,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAEtC,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAC/D,IAAI,uBAAuB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAEzE,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,4BAA4B,CACnC,IAAa,EACb,OAAwB,EACxB,UAAyB;IAEzB,IAAI,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC;QAAE,OAAO,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC/F,IAAI,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC;QAAE,OAAO,sBAAsB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACjG,IAAI,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC;QAAE,OAAO,2BAA2B,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACjG,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,qBAAqB,CAC5B,IAA+B,EAC/B,OAAwB,EACxB,UAAyB;IAEzB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAC9C,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC;QACzB,CAAC,CAAC,CAAC,QAAQ,EAAE,mBAAmB,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAC1E,CAAC,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,CACtD,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;QAC9G,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,sBAAsB,CAC7B,IAAgC,EAChC,OAAwB,EACxB,UAAyB;IAEzB,MAAM,UAAU,GAAyB,EAAE,CAAC;IAE5C,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACvC,MAAM,UAAU,GAAG,uBAAuB,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAC1E,IAAI,UAAU,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAC/C,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,uBAAuB,CAC9B,QAAqC,EACrC,OAAwB,EACxB,UAAyB;IAEzB,IAAI,EAAE,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,mBAAmB,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAC7E,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC;IAClG,CAAC;IAED,IAAI,EAAE,CAAC,6BAA6B,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/C,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,mBAAmB,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACvF,CAAC;IAED,IAAI,EAAE,CAAC,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,mBAAmB,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAC5E,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,2BAA2B,CAClC,IAA2B,EAC3B,OAAwB,EACxB,UAAyB;IAEzB,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC7C,mBAAmB,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,UAAU,CAAC;QACzD,IAAI,CAAC,OAAO,CAAC,IAAI;KAClB,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAClH,CAAC;AAED,SAAS,yBAAyB,CAChC,IAAa,EACb,OAAwB,EACxB,UAAyB;IAEzB,IAAI,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QACzE,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/E,CAAC;IAED,IAAI,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QACzE,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,CAAC,kBAAkB,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QACnF,OAAO,MAAM,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACpG,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,2BAA2B,CAClC,IAAa,EACb,OAAwB,EACxB,UAAyB;IAEzB,IAAI,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC;QAAE,OAAO,uBAAuB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACzF,IAAI,EAAE,CAAC,uBAAuB,CAAC,IAAI,CAAC;QAAE,OAAO,8BAA8B,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACvG,IAAI,EAAE,CAAC,uBAAuB,CAAC,IAAI,CAAC;QAAE,OAAO,8BAA8B,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACvG,IAAI,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC;QAAE,OAAO,yBAAyB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC7F,IAAI,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC;QAAE,OAAO,yBAAyB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC7F,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,uBAAuB,CAC9B,IAAuB,EACvB,OAAwB,EACxB,UAAyB;IAEzB,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACzE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,mBAAmB,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;IAClG,IAAI,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAEpF,IAAI,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1D,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAE,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,8BAA8B,CACrC,IAA8B,EAC9B,OAAwB,EACxB,UAAyB;IAEzB,MAAM,SAAS,GAAG,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC1E,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,mBAAmB,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC3E,OAAO,SAAS,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,IAAI,SAAS,KAAK,SAAS;QACjF,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,oBAAoB,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,8BAA8B,CACrC,IAA8B,EAC9B,OAAwB,EACxB,UAAyB;IAEzB,IAAI,IAAI,CAAC,QAAQ,KAAK,EAAE,CAAC,UAAU,CAAC,gBAAgB;QAAE,OAAO,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAE3G,MAAM,OAAO,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACvE,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;AAC3H,CAAC;AAED,SAAS,yBAAyB,CAChC,IAAyB,EACzB,OAAwB,EACxB,UAAyB;IAEzB,IAAI,oBAAoB,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QAClD,OAAO,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACjE,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACnE,IAAI,IAAI,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAEhE,IAAI,iBAAiB,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/C,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAChH,CAAC;IAED,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,qBAAqB;QACpE,CAAC,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC;QAC3B,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AAC5G,CAAC;AAED,SAAS,yBAAyB,CAChC,IAAyB,EACzB,OAAwB,EACxB,UAAyB;IAEzB,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC7E,OAAO,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;AACvE,CAAC;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import type { BehaviorFingerprint } from "./model.js";
|
|
3
|
+
declare function createBehaviorFingerprint(node: ts.FunctionLikeDeclaration, sourceFile: ts.SourceFile): BehaviorFingerprint | null;
|
|
4
|
+
export { createBehaviorFingerprint };
|
|
5
|
+
export type { BehaviorFingerprint };
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/checks/rules/dry/behavior/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAG5B,OAAO,KAAK,EAAmB,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAIvE,iBAAS,yBAAyB,CAAC,IAAI,EAAE,EAAE,CAAC,uBAAuB,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,GAAG,mBAAmB,GAAG,IAAI,CA2B1H;AAED,OAAO,EAAE,yBAAyB,EAAE,CAAC;AACrC,YAAY,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { stableSerialize } from "../../../../shared/utils.js";
|
|
3
|
+
import { normalizeExpression } from "./expressions.js";
|
|
4
|
+
import { normalizeFunctionReturn } from "./statements.js";
|
|
5
|
+
function createBehaviorFingerprint(node, sourceFile) {
|
|
6
|
+
const parameterNames = node.parameters.map((parameter) => ts.isIdentifier(parameter.name) ? parameter.name.text : null);
|
|
7
|
+
if (parameterNames.some((name) => name === null))
|
|
8
|
+
return null;
|
|
9
|
+
if (node.parameters.some((parameter) => parameter.dotDotDotToken))
|
|
10
|
+
return null;
|
|
11
|
+
const context = {
|
|
12
|
+
locals: new Map(),
|
|
13
|
+
parameters: new Map(parameterNames.map((name, index) => [name, `p${index}`])),
|
|
14
|
+
};
|
|
15
|
+
const parameterDefaults = node.parameters.map((parameter) => (parameter.initializer ? normalizeExpression(parameter.initializer, context, sourceFile) : null));
|
|
16
|
+
if (parameterDefaults.some((value) => value === undefined))
|
|
17
|
+
return null;
|
|
18
|
+
const returned = normalizeFunctionReturn(node, context, sourceFile);
|
|
19
|
+
if (returned === undefined)
|
|
20
|
+
return null;
|
|
21
|
+
const normalized = [
|
|
22
|
+
"behavior-function",
|
|
23
|
+
parameterDefaults,
|
|
24
|
+
returned,
|
|
25
|
+
];
|
|
26
|
+
return {
|
|
27
|
+
fingerprint: stableSerialize(normalized),
|
|
28
|
+
normalized,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export { createBehaviorFingerprint };
|
|
32
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/checks/rules/dry/behavior/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,SAAS,yBAAyB,CAAC,IAAgC,EAAE,UAAyB;IAC5F,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACxH,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9D,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,cAAc,CAAC;QAAE,OAAO,IAAI,CAAC;IAE/E,MAAM,OAAO,GAAoB;QAC/B,MAAM,EAAE,IAAI,GAAG,EAAE;QACjB,UAAU,EAAE,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,IAAK,EAAE,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;KAC/E,CAAC;IACF,MAAM,iBAAiB,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAC3D,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,mBAAmB,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAC/F,CAAC,CAAC;IACH,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IAExE,MAAM,QAAQ,GAAG,uBAAuB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACpE,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAExC,MAAM,UAAU,GAAG;QACjB,mBAAmB;QACnB,iBAAiB;QACjB,QAAQ;KACT,CAAC;IAEF,OAAO;QACL,WAAW,EAAE,eAAe,CAAC,UAAU,CAAC;QACxC,UAAU;KACX,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,yBAAyB,EAAE,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
type BehaviorExpression = unknown;
|
|
3
|
+
type BehaviorContext = {
|
|
4
|
+
locals: Map<string, BehaviorExpression>;
|
|
5
|
+
parameters: Map<string, string>;
|
|
6
|
+
};
|
|
7
|
+
type BehaviorFingerprint = {
|
|
8
|
+
fingerprint: string;
|
|
9
|
+
normalized: BehaviorExpression;
|
|
10
|
+
};
|
|
11
|
+
declare function cloneContext(context: BehaviorContext): BehaviorContext;
|
|
12
|
+
declare function isTagged(value: BehaviorExpression, tag: string): value is [string, ...BehaviorExpression[]];
|
|
13
|
+
declare function isNamedGlobal(value: BehaviorExpression, name: string): boolean;
|
|
14
|
+
declare function isBooleanExpression(value: BehaviorExpression): boolean;
|
|
15
|
+
declare function expressionsEqual(left: BehaviorExpression, right: BehaviorExpression): boolean;
|
|
16
|
+
declare function replaceExpression(expression: BehaviorExpression, target: BehaviorExpression, replacement: BehaviorExpression): BehaviorExpression;
|
|
17
|
+
declare function inferSingleReplacement(template: BehaviorExpression, concrete: BehaviorExpression, placeholder: BehaviorExpression): BehaviorExpression | undefined;
|
|
18
|
+
declare function normalizeAnd(terms: BehaviorExpression[]): BehaviorExpression;
|
|
19
|
+
declare function invertCondition(expression: BehaviorExpression): BehaviorExpression;
|
|
20
|
+
declare function flattenBinary(node: ts.BinaryExpression, operator: ts.SyntaxKind): ts.Node[];
|
|
21
|
+
declare function isComparisonOperator(kind: ts.SyntaxKind): boolean;
|
|
22
|
+
declare function isEqualityOperator(kind: ts.SyntaxKind): boolean;
|
|
23
|
+
declare function isLogicalOperator(kind: ts.SyntaxKind): boolean;
|
|
24
|
+
declare function positiveEqualityOperator(kind: ts.SyntaxKind): "==" | "===";
|
|
25
|
+
declare function normalizeComparison(operator: string, left: BehaviorExpression, right: BehaviorExpression): BehaviorExpression;
|
|
26
|
+
declare function reduceExpression(expression: BehaviorExpression): BehaviorExpression;
|
|
27
|
+
export { cloneContext, expressionsEqual, flattenBinary, inferSingleReplacement, invertCondition, isBooleanExpression, isComparisonOperator, isEqualityOperator, isLogicalOperator, isNamedGlobal, isTagged, normalizeAnd, normalizeComparison, positiveEqualityOperator, reduceExpression, replaceExpression, };
|
|
28
|
+
export type { BehaviorContext, BehaviorExpression, BehaviorFingerprint };
|
|
29
|
+
//# sourceMappingURL=model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../../../src/checks/rules/dry/behavior/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAI5B,KAAK,kBAAkB,GAAG,OAAO,CAAC;AAElC,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACxC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,kBAAkB,CAAC;CAChC,CAAC;AAIF,iBAAS,YAAY,CAAC,OAAO,EAAE,eAAe,GAAG,eAAe,CAK/D;AAED,iBAAS,QAAQ,CAAC,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,GAAG,kBAAkB,EAAE,CAAC,CAEpG;AAED,iBAAS,aAAa,CAAC,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvE;AAED,iBAAS,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAG/D;AAED,iBAAS,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAEtF;AAED,iBAAS,iBAAiB,CACxB,UAAU,EAAE,kBAAkB,EAC9B,MAAM,EAAE,kBAAkB,EAC1B,WAAW,EAAE,kBAAkB,GAC9B,kBAAkB,CAQpB;AA+BD,iBAAS,sBAAsB,CAC7B,QAAQ,EAAE,kBAAkB,EAC5B,QAAQ,EAAE,kBAAkB,EAC5B,WAAW,EAAE,kBAAkB,GAC9B,kBAAkB,GAAG,SAAS,CAGhC;AAED,iBAAS,YAAY,CAAC,KAAK,EAAE,kBAAkB,EAAE,GAAG,kBAAkB,CASrE;AAED,iBAAS,eAAe,CAAC,UAAU,EAAE,kBAAkB,GAAG,kBAAkB,CAG3E;AAED,iBAAS,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,EAAE,QAAQ,EAAE,EAAE,CAAC,UAAU,GAAG,EAAE,CAAC,IAAI,EAAE,CAQpF;AAED,iBAAS,oBAAoB,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,GAAG,OAAO,CAQ1D;AAED,iBAAS,kBAAkB,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,GAAG,OAAO,CAKxD;AAED,iBAAS,iBAAiB,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,GAAG,OAAO,CAGvD;AAED,iBAAS,wBAAwB,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,GAAG,IAAI,GAAG,KAAK,CAInE;AAED,iBAAS,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,kBAAkB,GAAG,kBAAkB,CAKtH;AAED,iBAAS,gBAAgB,CAAC,UAAU,EAAE,kBAAkB,GAAG,kBAAkB,CAuB5E;AAsDD,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,mBAAmB,EACnB,wBAAwB,EACxB,gBAAgB,EAChB,iBAAiB,GAClB,CAAC;AACF,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,CAAC"}
|