@checkdigit/eslint-plugin 7.15.0 → 7.16.0-PR.136-c0c4
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/dist-mjs/{is-aws-sdk-v3-used.mjs → aws/is-aws-sdk-v3-used.mjs} +2 -2
- package/dist-mjs/{require-aws-config.mjs → aws/require-aws-config.mjs} +3 -3
- package/dist-mjs/aws/require-consistent-read.mjs +128 -0
- package/dist-mjs/index.mjs +8 -4
- package/dist-types/aws/require-consistent-read.d.ts +12 -0
- package/dist-types/index.d.ts +1 -1
- package/package.json +1 -96
- package/src/{is-aws-sdk-v3-used.ts → aws/is-aws-sdk-v3-used.ts} +1 -1
- package/src/{require-aws-config.ts → aws/require-aws-config.ts} +2 -2
- package/src/aws/require-consistent-read.ts +175 -0
- package/src/index.ts +6 -2
- /package/dist-types/{is-aws-sdk-v3-used.d.ts → aws/is-aws-sdk-v3-used.d.ts} +0 -0
- /package/dist-types/{require-aws-config.d.ts → aws/require-aws-config.d.ts} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/is-aws-sdk-v3-used.ts
|
|
1
|
+
// src/aws/is-aws-sdk-v3-used.ts
|
|
2
2
|
import { promises as fs } from "node:fs";
|
|
3
3
|
var cachedIsAwsSdkV3Used;
|
|
4
4
|
async function isAwsSdkV3Used() {
|
|
@@ -13,4 +13,4 @@ async function isAwsSdkV3Used() {
|
|
|
13
13
|
export {
|
|
14
14
|
isAwsSdkV3Used as default
|
|
15
15
|
};
|
|
16
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
16
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2F3cy9pcy1hd3Mtc2RrLXYzLXVzZWQudHMiXSwKICAibWFwcGluZ3MiOiAiO0FBRUEsU0FBUyxZQUFZLFVBQVU7QUFTL0IsSUFBSTtBQUVKLGVBQU8saUJBQTBEO0FBQy9ELE1BQUkseUJBQXlCLFFBQVc7QUFDdEMsV0FBTztBQUFBLEVBQ1Q7QUFFQSxRQUFNLGNBQWMsS0FBSyxNQUFNLE1BQU0sR0FBRyxTQUFTLGdCQUFnQixNQUFNLENBQUM7QUFDeEUsUUFBTSxlQUFlLFlBQVksZ0JBQWdCLENBQUM7QUFFbEQseUJBQXVCLE9BQU8sS0FBSyxZQUFZLEVBQUUsS0FBSyxDQUFDLGVBQWUsV0FBVyxXQUFXLFdBQVcsQ0FBQztBQUN4RyxTQUFPO0FBQ1Q7IiwKICAibmFtZXMiOiBbXQp9Cg==
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// src/require-aws-config.ts
|
|
1
|
+
// src/aws/require-aws-config.ts
|
|
2
2
|
import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
|
|
3
|
-
import getDocumentationUrl from "
|
|
3
|
+
import getDocumentationUrl from "../get-documentation-url.mjs";
|
|
4
4
|
var ruleId = "require-aws-config";
|
|
5
5
|
var MESSAGE_ID_REQUIRE_AWS_CONFIG = "requireAwsConfig";
|
|
6
6
|
var MESSAGE_ID_NO_CHECKDIGIT_AWS = "noCheckdigitAws";
|
|
@@ -82,4 +82,4 @@ export {
|
|
|
82
82
|
require_aws_config_default as default,
|
|
83
83
|
ruleId
|
|
84
84
|
};
|
|
85
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
85
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2F3cy9yZXF1aXJlLWF3cy1jb25maWcudHMiXSwKICAibWFwcGluZ3MiOiAiO0FBUUEsU0FBUyxnQkFBZ0IsbUJBQTZCO0FBQ3RELE9BQU8seUJBQXlCO0FBRXpCLElBQU0sU0FBUztBQUNmLElBQU0sZ0NBQWdDO0FBQ3RDLElBQU0sK0JBQStCO0FBQzVDLElBQU0sYUFBYSxZQUFZLFlBQVksQ0FBQyxTQUFTLG9CQUFvQixJQUFJLENBQUM7QUFFOUUsU0FBUyxxQkFBcUIsbUJBQXdEO0FBQ3BGLFNBQU8sa0JBQWtCLE9BQU8sTUFBTSxXQUFXLGtCQUFrQjtBQUNyRTtBQUVBLFNBQVMsc0JBQXNCLG1CQUF3RDtBQUNyRixTQUFPLGtCQUFrQixPQUFPLFVBQVU7QUFDNUM7QUFFQSxTQUFTLFlBQVksZUFBdUIsb0JBQTJDO0FBR3JGLFNBQ0UsY0FBYyxTQUFTLFFBQVEsTUFBTSx1QkFBdUIsVUFBYSxtQkFBbUIsSUFBSSxhQUFhO0FBRWpIO0FBRUEsSUFBTSxPQUNKLFdBQVc7QUFBQSxFQUNULE1BQU07QUFBQSxFQUNOLE1BQU07QUFBQSxJQUNKLE1BQU07QUFBQSxJQUNOLE1BQU07QUFBQSxNQUNKLGFBQ0U7QUFBQSxJQUNKO0FBQUEsSUFDQSxVQUFVO0FBQUEsTUFDUixDQUFDLDZCQUE2QixHQUM1QjtBQUFBLE1BQ0YsQ0FBQyw0QkFBNEIsR0FDM0I7QUFBQSxJQUNKO0FBQUEsSUFDQSxRQUFRLENBQUM7QUFBQSxFQUNYO0FBQUEsRUFDQSxnQkFBZ0IsQ0FBQztBQUFBLEVBQ2pCLE9BQU8sU0FBUztBQUNkLFVBQU0sRUFBRSxlQUFlLElBQUksUUFBUTtBQUNuQyxVQUFNLHFCQUFxQixvQkFBSSxJQUFZO0FBRTNDLFdBQU87QUFBQSxNQUNMLGtCQUFrQixNQUFNO0FBQ3RCLFlBQUksbUJBQW1CLE1BQU07QUFDM0I7QUFBQSxRQUNGO0FBRUEsWUFBSSxzQkFBc0IsSUFBSSxHQUFHO0FBQy9CLGtCQUFRLE9BQU87QUFBQSxZQUNiO0FBQUEsWUFDQSxXQUFXO0FBQUEsVUFDYixDQUFDO0FBQ0Q7QUFBQSxRQUNGO0FBRUEsWUFBSSxxQkFBcUIsSUFBSSxHQUFHO0FBQzlCLHFCQUFXLGFBQWEsS0FBSyxZQUFZO0FBQ3ZDLGdCQUFJLFVBQVUsU0FBUyxlQUFlLG1CQUFtQixZQUFZLFVBQVUsTUFBTSxJQUFJLEdBQUc7QUFDMUYsaUNBQW1CLElBQUksVUFBVSxNQUFNLElBQUk7QUFBQSxZQUM3QztBQUFBLFVBQ0Y7QUFBQSxRQUNGO0FBQUEsTUFDRjtBQUFBLE1BRUEsY0FBYyxNQUFNO0FBQ2xCLFlBQUksbUJBQW1CLE1BQU07QUFDM0I7QUFBQSxRQUNGO0FBRUEsWUFBSSxLQUFLLE9BQU8sU0FBUyxlQUFlLGNBQWMsWUFBWSxLQUFLLE9BQU8sTUFBTSxrQkFBa0IsR0FBRztBQUN2RyxrQkFBUSxPQUFPO0FBQUEsWUFDYjtBQUFBLFlBQ0EsV0FBVztBQUFBLFlBQ1gsTUFBTSxFQUFFLGVBQWUsS0FBSyxPQUFPLEtBQUs7QUFBQSxVQUMxQyxDQUFDO0FBQUEsUUFDSCxXQUFXLEtBQUssT0FBTyxTQUFTLGVBQWUsa0JBQWtCO0FBRS9ELGdCQUFNLFdBQVcsS0FBSyxPQUFPO0FBQzdCLGNBQUksU0FBUyxTQUFTLGVBQWUsY0FBYyxZQUFZLFNBQVMsTUFBTSxrQkFBa0IsR0FBRztBQUNqRyxvQkFBUSxPQUFPO0FBQUEsY0FDYjtBQUFBLGNBQ0EsV0FBVztBQUFBLGNBQ1gsTUFBTSxFQUFFLGVBQWUsU0FBUyxLQUFLO0FBQUEsWUFDdkMsQ0FBQztBQUFBLFVBQ0g7QUFBQSxRQUNGO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFBQSxFQUNGO0FBQ0YsQ0FBQztBQUVILElBQU8sNkJBQVE7IiwKICAibmFtZXMiOiBbXQp9Cg==
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// src/aws/require-consistent-read.ts
|
|
2
|
+
import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
|
|
3
|
+
import getDocumentationUrl from "../get-documentation-url.mjs";
|
|
4
|
+
var ruleId = "require-consistent-read";
|
|
5
|
+
var MESSAGE_ID_CONSISTENT_READ_TRUE = "MESSAGE_ID_CONSISTENT_READ_TRUE";
|
|
6
|
+
var MESSAGE_ID_CONSISTENT_READ_FALSE = "MESSAGE_ID_CONSISTENT_READ_FALSE";
|
|
7
|
+
function getPropertyName(property) {
|
|
8
|
+
if (property.computed) {
|
|
9
|
+
return void 0;
|
|
10
|
+
}
|
|
11
|
+
const propertyKey = property.key;
|
|
12
|
+
return propertyKey.type === AST_NODE_TYPES.Identifier ? propertyKey.name : typeof propertyKey.value === "string" ? propertyKey.value : void 0;
|
|
13
|
+
}
|
|
14
|
+
function extractObjectProperties(objectExpression) {
|
|
15
|
+
const objectProperties = {};
|
|
16
|
+
for (const property of objectExpression.properties) {
|
|
17
|
+
if (property.type !== AST_NODE_TYPES.Property || property.computed) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const propertyName = getPropertyName(property);
|
|
21
|
+
if (propertyName !== void 0) {
|
|
22
|
+
objectProperties[propertyName] = property;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return objectProperties;
|
|
26
|
+
}
|
|
27
|
+
function existsRequestItemsProperty(extractedObjectProperties) {
|
|
28
|
+
const requestItemProperty = extractedObjectProperties["RequestItems"];
|
|
29
|
+
if (requestItemProperty?.type !== AST_NODE_TYPES.Property) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const requestItemValue = requestItemProperty.value;
|
|
33
|
+
if (requestItemValue.type !== AST_NODE_TYPES.ObjectExpression) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return requestItemValue.properties.some(
|
|
37
|
+
(property) => property.type === AST_NODE_TYPES.Property && property.value.type === AST_NODE_TYPES.ObjectExpression && extractObjectProperties(property.value)["Keys"]?.value.type === AST_NODE_TYPES.ArrayExpression
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
function existsKeyProperty(extractedObjectProperties) {
|
|
41
|
+
const keyProperty = extractedObjectProperties["Key"];
|
|
42
|
+
return keyProperty?.type === AST_NODE_TYPES.Property && keyProperty.value.type === AST_NODE_TYPES.ObjectExpression;
|
|
43
|
+
}
|
|
44
|
+
function getReadCommandInfo(objectExpression) {
|
|
45
|
+
const extractedProperties = extractObjectProperties(objectExpression);
|
|
46
|
+
let readCommandInfo;
|
|
47
|
+
if (existsRequestItemsProperty(extractedProperties)) {
|
|
48
|
+
readCommandInfo = { type: "BatchGetItem" };
|
|
49
|
+
} else {
|
|
50
|
+
const hasTableName = "TableName" in extractedProperties;
|
|
51
|
+
const hasKey = existsKeyProperty(extractedProperties);
|
|
52
|
+
if (hasTableName && hasKey) {
|
|
53
|
+
if (!("UpdateExpression" in extractedProperties) && !("ConditionExpression" in extractedProperties)) {
|
|
54
|
+
readCommandInfo = { type: "GetItem" };
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
const hasKeyCondExpr = extractedProperties["KeyConditionExpression"]?.value.type === AST_NODE_TYPES.Literal;
|
|
58
|
+
const hasLegacyKeyConditions = extractedProperties["KeyConditions"]?.value.type === AST_NODE_TYPES.ObjectExpression;
|
|
59
|
+
if (hasTableName && (hasKeyCondExpr || hasLegacyKeyConditions)) {
|
|
60
|
+
readCommandInfo = { type: "Query" };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (readCommandInfo === void 0) {
|
|
65
|
+
return void 0;
|
|
66
|
+
}
|
|
67
|
+
const consistentReadProperty = extractedProperties["ConsistentRead"];
|
|
68
|
+
if (consistentReadProperty?.type === AST_NODE_TYPES.Property && consistentReadProperty.value.type === AST_NODE_TYPES.Literal && typeof consistentReadProperty.value.value === "boolean") {
|
|
69
|
+
readCommandInfo.consistentRead = consistentReadProperty.value.value;
|
|
70
|
+
}
|
|
71
|
+
const indexNameProperty = extractedProperties["IndexName"];
|
|
72
|
+
if (indexNameProperty?.type === AST_NODE_TYPES.Property && indexNameProperty.value.type === AST_NODE_TYPES.Literal && typeof indexNameProperty.value.value === "string") {
|
|
73
|
+
readCommandInfo.usedIndex = true;
|
|
74
|
+
}
|
|
75
|
+
return readCommandInfo;
|
|
76
|
+
}
|
|
77
|
+
var createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
|
|
78
|
+
var rule = createRule({
|
|
79
|
+
name: ruleId,
|
|
80
|
+
meta: {
|
|
81
|
+
type: "problem",
|
|
82
|
+
docs: {
|
|
83
|
+
description: "For AWS dynamodb commands Query/GetItem/BatchGetItem, ConsistentRead option should always be set as true unless global index is used. This will make the service more robust at the ignorable cost of RCU."
|
|
84
|
+
},
|
|
85
|
+
messages: {
|
|
86
|
+
[MESSAGE_ID_CONSISTENT_READ_TRUE]: "ConsistentRead option should always be set as true for {{readCommandType}} command.",
|
|
87
|
+
[MESSAGE_ID_CONSISTENT_READ_FALSE]: "ConsistentRead option should not be set as true for {{readCommandType}} command when using a global secondary index."
|
|
88
|
+
},
|
|
89
|
+
schema: []
|
|
90
|
+
},
|
|
91
|
+
defaultOptions: [],
|
|
92
|
+
create(context) {
|
|
93
|
+
const sourceCode = context.sourceCode;
|
|
94
|
+
return {
|
|
95
|
+
ObjectExpression(node) {
|
|
96
|
+
const text = sourceCode.getText(node);
|
|
97
|
+
if (!/TableName|RequestItems|KeyConditionExpression|KeyConditions/u.test(text)) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const readCommandInfo = getReadCommandInfo(node);
|
|
101
|
+
if (readCommandInfo !== void 0) {
|
|
102
|
+
if (readCommandInfo.usedIndex !== true && readCommandInfo.consistentRead !== true) {
|
|
103
|
+
context.report({
|
|
104
|
+
node,
|
|
105
|
+
messageId: MESSAGE_ID_CONSISTENT_READ_TRUE,
|
|
106
|
+
data: { readCommandType: readCommandInfo.type }
|
|
107
|
+
});
|
|
108
|
+
} else if (readCommandInfo.usedIndex === true && readCommandInfo.consistentRead !== false) {
|
|
109
|
+
context.report({
|
|
110
|
+
node,
|
|
111
|
+
messageId: MESSAGE_ID_CONSISTENT_READ_FALSE,
|
|
112
|
+
data: { readCommandType: readCommandInfo.type }
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
var require_consistent_read_default = rule;
|
|
121
|
+
export {
|
|
122
|
+
MESSAGE_ID_CONSISTENT_READ_FALSE,
|
|
123
|
+
MESSAGE_ID_CONSISTENT_READ_TRUE,
|
|
124
|
+
require_consistent_read_default as default,
|
|
125
|
+
getReadCommandInfo,
|
|
126
|
+
ruleId
|
|
127
|
+
};
|
|
128
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2F3cy9yZXF1aXJlLWNvbnNpc3RlbnQtcmVhZC50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFRQSxTQUFTLGdCQUFnQixtQkFBNkI7QUFDdEQsT0FBTyx5QkFBeUI7QUFFekIsSUFBTSxTQUFTO0FBQ2YsSUFBTSxrQ0FBa0M7QUFDeEMsSUFBTSxtQ0FBbUM7QUFRaEQsU0FBUyxnQkFBZ0IsVUFBaUQ7QUFDeEUsTUFBSSxTQUFTLFVBQVU7QUFDckIsV0FBTztBQUFBLEVBQ1Q7QUFDQSxRQUFNLGNBQWMsU0FBUztBQUU3QixTQUFPLFlBQVksU0FBUyxlQUFlLGFBQ3ZDLFlBQVksT0FDWixPQUFPLFlBQVksVUFBVSxXQUMzQixZQUFZLFFBQ1o7QUFDUjtBQUVBLFNBQVMsd0JBQXdCLGtCQUFnRjtBQUMvRyxRQUFNLG1CQUFzRCxDQUFDO0FBQzdELGFBQVcsWUFBWSxpQkFBaUIsWUFBWTtBQUNsRCxRQUFJLFNBQVMsU0FBUyxlQUFlLFlBQVksU0FBUyxVQUFVO0FBQ2xFO0FBQUEsSUFDRjtBQUNBLFVBQU0sZUFBZSxnQkFBZ0IsUUFBUTtBQUM3QyxRQUFJLGlCQUFpQixRQUFXO0FBQzlCLHVCQUFpQixZQUFZLElBQUk7QUFBQSxJQUNuQztBQUFBLEVBQ0Y7QUFDQSxTQUFPO0FBQ1Q7QUFFQSxTQUFTLDJCQUEyQiwyQkFBdUU7QUFDekcsUUFBTSxzQkFBc0IsMEJBQTBCLGNBQWM7QUFDcEUsTUFBSSxxQkFBcUIsU0FBUyxlQUFlLFVBQVU7QUFDekQsV0FBTztBQUFBLEVBQ1Q7QUFDQSxRQUFNLG1CQUFtQixvQkFBb0I7QUFDN0MsTUFBSSxpQkFBaUIsU0FBUyxlQUFlLGtCQUFrQjtBQUM3RCxXQUFPO0FBQUEsRUFDVDtBQUVBLFNBQU8saUJBQWlCLFdBQVc7QUFBQSxJQUNqQyxDQUFDLGFBQ0MsU0FBUyxTQUFTLGVBQWUsWUFDakMsU0FBUyxNQUFNLFNBQVMsZUFBZSxvQkFDdkMsd0JBQXdCLFNBQVMsS0FBSyxFQUFFLE1BQU0sR0FB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
|
package/dist-mjs/index.mjs
CHANGED
|
@@ -17,7 +17,8 @@ import noServeRuntime, { ruleId as noServeRuntimeRuleId } from "./no-serve-runti
|
|
|
17
17
|
import requireServiceCallResponseDeclaration, {
|
|
18
18
|
ruleId as requireServiceCallResponseDeclarationRuleId
|
|
19
19
|
} from "./require-service-call-response-declaration.mjs";
|
|
20
|
-
import
|
|
20
|
+
import requireConsistentRead, { ruleId as requireConsistentReadRuleId } from "./aws/require-consistent-read.mjs";
|
|
21
|
+
import requireAwsConfig, { ruleId as requireAwsConfigRuleId } from "./aws/require-aws-config.mjs";
|
|
21
22
|
import filePathComment from "./file-path-comment.mjs";
|
|
22
23
|
import noCardNumbers from "./no-card-numbers.mjs";
|
|
23
24
|
import noEnum from "./no-enum.mjs";
|
|
@@ -33,7 +34,7 @@ import requireAssertPredicateRejectsThrows from "./require-assert-predicate-reje
|
|
|
33
34
|
import requireStrictAssert from "./require-strict-assert.mjs";
|
|
34
35
|
import requireAssertMessage from "./require-assert-message.mjs";
|
|
35
36
|
import requireTsExtensionImportsExports from "./require-ts-extension-imports-exports.mjs";
|
|
36
|
-
import { default as default2 } from "./is-aws-sdk-v3-used.mjs";
|
|
37
|
+
import { default as default2 } from "./aws/is-aws-sdk-v3-used.mjs";
|
|
37
38
|
var rules = {
|
|
38
39
|
"file-path-comment": filePathComment,
|
|
39
40
|
"no-card-numbers": noCardNumbers,
|
|
@@ -60,7 +61,8 @@ var rules = {
|
|
|
60
61
|
[requireServiceCallResponseDeclarationRuleId]: requireServiceCallResponseDeclaration,
|
|
61
62
|
[requireAwsConfigRuleId]: requireAwsConfig,
|
|
62
63
|
[requireFixedServicesImportRuleId]: requireFixedServicesImport,
|
|
63
|
-
[requireTypeOutOfTypeOnlyImportsRuleId]: requireTypeOutOfTypeOnlyImports
|
|
64
|
+
[requireTypeOutOfTypeOnlyImportsRuleId]: requireTypeOutOfTypeOnlyImports,
|
|
65
|
+
[requireConsistentReadRuleId]: requireConsistentRead
|
|
64
66
|
};
|
|
65
67
|
var plugin = {
|
|
66
68
|
rules
|
|
@@ -98,6 +100,7 @@ var configs = {
|
|
|
98
100
|
[`@checkdigit/${requireTypeOutOfTypeOnlyImportsRuleId}`]: "error",
|
|
99
101
|
[`@checkdigit/${noServeRuntimeRuleId}`]: "error",
|
|
100
102
|
[`@checkdigit/${requireServiceCallResponseDeclarationRuleId}`]: "error",
|
|
103
|
+
[`@checkdigit/${requireConsistentReadRuleId}`]: "error",
|
|
101
104
|
[`@checkdigit/${requireAwsConfigRuleId}`]: "error"
|
|
102
105
|
}
|
|
103
106
|
}
|
|
@@ -134,6 +137,7 @@ var configs = {
|
|
|
134
137
|
[`@checkdigit/${requireTypeOutOfTypeOnlyImportsRuleId}`]: "error",
|
|
135
138
|
[`@checkdigit/${noServeRuntimeRuleId}`]: "off",
|
|
136
139
|
[`@checkdigit/${requireServiceCallResponseDeclarationRuleId}`]: "off",
|
|
140
|
+
[`@checkdigit/${requireConsistentReadRuleId}`]: "off",
|
|
137
141
|
[`@checkdigit/${requireAwsConfigRuleId}`]: "off"
|
|
138
142
|
}
|
|
139
143
|
}
|
|
@@ -148,4 +152,4 @@ export {
|
|
|
148
152
|
index_default as default,
|
|
149
153
|
default2 as isAwsSdkV3Used
|
|
150
154
|
};
|
|
151
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
155
|
+
//# sourceMappingURL=data:application/json;base64,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
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ESLintUtils, TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
export declare const ruleId = "require-consistent-read";
|
|
3
|
+
export declare const MESSAGE_ID_CONSISTENT_READ_TRUE = "MESSAGE_ID_CONSISTENT_READ_TRUE";
|
|
4
|
+
export declare const MESSAGE_ID_CONSISTENT_READ_FALSE = "MESSAGE_ID_CONSISTENT_READ_FALSE";
|
|
5
|
+
interface ReadCommandInfo {
|
|
6
|
+
type: 'GetItem' | 'Query' | 'BatchGetItem';
|
|
7
|
+
consistentRead?: boolean;
|
|
8
|
+
usedIndex?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function getReadCommandInfo(objectExpression: TSESTree.ObjectExpression): ReadCommandInfo | undefined;
|
|
11
|
+
declare const rule: ESLintUtils.RuleModule<typeof MESSAGE_ID_CONSISTENT_READ_TRUE | typeof MESSAGE_ID_CONSISTENT_READ_FALSE>;
|
|
12
|
+
export default rule;
|
package/dist-types/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TSESLint } from '@typescript-eslint/utils';
|
|
2
|
-
export { default as isAwsSdkV3Used } from './is-aws-sdk-v3-used.ts';
|
|
2
|
+
export { default as isAwsSdkV3Used } from './aws/is-aws-sdk-v3-used.ts';
|
|
3
3
|
declare const defaultToExport: Exclude<TSESLint.FlatConfig.Plugin, 'config'> & {
|
|
4
4
|
configs: Record<string, TSESLint.FlatConfig.Config[]>;
|
|
5
5
|
};
|
package/package.json
CHANGED
|
@@ -1,96 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@checkdigit/eslint-plugin",
|
|
3
|
-
"version": "7.15.0",
|
|
4
|
-
"description": "Check Digit eslint plugins",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"eslint",
|
|
7
|
-
"eslintplugin"
|
|
8
|
-
],
|
|
9
|
-
"homepage": "https://github.com/checkdigit/eslint-plugin#readme",
|
|
10
|
-
"bugs": {
|
|
11
|
-
"url": "https://github.com/checkdigit/eslint-plugin/issues"
|
|
12
|
-
},
|
|
13
|
-
"repository": {
|
|
14
|
-
"type": "git",
|
|
15
|
-
"url": "https://github.com/checkdigit/eslint-plugin"
|
|
16
|
-
},
|
|
17
|
-
"license": "MIT",
|
|
18
|
-
"author": "Check Digit, LLC",
|
|
19
|
-
"sideEffects": false,
|
|
20
|
-
"type": "module",
|
|
21
|
-
"exports": {
|
|
22
|
-
".": {
|
|
23
|
-
"types": "./dist-types/index.d.ts",
|
|
24
|
-
"import": "./dist-mjs/index.mjs",
|
|
25
|
-
"default": "./dist-mjs/index.mjs"
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
"files": [
|
|
29
|
-
"src",
|
|
30
|
-
"dist-types",
|
|
31
|
-
"dist-mjs",
|
|
32
|
-
"!src/**/test/**",
|
|
33
|
-
"!src/**/*.test.ts",
|
|
34
|
-
"!src/**/*.spec.ts",
|
|
35
|
-
"!dist-types/**/test/**",
|
|
36
|
-
"!dist-types/**/*.test.d.ts",
|
|
37
|
-
"!dist-types/**/*.spec.d.ts",
|
|
38
|
-
"!dist-mjs/**/test/**",
|
|
39
|
-
"!dist-mjs/**/*.test.mjs",
|
|
40
|
-
"!dist-mjs/**/*.spec.mjs",
|
|
41
|
-
"SECURITY.md"
|
|
42
|
-
],
|
|
43
|
-
"scripts": {
|
|
44
|
-
"build:dist-mjs": "rimraf dist-mjs && npx builder --type=module --sourceMap --outDir=dist-mjs && node dist-mjs/index.mjs",
|
|
45
|
-
"build:dist-types": "rimraf dist-types && npx builder --type=types --outDir=dist-types",
|
|
46
|
-
"ci:compile": "tsc --noEmit",
|
|
47
|
-
"ci:coverage": "NODE_OPTIONS=\"--disable-warning ExperimentalWarning --experimental-vm-modules\" jest --coverage=true",
|
|
48
|
-
"ci:lint": "npm run lint",
|
|
49
|
-
"ci:style": "npm run prettier",
|
|
50
|
-
"ci:test": "NODE_OPTIONS=\"--disable-warning ExperimentalWarning --experimental-vm-modules\" jest --coverage=false",
|
|
51
|
-
"lint": "eslint --max-warnings 0 .",
|
|
52
|
-
"lint:fix": "eslint --max-warnings 0 --fix .",
|
|
53
|
-
"prepare": "",
|
|
54
|
-
"prepublishOnly": "npm run build:dist-types && npm run build:dist-mjs",
|
|
55
|
-
"prettier": "prettier --ignore-path .gitignore --list-different .",
|
|
56
|
-
"prettier:fix": "prettier --ignore-path .gitignore --write .",
|
|
57
|
-
"test": "npm run ci:compile && npm run ci:test && npm run ci:lint && npm run ci:style"
|
|
58
|
-
},
|
|
59
|
-
"prettier": "@checkdigit/prettier-config",
|
|
60
|
-
"jest": {
|
|
61
|
-
"preset": "@checkdigit/jest-config"
|
|
62
|
-
},
|
|
63
|
-
"dependencies": {
|
|
64
|
-
"@typescript-eslint/type-utils": "^8.46.0",
|
|
65
|
-
"@typescript-eslint/utils": "^8.46.0",
|
|
66
|
-
"http-status-codes": "^2.3.0",
|
|
67
|
-
"ts-api-utils": "^2.1.0"
|
|
68
|
-
},
|
|
69
|
-
"devDependencies": {
|
|
70
|
-
"@checkdigit/jest-config": "^6.0.2",
|
|
71
|
-
"@checkdigit/prettier-config": "^6.1.0",
|
|
72
|
-
"@checkdigit/typescript-config": "^9.3.1",
|
|
73
|
-
"@eslint/js": "^9.37.0",
|
|
74
|
-
"@types/eslint": "^9.6.1",
|
|
75
|
-
"@types/eslint-config-prettier": "^6.11.3",
|
|
76
|
-
"@typescript-eslint/parser": "^8.46.0",
|
|
77
|
-
"@typescript-eslint/rule-tester": "^8.46.0",
|
|
78
|
-
"eslint": "^9.37.0",
|
|
79
|
-
"eslint-config-prettier": "^10.1.8",
|
|
80
|
-
"eslint-import-resolver-typescript": "^4.4.4",
|
|
81
|
-
"eslint-plugin-eslint-plugin": "^6.4.0",
|
|
82
|
-
"eslint-plugin-import": "^2.32.0",
|
|
83
|
-
"eslint-plugin-no-only-tests": "^3.3.0",
|
|
84
|
-
"eslint-plugin-no-secrets": "^2.2.1",
|
|
85
|
-
"eslint-plugin-node": "^11.1.0",
|
|
86
|
-
"eslint-plugin-sonarjs": "1.0.4",
|
|
87
|
-
"rimraf": "^6.0.1",
|
|
88
|
-
"typescript-eslint": "^8.46.0"
|
|
89
|
-
},
|
|
90
|
-
"peerDependencies": {
|
|
91
|
-
"eslint": ">=9 <10"
|
|
92
|
-
},
|
|
93
|
-
"engines": {
|
|
94
|
-
"node": ">=22.18"
|
|
95
|
-
}
|
|
96
|
-
}
|
|
1
|
+
{"name":"@checkdigit/eslint-plugin","version":"7.16.0-PR.136-c0c4","description":"Check Digit eslint plugins","keywords":["eslint","eslintplugin"],"homepage":"https://github.com/checkdigit/eslint-plugin#readme","bugs":{"url":"https://github.com/checkdigit/eslint-plugin/issues"},"repository":{"type":"git","url":"https://github.com/checkdigit/eslint-plugin"},"license":"MIT","author":"Check Digit, LLC","sideEffects":false,"type":"module","exports":{".":{"types":"./dist-types/index.d.ts","import":"./dist-mjs/index.mjs","default":"./dist-mjs/index.mjs"}},"files":["src","dist-types","dist-mjs","!src/**/test/**","!src/**/*.test.ts","!src/**/*.spec.ts","!dist-types/**/test/**","!dist-types/**/*.test.d.ts","!dist-types/**/*.spec.d.ts","!dist-mjs/**/test/**","!dist-mjs/**/*.test.mjs","!dist-mjs/**/*.spec.mjs","SECURITY.md"],"scripts":{"build:dist-mjs":"rimraf dist-mjs && npx builder --type=module --sourceMap --outDir=dist-mjs && node dist-mjs/index.mjs","build:dist-types":"rimraf dist-types && npx builder --type=types --outDir=dist-types","ci:compile":"tsc --noEmit","ci:coverage":"NODE_OPTIONS=\"--disable-warning ExperimentalWarning --experimental-vm-modules\" jest --coverage=true","ci:lint":"npm run lint","ci:style":"npm run prettier","ci:test":"NODE_OPTIONS=\"--disable-warning ExperimentalWarning --experimental-vm-modules\" jest --coverage=false","lint":"eslint --max-warnings 0 .","lint:fix":"eslint --max-warnings 0 --fix .","prepare":"","prepublishOnly":"npm run build:dist-types && npm run build:dist-mjs","prettier":"prettier --ignore-path .gitignore --list-different .","prettier:fix":"prettier --ignore-path .gitignore --write .","test":"npm run ci:compile && npm run ci:test && npm run ci:lint && npm run ci:style"},"prettier":"@checkdigit/prettier-config","jest":{"preset":"@checkdigit/jest-config"},"dependencies":{"@typescript-eslint/type-utils":"^8.46.0","@typescript-eslint/utils":"^8.46.0","http-status-codes":"^2.3.0","ts-api-utils":"^2.1.0"},"devDependencies":{"@checkdigit/jest-config":"^6.0.2","@checkdigit/prettier-config":"^6.1.0","@checkdigit/typescript-config":"^9.3.2","@eslint/js":"^9.37.0","@types/eslint":"^9.6.1","@types/eslint-config-prettier":"^6.11.3","@typescript-eslint/parser":"^8.46.0","@typescript-eslint/rule-tester":"^8.46.0","eslint":"^9.37.0","eslint-config-prettier":"^10.1.8","eslint-import-resolver-typescript":"^4.4.4","eslint-plugin-eslint-plugin":"^6.4.0","eslint-plugin-import":"^2.32.0","eslint-plugin-no-only-tests":"^3.3.0","eslint-plugin-no-secrets":"^2.2.1","eslint-plugin-node":"^11.1.0","eslint-plugin-sonarjs":"1.0.4","rimraf":"^6.0.1","typescript-eslint":"^8.46.0"},"peerDependencies":{"eslint":">=9 <10"},"engines":{"node":">=22.18"}}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// require-aws-config.ts
|
|
1
|
+
// aws/require-aws-config.ts
|
|
2
2
|
|
|
3
3
|
/*
|
|
4
4
|
* Copyright (c) 2021-2025 Check Digit, LLC
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { AST_NODE_TYPES, ESLintUtils, TSESTree } from '@typescript-eslint/utils';
|
|
10
|
-
import getDocumentationUrl from '
|
|
10
|
+
import getDocumentationUrl from '../get-documentation-url.ts';
|
|
11
11
|
|
|
12
12
|
export const ruleId = 'require-aws-config';
|
|
13
13
|
export const MESSAGE_ID_REQUIRE_AWS_CONFIG = 'requireAwsConfig';
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// aws/require-consistent-read.ts
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Copyright (c) 2021-2025 Check Digit, LLC
|
|
5
|
+
*
|
|
6
|
+
* This code is licensed under the MIT license (see LICENSE.txt for details).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { AST_NODE_TYPES, ESLintUtils, TSESTree } from '@typescript-eslint/utils';
|
|
10
|
+
import getDocumentationUrl from '../get-documentation-url.ts';
|
|
11
|
+
|
|
12
|
+
export const ruleId = 'require-consistent-read';
|
|
13
|
+
export const MESSAGE_ID_CONSISTENT_READ_TRUE = 'MESSAGE_ID_CONSISTENT_READ_TRUE';
|
|
14
|
+
export const MESSAGE_ID_CONSISTENT_READ_FALSE = 'MESSAGE_ID_CONSISTENT_READ_FALSE';
|
|
15
|
+
|
|
16
|
+
interface ReadCommandInfo {
|
|
17
|
+
type: 'GetItem' | 'Query' | 'BatchGetItem';
|
|
18
|
+
consistentRead?: boolean;
|
|
19
|
+
usedIndex?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getPropertyName(property: TSESTree.Property): string | undefined {
|
|
23
|
+
if (property.computed) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
const propertyKey = property.key;
|
|
27
|
+
// eslint-disable-next-line no-nested-ternary
|
|
28
|
+
return propertyKey.type === AST_NODE_TYPES.Identifier
|
|
29
|
+
? propertyKey.name
|
|
30
|
+
: typeof propertyKey.value === 'string'
|
|
31
|
+
? propertyKey.value
|
|
32
|
+
: undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function extractObjectProperties(objectExpression: TSESTree.ObjectExpression): Record<string, TSESTree.Property> {
|
|
36
|
+
const objectProperties: Record<string, TSESTree.Property> = {};
|
|
37
|
+
for (const property of objectExpression.properties) {
|
|
38
|
+
if (property.type !== AST_NODE_TYPES.Property || property.computed) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const propertyName = getPropertyName(property);
|
|
42
|
+
if (propertyName !== undefined) {
|
|
43
|
+
objectProperties[propertyName] = property;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return objectProperties;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function existsRequestItemsProperty(extractedObjectProperties: Record<string, TSESTree.Property>): boolean {
|
|
50
|
+
const requestItemProperty = extractedObjectProperties['RequestItems'];
|
|
51
|
+
if (requestItemProperty?.type !== AST_NODE_TYPES.Property) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const requestItemValue = requestItemProperty.value;
|
|
55
|
+
if (requestItemValue.type !== AST_NODE_TYPES.ObjectExpression) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
// any table entry with an object having a Keys array
|
|
59
|
+
return requestItemValue.properties.some(
|
|
60
|
+
(property) =>
|
|
61
|
+
property.type === AST_NODE_TYPES.Property &&
|
|
62
|
+
property.value.type === AST_NODE_TYPES.ObjectExpression &&
|
|
63
|
+
extractObjectProperties(property.value)['Keys']?.value.type === AST_NODE_TYPES.ArrayExpression,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function existsKeyProperty(extractedObjectProperties: Record<string, TSESTree.Property>): boolean {
|
|
68
|
+
const keyProperty = extractedObjectProperties['Key'];
|
|
69
|
+
// Relaxed: just ensure it's an object (works for both low-level and DocumentClient)
|
|
70
|
+
return keyProperty?.type === AST_NODE_TYPES.Property && keyProperty.value.type === AST_NODE_TYPES.ObjectExpression;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function getReadCommandInfo(objectExpression: TSESTree.ObjectExpression): ReadCommandInfo | undefined {
|
|
74
|
+
const extractedProperties = extractObjectProperties(objectExpression);
|
|
75
|
+
let readCommandInfo: ReadCommandInfo | undefined;
|
|
76
|
+
|
|
77
|
+
if (existsRequestItemsProperty(extractedProperties)) {
|
|
78
|
+
readCommandInfo = { type: 'BatchGetItem' };
|
|
79
|
+
} else {
|
|
80
|
+
const hasTableName = 'TableName' in extractedProperties;
|
|
81
|
+
const hasKey = existsKeyProperty(extractedProperties);
|
|
82
|
+
if (hasTableName && hasKey) {
|
|
83
|
+
// make sure it is not an update or conditional write;
|
|
84
|
+
// we can't really tell if it's a delete, but we simply ignore that case assuming they'll never be used
|
|
85
|
+
if (!('UpdateExpression' in extractedProperties) && !('ConditionExpression' in extractedProperties)) {
|
|
86
|
+
readCommandInfo = { type: 'GetItem' };
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
const hasKeyCondExpr = extractedProperties['KeyConditionExpression']?.value.type === AST_NODE_TYPES.Literal;
|
|
90
|
+
const hasLegacyKeyConditions =
|
|
91
|
+
extractedProperties['KeyConditions']?.value.type === AST_NODE_TYPES.ObjectExpression;
|
|
92
|
+
if (hasTableName && (hasKeyCondExpr || hasLegacyKeyConditions)) {
|
|
93
|
+
readCommandInfo = { type: 'Query' };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (readCommandInfo === undefined) {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const consistentReadProperty = extractedProperties['ConsistentRead'];
|
|
103
|
+
if (
|
|
104
|
+
consistentReadProperty?.type === AST_NODE_TYPES.Property &&
|
|
105
|
+
consistentReadProperty.value.type === AST_NODE_TYPES.Literal &&
|
|
106
|
+
typeof consistentReadProperty.value.value === 'boolean'
|
|
107
|
+
) {
|
|
108
|
+
readCommandInfo.consistentRead = consistentReadProperty.value.value;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const indexNameProperty = extractedProperties['IndexName'];
|
|
112
|
+
if (
|
|
113
|
+
indexNameProperty?.type === AST_NODE_TYPES.Property &&
|
|
114
|
+
indexNameProperty.value.type === AST_NODE_TYPES.Literal &&
|
|
115
|
+
typeof indexNameProperty.value.value === 'string'
|
|
116
|
+
) {
|
|
117
|
+
readCommandInfo.usedIndex = true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return readCommandInfo;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
|
|
124
|
+
|
|
125
|
+
const rule: ESLintUtils.RuleModule<typeof MESSAGE_ID_CONSISTENT_READ_TRUE | typeof MESSAGE_ID_CONSISTENT_READ_FALSE> =
|
|
126
|
+
createRule({
|
|
127
|
+
name: ruleId,
|
|
128
|
+
meta: {
|
|
129
|
+
type: 'problem',
|
|
130
|
+
docs: {
|
|
131
|
+
description:
|
|
132
|
+
'For AWS dynamodb commands Query/GetItem/BatchGetItem, ConsistentRead option should always be set as true unless global index is used. This will make the service more robust at the ignorable cost of RCU.',
|
|
133
|
+
},
|
|
134
|
+
messages: {
|
|
135
|
+
[MESSAGE_ID_CONSISTENT_READ_TRUE]:
|
|
136
|
+
'ConsistentRead option should always be set as true for {{readCommandType}} command.',
|
|
137
|
+
[MESSAGE_ID_CONSISTENT_READ_FALSE]:
|
|
138
|
+
'ConsistentRead option should not be set as true for {{readCommandType}} command when using a global secondary index.',
|
|
139
|
+
},
|
|
140
|
+
schema: [],
|
|
141
|
+
},
|
|
142
|
+
defaultOptions: [],
|
|
143
|
+
create(context) {
|
|
144
|
+
const sourceCode = context.sourceCode;
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
ObjectExpression(node) {
|
|
148
|
+
// Quick prefilter: only look at objects that mention table/read-ish keys
|
|
149
|
+
const text = sourceCode.getText(node);
|
|
150
|
+
if (!/TableName|RequestItems|KeyConditionExpression|KeyConditions/u.test(text)) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const readCommandInfo = getReadCommandInfo(node);
|
|
155
|
+
if (readCommandInfo !== undefined) {
|
|
156
|
+
if (readCommandInfo.usedIndex !== true && readCommandInfo.consistentRead !== true) {
|
|
157
|
+
context.report({
|
|
158
|
+
node,
|
|
159
|
+
messageId: MESSAGE_ID_CONSISTENT_READ_TRUE,
|
|
160
|
+
data: { readCommandType: readCommandInfo.type },
|
|
161
|
+
});
|
|
162
|
+
} else if (readCommandInfo.usedIndex === true && readCommandInfo.consistentRead !== false) {
|
|
163
|
+
context.report({
|
|
164
|
+
node,
|
|
165
|
+
messageId: MESSAGE_ID_CONSISTENT_READ_FALSE,
|
|
166
|
+
data: { readCommandType: readCommandInfo.type },
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
export default rule;
|
package/src/index.ts
CHANGED
|
@@ -26,7 +26,8 @@ import noServeRuntime, { ruleId as noServeRuntimeRuleId } from './no-serve-runti
|
|
|
26
26
|
import requireServiceCallResponseDeclaration, {
|
|
27
27
|
ruleId as requireServiceCallResponseDeclarationRuleId,
|
|
28
28
|
} from './require-service-call-response-declaration.ts';
|
|
29
|
-
import
|
|
29
|
+
import requireConsistentRead, { ruleId as requireConsistentReadRuleId } from './aws/require-consistent-read.ts';
|
|
30
|
+
import requireAwsConfig, { ruleId as requireAwsConfigRuleId } from './aws/require-aws-config.ts';
|
|
30
31
|
import filePathComment from './file-path-comment.ts';
|
|
31
32
|
import noCardNumbers from './no-card-numbers.ts';
|
|
32
33
|
import noEnum from './no-enum.ts';
|
|
@@ -43,7 +44,7 @@ import requireStrictAssert from './require-strict-assert.ts';
|
|
|
43
44
|
import requireAssertMessage from './require-assert-message';
|
|
44
45
|
import requireTsExtensionImportsExports from './require-ts-extension-imports-exports.ts';
|
|
45
46
|
|
|
46
|
-
export { default as isAwsSdkV3Used } from './is-aws-sdk-v3-used.ts';
|
|
47
|
+
export { default as isAwsSdkV3Used } from './aws/is-aws-sdk-v3-used.ts';
|
|
47
48
|
|
|
48
49
|
const rules: Record<string, TSESLint.LooseRuleDefinition> = {
|
|
49
50
|
'file-path-comment': filePathComment,
|
|
@@ -72,6 +73,7 @@ const rules: Record<string, TSESLint.LooseRuleDefinition> = {
|
|
|
72
73
|
[requireAwsConfigRuleId]: requireAwsConfig,
|
|
73
74
|
[requireFixedServicesImportRuleId]: requireFixedServicesImport,
|
|
74
75
|
[requireTypeOutOfTypeOnlyImportsRuleId]: requireTypeOutOfTypeOnlyImports,
|
|
76
|
+
[requireConsistentReadRuleId]: requireConsistentRead,
|
|
75
77
|
};
|
|
76
78
|
|
|
77
79
|
const plugin: TSESLint.FlatConfig.Plugin = {
|
|
@@ -111,6 +113,7 @@ const configs: Record<string, TSESLint.FlatConfig.Config[]> = {
|
|
|
111
113
|
[`@checkdigit/${requireTypeOutOfTypeOnlyImportsRuleId}`]: 'error',
|
|
112
114
|
[`@checkdigit/${noServeRuntimeRuleId}`]: 'error',
|
|
113
115
|
[`@checkdigit/${requireServiceCallResponseDeclarationRuleId}`]: 'error',
|
|
116
|
+
[`@checkdigit/${requireConsistentReadRuleId}`]: 'error',
|
|
114
117
|
[`@checkdigit/${requireAwsConfigRuleId}`]: 'error',
|
|
115
118
|
},
|
|
116
119
|
},
|
|
@@ -147,6 +150,7 @@ const configs: Record<string, TSESLint.FlatConfig.Config[]> = {
|
|
|
147
150
|
[`@checkdigit/${requireTypeOutOfTypeOnlyImportsRuleId}`]: 'error',
|
|
148
151
|
[`@checkdigit/${noServeRuntimeRuleId}`]: 'off',
|
|
149
152
|
[`@checkdigit/${requireServiceCallResponseDeclarationRuleId}`]: 'off',
|
|
153
|
+
[`@checkdigit/${requireConsistentReadRuleId}`]: 'off',
|
|
150
154
|
[`@checkdigit/${requireAwsConfigRuleId}`]: 'off',
|
|
151
155
|
},
|
|
152
156
|
},
|
|
File without changes
|
|
File without changes
|