@checkdigit/eslint-plugin 7.17.1 → 7.18.0-PR.143-8290
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/athena/api-locator.mjs +30 -0
- package/dist-mjs/athena/api-matcher.mjs +108 -0
- package/dist-mjs/athena/athena.mjs +331 -0
- package/dist-mjs/athena/column.mjs +1 -0
- package/dist-mjs/athena/context.mjs +21 -0
- package/dist-mjs/athena/index.mjs +1 -0
- package/dist-mjs/athena/service-table.mjs +32 -0
- package/dist-mjs/athena/types.mjs +1 -0
- package/dist-mjs/athena/visitor.mjs +258 -0
- package/dist-mjs/index.mjs +8 -4
- package/dist-mjs/no-status-code-assert.mjs +1 -1
- package/dist-mjs/openapi/deref-schema.mjs +14 -0
- package/dist-mjs/openapi/generate-schema.mjs +273 -0
- package/dist-mjs/openapi/service-schema-generator.mjs +147 -0
- package/dist-mjs/peggy/athena-peggy.mjs +20629 -0
- package/dist-types/athena/api-locator.d.ts +2 -0
- package/dist-types/athena/api-matcher.d.ts +14 -0
- package/dist-types/athena/athena.d.ts +6 -0
- package/dist-types/athena/column.d.ts +1 -0
- package/dist-types/athena/context.d.ts +21 -0
- package/dist-types/athena/index.d.ts +8 -0
- package/dist-types/athena/service-table.d.ts +8 -0
- package/dist-types/athena/types.d.ts +474 -0
- package/dist-types/athena/visitor.d.ts +63 -0
- package/dist-types/no-status-code-assert.d.ts +1 -1
- package/dist-types/openapi/deref-schema.d.ts +1 -0
- package/dist-types/openapi/generate-schema.d.ts +33 -0
- package/dist-types/openapi/service-schema-generator.d.ts +5 -0
- package/dist-types/peggy/athena-peggy.d.ts +13 -0
- package/package.json +1 -96
- package/src/athena/ATHENA.md +387 -0
- package/src/athena/PLAN.md +355 -0
- package/src/athena/api-locator.ts +39 -0
- package/src/athena/api-matcher.ts +169 -0
- package/src/athena/athena.ts +491 -0
- package/src/athena/column.ts +2 -0
- package/src/athena/context.ts +47 -0
- package/src/athena/index.ts +11 -0
- package/src/athena/service-table.ts +55 -0
- package/src/athena/types.ts +526 -0
- package/src/athena/visitor.ts +365 -0
- package/src/index.ts +4 -0
- package/src/no-side-effects.ts +1 -1
- package/src/no-status-code-assert.ts +2 -2
- package/src/openapi/deref-schema.ts +14 -0
- package/src/openapi/generate-schema.ts +422 -0
- package/src/openapi/service-schema-generator.ts +189 -0
- package/src/peggy/athena-chat.peggy +608 -0
- package/src/peggy/athena-peggy.ts +22078 -0
- package/src/peggy/athena.peggy +2967 -0
- package/src/require-service-call-response-declaration.ts +2 -2
- package/src/services/interchange/v1/swagger.schema.deref.json +849 -0
- package/src/services/interchange/v1/swagger.schema.json +473 -0
- package/src/services/interchange/v1/swagger.yml +414 -0
- package/src/services/ledger/v1/swagger.schema.deref.json +6694 -0
- package/src/services/ledger/v1/swagger.schema.json +1820 -0
- package/src/services/ledger/v1/swagger.yml +1094 -0
- package/src/services/link/v1/swagger.schema.deref.json +648 -0
- package/src/services/link/v1/swagger.schema.json +444 -0
- package/src/services/link/v1/swagger.yml +343 -0
- package/src/services/message/v1/swagger.schema.deref.json +22049 -0
- package/src/services/message/v1/swagger.schema.json +3470 -0
- package/src/services/message/v1/swagger.yml +2798 -0
- package/src/services/message/v2/swagger.schema.deref.json +72221 -0
- package/src/services/message/v2/swagger.schema.json +3558 -0
- package/src/services/message/v2/swagger.yml +3009 -0
- package/src/services/paymentCard/v1/swagger.schema.deref.json +4346 -0
- package/src/services/paymentCard/v1/swagger.schema.json +2181 -0
- package/src/services/paymentCard/v1/swagger.yml +1161 -0
- package/src/services/paymentCard/v2/swagger.schema.deref.json +4336 -0
- package/src/services/paymentCard/v2/swagger.schema.json +2155 -0
- package/src/services/paymentCard/v2/swagger.yml +1149 -0
- package/src/services/person/v1/swagger.schema.deref.json +6786 -0
- package/src/services/person/v1/swagger.schema.json +1445 -0
- package/src/services/person/v1/swagger.yml +1157 -0
- package/src/services/teampayApproval/v1/swagger.schema.deref.json +9898 -0
- package/src/services/teampayCardManagement/v1/swagger.schema.deref.json +6187 -0
- package/src/services/teampayClientManagement/v1/swagger.schema.deref.json +4914 -0
- package/src/services/teampayClientManagement/v1/swagger.schema.json +1964 -0
- package/src/services/teampayClientManagement/v1/swagger.yml +1376 -0
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
// athena/visitor.ts
|
|
2
|
+
|
|
3
|
+
import debug from 'debug';
|
|
4
|
+
|
|
5
|
+
const log = debug('athena:visitor');
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
AggrFunc,
|
|
9
|
+
BaseFrom,
|
|
10
|
+
Binary,
|
|
11
|
+
Case,
|
|
12
|
+
Cast,
|
|
13
|
+
Column,
|
|
14
|
+
ColumnRefItem,
|
|
15
|
+
Dual,
|
|
16
|
+
ExpressionValue,
|
|
17
|
+
ExprList,
|
|
18
|
+
From,
|
|
19
|
+
Function,
|
|
20
|
+
Join,
|
|
21
|
+
Select,
|
|
22
|
+
TableExpr,
|
|
23
|
+
With,
|
|
24
|
+
} from './types';
|
|
25
|
+
|
|
26
|
+
// UNNEST is not in types.ts (the grammar produces it but the TS types don't model it).
|
|
27
|
+
export interface UnnestFrom {
|
|
28
|
+
type: 'unnest';
|
|
29
|
+
expr: ColumnRefItem;
|
|
30
|
+
parentheses: boolean;
|
|
31
|
+
as: {
|
|
32
|
+
type: 'function';
|
|
33
|
+
name: { name: { type: string; value: string }[] };
|
|
34
|
+
args: ExprList;
|
|
35
|
+
} | null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ColumnRefItem is extended by the parser with array_index for bracket access (e.g. col['key']).
|
|
39
|
+
export interface ColumnRefWithIndex extends ColumnRefItem {
|
|
40
|
+
array_index: { brackets: true; index: { type: string; value: unknown } }[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// -------------------------------------------------------------------
|
|
44
|
+
// Visitor map — all hooks are optional; implement only what you need.
|
|
45
|
+
// -------------------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
export interface VisitorMap {
|
|
48
|
+
visitSelect?(node: Select): void;
|
|
49
|
+
visitWith?(node: With): void;
|
|
50
|
+
visitBaseFrom?(node: BaseFrom): void;
|
|
51
|
+
visitJoin?(node: Join): void;
|
|
52
|
+
visitTableExpr?(node: TableExpr): void;
|
|
53
|
+
visitUnnest?(node: UnnestFrom): void;
|
|
54
|
+
visitColumn?(node: Column): void;
|
|
55
|
+
visitColumnRef?(node: ColumnRefItem): void;
|
|
56
|
+
visitFunction?(node: Function): void;
|
|
57
|
+
visitBinary?(node: Binary): void;
|
|
58
|
+
visitAggrFunc?(node: AggrFunc): void;
|
|
59
|
+
visitCast?(node: Cast): void;
|
|
60
|
+
visitCase?(node: Case): void;
|
|
61
|
+
visitExprList?(node: ExprList): void;
|
|
62
|
+
visitValue?(node: ExpressionValue): void;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// -------------------------------------------------------------------
|
|
66
|
+
// Type guards — all accept `unknown` so callers can pass untyped AST
|
|
67
|
+
// nodes without an intermediate cast.
|
|
68
|
+
// -------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
export function isUnnestFrom(node: unknown): node is UnnestFrom {
|
|
71
|
+
return typeof node === 'object' && node !== null && (node as { type?: unknown }).type === 'unnest';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function isDual(node: unknown): node is Dual {
|
|
75
|
+
return typeof node === 'object' && node !== null && (node as { type?: unknown }).type === 'dual';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function isTableExpr(node: unknown): node is TableExpr {
|
|
79
|
+
if (typeof node !== 'object' || node === null) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
const expr = (node as { expr?: unknown }).expr;
|
|
83
|
+
return typeof expr === 'object' && expr !== null && 'ast' in expr;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function isJoin(node: unknown): node is Join {
|
|
87
|
+
return (
|
|
88
|
+
!isUnnestFrom(node) &&
|
|
89
|
+
!isDual(node) &&
|
|
90
|
+
!isTableExpr(node) &&
|
|
91
|
+
typeof node === 'object' &&
|
|
92
|
+
node !== null &&
|
|
93
|
+
'join' in node
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function isBaseFrom(node: unknown): node is BaseFrom {
|
|
98
|
+
return (
|
|
99
|
+
!isUnnestFrom(node) &&
|
|
100
|
+
!isDual(node) &&
|
|
101
|
+
!isTableExpr(node) &&
|
|
102
|
+
!isJoin(node) &&
|
|
103
|
+
typeof node === 'object' &&
|
|
104
|
+
node !== null &&
|
|
105
|
+
'table' in node
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function hasArrayIndex(node: ColumnRefItem): node is ColumnRefWithIndex {
|
|
110
|
+
const typed = node as unknown as { array_index?: unknown };
|
|
111
|
+
return Array.isArray(typed.array_index) && typed.array_index.length > 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// -------------------------------------------------------------------
|
|
115
|
+
// Core walk helpers — defined before walk() to satisfy no-use-before-define.
|
|
116
|
+
// walkExpr has a single forward reference to walk() for nested selects.
|
|
117
|
+
// -------------------------------------------------------------------
|
|
118
|
+
|
|
119
|
+
function walkExpr(node: unknown, visitor: VisitorMap): void {
|
|
120
|
+
if (typeof node !== 'object' || node === null) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const typed = node as Record<string, unknown>;
|
|
124
|
+
|
|
125
|
+
switch (typed['type']) {
|
|
126
|
+
case 'select': {
|
|
127
|
+
// eslint-disable-next-line no-use-before-define
|
|
128
|
+
walk(node, visitor);
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
case 'expr': {
|
|
132
|
+
walkExpr((node as Column).expr, visitor);
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case 'binary_expr': {
|
|
136
|
+
const bin = node as Binary;
|
|
137
|
+
visitor.visitBinary?.(bin);
|
|
138
|
+
walkExpr(bin.left, visitor);
|
|
139
|
+
walkExpr(bin.right, visitor);
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
case 'column_ref': {
|
|
143
|
+
visitor.visitColumnRef?.(node as ColumnRefItem);
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
case 'function': {
|
|
147
|
+
const fn = node as Function;
|
|
148
|
+
visitor.visitFunction?.(fn);
|
|
149
|
+
if (fn.args !== undefined) {
|
|
150
|
+
walkExpr(fn.args, visitor);
|
|
151
|
+
}
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
case 'aggr_func': {
|
|
155
|
+
const agg = node as AggrFunc;
|
|
156
|
+
visitor.visitAggrFunc?.(agg);
|
|
157
|
+
walkExpr(agg.args.expr, visitor);
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
case 'cast': {
|
|
161
|
+
const cast = node as Cast;
|
|
162
|
+
visitor.visitCast?.(cast);
|
|
163
|
+
walkExpr(cast.expr, visitor);
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
case 'case': {
|
|
167
|
+
const caseNode = node as Case;
|
|
168
|
+
visitor.visitCase?.(caseNode);
|
|
169
|
+
for (const arm of caseNode.args) {
|
|
170
|
+
if ('cond' in arm) {
|
|
171
|
+
walkExpr(arm.cond, visitor);
|
|
172
|
+
}
|
|
173
|
+
walkExpr(arm.result, visitor);
|
|
174
|
+
}
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
case 'expr_list': {
|
|
178
|
+
const list = node as ExprList;
|
|
179
|
+
visitor.visitExprList?.(list);
|
|
180
|
+
for (const item of list.value) {
|
|
181
|
+
walkExpr(item, visitor);
|
|
182
|
+
}
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
default: {
|
|
186
|
+
// Column wrapper nodes (e.g. bare `SELECT *`) may lack a 'type' field but carry an 'expr'.
|
|
187
|
+
if (typed['type'] === undefined && 'expr' in typed) {
|
|
188
|
+
walkExpr(typed['expr'], visitor);
|
|
189
|
+
} else {
|
|
190
|
+
visitor.visitValue?.(node as ExpressionValue);
|
|
191
|
+
}
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function walkFrom(node: From, visitor: VisitorMap): void {
|
|
198
|
+
if (isDual(node)) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (isUnnestFrom(node)) {
|
|
202
|
+
visitor.visitUnnest?.(node);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (isTableExpr(node)) {
|
|
206
|
+
visitor.visitTableExpr?.(node);
|
|
207
|
+
// eslint-disable-next-line no-use-before-define
|
|
208
|
+
walk(node.expr.ast, visitor);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (isJoin(node)) {
|
|
212
|
+
visitor.visitJoin?.(node);
|
|
213
|
+
if (node.on !== undefined) {
|
|
214
|
+
walkExpr(node.on, visitor);
|
|
215
|
+
}
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
visitor.visitBaseFrom?.(node);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// -------------------------------------------------------------------
|
|
222
|
+
// Core walk — dispatches per node type and recurses into children.
|
|
223
|
+
// -------------------------------------------------------------------
|
|
224
|
+
|
|
225
|
+
export function walk(node: unknown, visitor: VisitorMap): void {
|
|
226
|
+
if (typeof node !== 'object' || node === null) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const typed = node as Record<string, unknown>;
|
|
230
|
+
|
|
231
|
+
if (typed['type'] === 'select') {
|
|
232
|
+
const sel = node as Select;
|
|
233
|
+
visitor.visitSelect?.(sel);
|
|
234
|
+
for (const withItem of sel.with ?? []) {
|
|
235
|
+
visitor.visitWith?.(withItem);
|
|
236
|
+
walk(withItem.stmt.ast, visitor);
|
|
237
|
+
}
|
|
238
|
+
let fromItems: From[];
|
|
239
|
+
if (Array.isArray(sel.from)) {
|
|
240
|
+
fromItems = sel.from;
|
|
241
|
+
} else if (sel.from !== null) {
|
|
242
|
+
fromItems = [sel.from];
|
|
243
|
+
} else {
|
|
244
|
+
fromItems = [];
|
|
245
|
+
}
|
|
246
|
+
for (const fromItem of fromItems) {
|
|
247
|
+
walkFrom(fromItem, visitor);
|
|
248
|
+
}
|
|
249
|
+
for (const col of sel.columns) {
|
|
250
|
+
walkExpr(col, visitor);
|
|
251
|
+
}
|
|
252
|
+
if (sel.where !== null) {
|
|
253
|
+
walkExpr(sel.where, visitor);
|
|
254
|
+
}
|
|
255
|
+
if (sel._next !== undefined) {
|
|
256
|
+
walk(sel._next, visitor);
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
walkExpr(node, visitor);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// -------------------------------------------------------------------
|
|
264
|
+
// Convenience extractors — replace ad-hoc JSONPath queries.
|
|
265
|
+
// -------------------------------------------------------------------
|
|
266
|
+
|
|
267
|
+
/** Collect all column_ref nodes within an expression subtree. */
|
|
268
|
+
export function extractColumnRefs(expr: unknown): ColumnRefItem[] {
|
|
269
|
+
const refs: ColumnRefItem[] = [];
|
|
270
|
+
walkExpr(expr, {
|
|
271
|
+
visitColumnRef(node) {
|
|
272
|
+
refs.push(node);
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
return refs;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Return the path string from the first json_extract_scalar / json_extract call found. */
|
|
279
|
+
export function extractJsonExtractPath(expr: unknown): string | undefined {
|
|
280
|
+
let path: string | undefined;
|
|
281
|
+
walkExpr(expr, {
|
|
282
|
+
visitFunction(node) {
|
|
283
|
+
if (path !== undefined) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
const fnName = node.name.name[0]?.value;
|
|
287
|
+
if (fnName === 'json_extract_scalar' || fnName === 'json_extract') {
|
|
288
|
+
const pathArg = node.args?.value[1];
|
|
289
|
+
if (pathArg !== undefined) {
|
|
290
|
+
const val = (pathArg as unknown as { value?: unknown }).value;
|
|
291
|
+
if (typeof val === 'string') {
|
|
292
|
+
path = val;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
log('extractJsonExtractPath, function:', fnName, path);
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
});
|
|
299
|
+
return path;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export interface JsonExtractCall {
|
|
303
|
+
ref: ColumnRefItem;
|
|
304
|
+
path: string;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** Collect ALL json_extract / json_extract_scalar calls as (source column_ref, path) pairs. */
|
|
308
|
+
export function extractJsonExtractCalls(expr: unknown): JsonExtractCall[] {
|
|
309
|
+
const calls: JsonExtractCall[] = [];
|
|
310
|
+
walkExpr(expr, {
|
|
311
|
+
visitFunction(node) {
|
|
312
|
+
const fnName = node.name.name[0]?.value;
|
|
313
|
+
if (fnName !== 'json_extract_scalar' && fnName !== 'json_extract') {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const sourceArg = node.args?.value[0];
|
|
317
|
+
const pathArg = node.args?.value[1];
|
|
318
|
+
if (sourceArg === undefined || pathArg === undefined) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const sourceRefs = extractColumnRefs(sourceArg);
|
|
322
|
+
if (sourceRefs.length !== 1) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const [ref] = sourceRefs;
|
|
326
|
+
const path = (pathArg as unknown as { value?: unknown }).value;
|
|
327
|
+
if (ref === undefined || typeof path !== 'string') {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
calls.push({ ref, path });
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
return calls;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/** Return the JSONPath-style string from a bracket accessor (col['key']), or undefined. */
|
|
337
|
+
export function extractBracketAccessorPath(expr: unknown): string | undefined {
|
|
338
|
+
let path: string | undefined;
|
|
339
|
+
walkExpr(expr, {
|
|
340
|
+
visitColumnRef(node) {
|
|
341
|
+
if (path !== undefined || !hasArrayIndex(node)) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
const indexValue = node.array_index[0]?.index.value;
|
|
345
|
+
if (typeof indexValue === 'string') {
|
|
346
|
+
path = `$["${indexValue}"]`;
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
});
|
|
350
|
+
return path;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/** Return true if the expression tree contains any function or aggregate call. */
|
|
354
|
+
export function hasFunctionCalls(expr: unknown): boolean {
|
|
355
|
+
let found = false;
|
|
356
|
+
walkExpr(expr, {
|
|
357
|
+
visitFunction() {
|
|
358
|
+
found = true;
|
|
359
|
+
},
|
|
360
|
+
visitAggrFunc() {
|
|
361
|
+
found = true;
|
|
362
|
+
},
|
|
363
|
+
});
|
|
364
|
+
return found;
|
|
365
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -29,6 +29,7 @@ import requireServiceCallResponseDeclaration, {
|
|
|
29
29
|
import requireAwsConfig, { ruleId as requireAwsConfigRuleId } from './aws/require-aws-config.ts';
|
|
30
30
|
import requireAWSBareBones, { ruleId as requireAWSBareBonesRuleId } from './aws/require-aws-bare-bones.ts';
|
|
31
31
|
import requireConsistentRead, { ruleId as requireConsistentReadRuleId } from './aws/require-consistent-read.ts';
|
|
32
|
+
import athena, { ruleId as athenaRuleId } from './athena/athena.ts';
|
|
32
33
|
import filePathComment from './file-path-comment.ts';
|
|
33
34
|
import noCardNumbers from './no-card-numbers.ts';
|
|
34
35
|
import noEnum from './no-enum.ts';
|
|
@@ -76,6 +77,7 @@ const rules: Record<string, TSESLint.LooseRuleDefinition> = {
|
|
|
76
77
|
[requireTypeOutOfTypeOnlyImportsRuleId]: requireTypeOutOfTypeOnlyImports,
|
|
77
78
|
[requireAWSBareBonesRuleId]: requireAWSBareBones,
|
|
78
79
|
[requireConsistentReadRuleId]: requireConsistentRead,
|
|
80
|
+
[athenaRuleId]: athena,
|
|
79
81
|
};
|
|
80
82
|
|
|
81
83
|
const plugin: TSESLint.FlatConfig.Plugin = {
|
|
@@ -118,6 +120,7 @@ const configs: Record<string, TSESLint.FlatConfig.Config[]> = {
|
|
|
118
120
|
[`@checkdigit/${requireConsistentReadRuleId}`]: 'error',
|
|
119
121
|
[`@checkdigit/${requireAwsConfigRuleId}`]: 'error',
|
|
120
122
|
[`@checkdigit/${requireAWSBareBonesRuleId}`]: 'error',
|
|
123
|
+
[`@checkdigit/${athenaRuleId}`]: 'error',
|
|
121
124
|
},
|
|
122
125
|
},
|
|
123
126
|
],
|
|
@@ -156,6 +159,7 @@ const configs: Record<string, TSESLint.FlatConfig.Config[]> = {
|
|
|
156
159
|
[`@checkdigit/${requireConsistentReadRuleId}`]: 'off',
|
|
157
160
|
[`@checkdigit/${requireAwsConfigRuleId}`]: 'off',
|
|
158
161
|
[`@checkdigit/${requireAWSBareBonesRuleId}`]: 'off',
|
|
162
|
+
[`@checkdigit/${athenaRuleId}`]: 'off',
|
|
159
163
|
},
|
|
160
164
|
},
|
|
161
165
|
],
|
package/src/no-side-effects.ts
CHANGED
|
@@ -203,7 +203,7 @@ const rule: ReturnType<typeof createRule> = createRule({
|
|
|
203
203
|
},
|
|
204
204
|
defaultOptions: [{ excludedIdentifiers: [''] }],
|
|
205
205
|
create(context) {
|
|
206
|
-
const options: RuleOptions = context.options[0]
|
|
206
|
+
const options: RuleOptions = context.options[0];
|
|
207
207
|
const excludedIdentifiers = options.excludedIdentifiers.length > 0 ? options.excludedIdentifiers : [];
|
|
208
208
|
return {
|
|
209
209
|
Program(node: TSESTree.Program) {
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { StatusCodes } from 'http-status-codes';
|
|
10
|
-
import { AST_NODE_TYPES, ESLintUtils, TSESLint, TSESTree } from '@typescript-eslint/utils';
|
|
11
|
-
import getDocumentationUrl from './get-documentation-url';
|
|
10
|
+
import { AST_NODE_TYPES, ESLintUtils, type TSESLint, type TSESTree } from '@typescript-eslint/utils';
|
|
11
|
+
import getDocumentationUrl from './get-documentation-url.ts';
|
|
12
12
|
|
|
13
13
|
export const ruleId = 'no-status-code-assert';
|
|
14
14
|
const NO_STATUS_CODE_ASSERT = 'NO_STATUS_CODE_ASSERT';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// openapi/deref-schema.ts
|
|
2
|
+
|
|
3
|
+
import { promises as fs } from 'node:fs';
|
|
4
|
+
|
|
5
|
+
import { dereference } from '@apidevtools/json-schema-ref-parser';
|
|
6
|
+
|
|
7
|
+
export async function derefSchema(schemaFileName: string): Promise<void> {
|
|
8
|
+
const schemaFile = await fs.readFile(`${schemaFileName}.json`, 'utf-8');
|
|
9
|
+
const adjustedSchemaFileForDeref = schemaFile.replace(/"\$ref": ".*\/definitions\//gu, '"$ref": "#/definitions/');
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
11
|
+
const json = JSON.parse(adjustedSchemaFileForDeref);
|
|
12
|
+
const deref = await dereference(json);
|
|
13
|
+
await fs.writeFile(`${schemaFileName}.deref.json`, JSON.stringify(deref, null, 2));
|
|
14
|
+
}
|