@checkdigit/eslint-plugin 7.18.0-PR.143-8290 → 7.18.0-PR.143-0de2
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-matcher.mjs +169 -79
- package/dist-mjs/athena/athena.mjs +16 -1
- package/dist-types/athena/types.d.ts +2 -2
- package/package.json +1 -1
- package/src/athena/api-matcher.ts +204 -105
- package/src/athena/athena.ts +17 -0
- package/src/athena/types.ts +1 -1
|
@@ -1,103 +1,193 @@
|
|
|
1
1
|
// src/athena/api-matcher.ts
|
|
2
2
|
import debug from "debug";
|
|
3
|
-
import { JSONPath } from "jsonpath-plus";
|
|
4
3
|
var log = debug("eslint-plugin:athena:api-matcher");
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
var ALWAYS_TRUE = () => true;
|
|
5
|
+
function rec(node) {
|
|
6
|
+
return typeof node === "object" && node !== null ? node : void 0;
|
|
7
7
|
}
|
|
8
|
-
function
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
});
|
|
13
|
-
if (pathPartCondition !== void 0) {
|
|
14
|
-
const [pathPartIndex] = JSONPath({
|
|
15
|
-
json: pathPartCondition,
|
|
16
|
-
path: "$.left.array_index[0].index.value"
|
|
17
|
-
});
|
|
18
|
-
const [pathPartMatch] = JSONPath({
|
|
19
|
-
json: pathPartCondition,
|
|
20
|
-
path: "$.right.value"
|
|
21
|
-
});
|
|
22
|
-
return (path, _method) => {
|
|
23
|
-
const parts = path.split("/");
|
|
24
|
-
const part = parts[pathPartIndex - 1];
|
|
25
|
-
log(`checking path part`, { path, pathPartIndex, part, pathPartMatch });
|
|
26
|
-
return part?.startsWith(":") === true ? true : parts[pathPartIndex - 1] === pathPartMatch;
|
|
27
|
-
};
|
|
8
|
+
function getFunctionName(node) {
|
|
9
|
+
const fn = rec(node);
|
|
10
|
+
if (fn?.["type"] !== "function") {
|
|
11
|
+
return void 0;
|
|
28
12
|
}
|
|
29
|
-
|
|
13
|
+
const name = fn["name"];
|
|
14
|
+
const firstName = name?.name[0];
|
|
15
|
+
return firstName === void 0 ? void 0 : firstName.value.toLowerCase();
|
|
30
16
|
}
|
|
31
|
-
function
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
});
|
|
36
|
-
if (pathPartCount !== void 0) {
|
|
37
|
-
return (path, _method) => {
|
|
38
|
-
const parts = path.split("/");
|
|
39
|
-
return parts.length === pathPartCount;
|
|
40
|
-
};
|
|
17
|
+
function getColumnName(node) {
|
|
18
|
+
const col = rec(node);
|
|
19
|
+
if (col?.["type"] !== "column_ref") {
|
|
20
|
+
return void 0;
|
|
41
21
|
}
|
|
42
|
-
|
|
22
|
+
const column = node.column;
|
|
23
|
+
return typeof column === "string" ? column.toLowerCase() : void 0;
|
|
24
|
+
}
|
|
25
|
+
function getColumnTable(node) {
|
|
26
|
+
const col = rec(node);
|
|
27
|
+
if (col?.["type"] !== "column_ref") {
|
|
28
|
+
return void 0;
|
|
29
|
+
}
|
|
30
|
+
return node.table;
|
|
31
|
+
}
|
|
32
|
+
function getStringValue(node) {
|
|
33
|
+
const val = rec(node);
|
|
34
|
+
if (val?.["type"] !== "single_quote_string" && val?.["type"] !== "string") {
|
|
35
|
+
return void 0;
|
|
36
|
+
}
|
|
37
|
+
return typeof val["value"] === "string" ? val["value"] : void 0;
|
|
38
|
+
}
|
|
39
|
+
function getNumberValue(node) {
|
|
40
|
+
const val = rec(node);
|
|
41
|
+
return val?.["type"] === "number" && typeof val["value"] === "number" ? val["value"] : void 0;
|
|
42
|
+
}
|
|
43
|
+
function isSplitUrlIndexed(node) {
|
|
44
|
+
const fn = rec(node);
|
|
45
|
+
if (fn?.["type"] !== "function") {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (getFunctionName(node) !== "split") {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const args = fn["args"]?.value;
|
|
52
|
+
if (!Array.isArray(args) || args.length < 2) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (getColumnName(args[0]) !== "url") {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
if (getStringValue(args[1]) !== "/") {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return Array.isArray(fn["array_index"]) && fn["array_index"].length > 0;
|
|
62
|
+
}
|
|
63
|
+
function isCardinalitySplitUrl(node) {
|
|
64
|
+
const fn = rec(node);
|
|
65
|
+
if (fn?.["type"] !== "function") {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
if (getFunctionName(node) !== "cardinality") {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
const outerArgs = fn["args"]?.value;
|
|
72
|
+
if (!Array.isArray(outerArgs) || outerArgs.length === 0) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
const innerFn = rec(outerArgs[0]);
|
|
76
|
+
if (innerFn?.["type"] !== "function") {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
if (getFunctionName(outerArgs[0]) !== "split") {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
const innerArgs = innerFn["args"]?.value;
|
|
83
|
+
if (!Array.isArray(innerArgs) || innerArgs.length < 2) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
return getColumnName(innerArgs[0]) === "url" && getStringValue(innerArgs[1]) === "/";
|
|
43
87
|
}
|
|
44
|
-
function
|
|
45
|
-
|
|
88
|
+
function getConditionTableQualifier(left) {
|
|
89
|
+
const colName = getColumnName(left);
|
|
90
|
+
if (colName !== void 0) {
|
|
91
|
+
return getColumnTable(left);
|
|
92
|
+
}
|
|
93
|
+
if (isSplitUrlIndexed(left)) {
|
|
94
|
+
const args = rec(left)?.["args"]?.value;
|
|
95
|
+
return getColumnTable(args?.[0]) ?? null;
|
|
96
|
+
}
|
|
97
|
+
if (isCardinalitySplitUrl(left)) {
|
|
98
|
+
const outerArgs = rec(left)?.["args"]?.value;
|
|
99
|
+
const splitFn = rec(outerArgs?.[0]);
|
|
100
|
+
const innerArgs = splitFn?.["args"]?.value;
|
|
101
|
+
return getColumnTable(innerArgs?.[0]) ?? null;
|
|
102
|
+
}
|
|
103
|
+
return void 0;
|
|
46
104
|
}
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
105
|
+
function buildLeafPredicate(node, tableAlias) {
|
|
106
|
+
if (node.operator !== "=") {
|
|
107
|
+
return void 0;
|
|
108
|
+
}
|
|
109
|
+
const { left, right } = node;
|
|
110
|
+
const conditionTable = getConditionTableQualifier(left);
|
|
111
|
+
if (conditionTable !== null && conditionTable !== void 0 && tableAlias !== null && conditionTable !== tableAlias) {
|
|
112
|
+
return void 0;
|
|
113
|
+
}
|
|
114
|
+
if (getColumnName(left) === "method") {
|
|
115
|
+
const value = getStringValue(right);
|
|
116
|
+
if (value !== void 0) {
|
|
117
|
+
return (_path, method) => method === value;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (getColumnName(left) === "responsestatus") {
|
|
121
|
+
const value = getStringValue(right);
|
|
122
|
+
if (value !== void 0) {
|
|
123
|
+
return (_path, _method, responseCode) => responseCode === value;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (isSplitUrlIndexed(left)) {
|
|
127
|
+
const index = left.array_index[0]?.index.value;
|
|
128
|
+
const value = getStringValue(right);
|
|
129
|
+
if (typeof index === "number" && value !== void 0) {
|
|
130
|
+
return (path) => {
|
|
131
|
+
const parts = path.split("/");
|
|
132
|
+
const part = parts[index - 1];
|
|
133
|
+
log(`checking path part`, { path, index, part, value });
|
|
134
|
+
return part?.startsWith(":") === true ? true : part === value;
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (isCardinalitySplitUrl(left)) {
|
|
139
|
+
const count = getNumberValue(right);
|
|
140
|
+
if (count !== void 0) {
|
|
141
|
+
return (path) => path.split("/").length === count;
|
|
142
|
+
}
|
|
54
143
|
}
|
|
55
144
|
return void 0;
|
|
56
145
|
}
|
|
57
|
-
function
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
146
|
+
function buildPredicate(expr, tableAlias) {
|
|
147
|
+
const node = rec(expr);
|
|
148
|
+
if (node?.["type"] !== "binary_expr") {
|
|
149
|
+
return ALWAYS_TRUE;
|
|
150
|
+
}
|
|
151
|
+
const binary = expr;
|
|
152
|
+
switch (binary.operator) {
|
|
153
|
+
case "AND": {
|
|
154
|
+
const leftPred = buildPredicate(binary.left, tableAlias);
|
|
155
|
+
const rightPred = buildPredicate(binary.right, tableAlias);
|
|
156
|
+
return (path, method, code) => leftPred(path, method, code) && rightPred(path, method, code);
|
|
157
|
+
}
|
|
158
|
+
case "OR": {
|
|
159
|
+
const leftPred = buildPredicate(binary.left, tableAlias);
|
|
160
|
+
const rightPred = buildPredicate(binary.right, tableAlias);
|
|
161
|
+
return (path, method, code) => leftPred(path, method, code) || rightPred(path, method, code);
|
|
162
|
+
}
|
|
163
|
+
case "NOT": {
|
|
164
|
+
const innerPred = buildPredicate(binary.left, tableAlias);
|
|
165
|
+
return (path, method, code) => !innerPred(path, method, code);
|
|
166
|
+
}
|
|
167
|
+
default: {
|
|
168
|
+
return buildLeafPredicate(binary, tableAlias) ?? ALWAYS_TRUE;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
63
171
|
}
|
|
64
172
|
function matchApi(selectAST, tableAST, apiSchemas) {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
getMethodMatcher(selectAST, tableAST)
|
|
69
|
-
].flat().filter((matcher) => matcher !== void 0);
|
|
70
|
-
const allOperationSchemas = apiSchemas.flatMap((apiSchema) => Object.entries(apiSchema.apis)).flatMap(
|
|
173
|
+
const tableAlias = tableAST.as ?? null;
|
|
174
|
+
const predicate = buildPredicate(selectAST.where ?? null, tableAlias);
|
|
175
|
+
const allOperations = apiSchemas.flatMap((apiSchema) => Object.entries(apiSchema.apis)).flatMap(
|
|
71
176
|
([path, operations]) => Object.entries(operations).map(([method, operationSchemas]) => ({
|
|
72
177
|
path,
|
|
73
178
|
method: method.toUpperCase(),
|
|
74
179
|
operationSchemas
|
|
75
180
|
}))
|
|
76
181
|
);
|
|
77
|
-
log("total operation schemas",
|
|
78
|
-
const
|
|
79
|
-
({ path, method }) =>
|
|
182
|
+
log("total operation schemas", allOperations.length);
|
|
183
|
+
const matchedApis = allOperations.flatMap(
|
|
184
|
+
({ path, method, operationSchemas }) => Object.entries(operationSchemas.responses).flatMap(
|
|
185
|
+
([responseCode, responseSchema]) => predicate(path, method, responseCode) ? [{ path, method, request: operationSchemas.request, response: responseSchema }] : []
|
|
186
|
+
)
|
|
80
187
|
);
|
|
81
|
-
log("matched
|
|
82
|
-
if (matchedOperationSchemas.length === 0) {
|
|
83
|
-
log("no matched operation schema");
|
|
84
|
-
throw new Error("no matched operation schema");
|
|
85
|
-
}
|
|
86
|
-
const matchedResponseStatus = getResponseStatusToMatch(selectAST, tableAST);
|
|
87
|
-
log("matchedResponseStatus", matchedResponseStatus);
|
|
88
|
-
const matchedApis = matchedOperationSchemas.flatMap(
|
|
89
|
-
(operation) => Object.entries(operation.operationSchemas.responses).map(([responseCode, responseSchema]) => {
|
|
90
|
-
const matchedResponseSchema = matchedResponseStatus === void 0 || responseCode === matchedResponseStatus ? responseSchema : void 0;
|
|
91
|
-
return matchedResponseSchema === void 0 ? void 0 : {
|
|
92
|
-
path: operation.path,
|
|
93
|
-
method: operation.method,
|
|
94
|
-
request: operation.operationSchemas.request,
|
|
95
|
-
response: matchedResponseSchema
|
|
96
|
-
};
|
|
97
|
-
})
|
|
98
|
-
).filter((api) => api !== void 0);
|
|
188
|
+
log("matched apis", matchedApis.length);
|
|
99
189
|
if (matchedApis.length === 0) {
|
|
100
|
-
log("no api
|
|
190
|
+
log("no matched api");
|
|
101
191
|
throw new Error("no matched api");
|
|
102
192
|
}
|
|
103
193
|
return matchedApis;
|
|
@@ -105,4 +195,4 @@ function matchApi(selectAST, tableAST, apiSchemas) {
|
|
|
105
195
|
export {
|
|
106
196
|
matchApi
|
|
107
197
|
};
|
|
108
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
198
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2F0aGVuYS9hcGktbWF0Y2hlci50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFFQSxPQUFPLFdBQVc7QUFNbEIsSUFBTSxNQUFNLE1BQU0sa0NBQWtDO0FBa0JwRCxJQUFNLGNBQWtDLE1BQU07QUFJOUMsU0FBUyxJQUFJLE1BQW9EO0FBQy9ELFNBQU8sT0FBTyxTQUFTLFlBQVksU0FBUyxPQUFRLE9BQW1DO0FBQ3pGO0FBRUEsU0FBUyxnQkFBZ0IsTUFBbUM7QUFDMUQsUUFBTSxLQUFLLElBQUksSUFBSTtBQUNuQixNQUFJLEtBQUssTUFBTSxNQUFNLFlBQVk7QUFDL0IsV0FBTztBQUFBLEVBQ1Q7QUFDQSxRQUFNLE9BQU8sR0FBRyxNQUFNO0FBQ3RCLFFBQU0sWUFBWSxNQUFNLEtBQUssQ0FBQztBQUM5QixTQUFPLGNBQWMsU0FBWSxTQUFZLFVBQVUsTUFBTSxZQUFZO0FBQzNFO0FBRUEsU0FBUyxjQUFjLE1BQW1DO0FBQ3hELFFBQU0sTUFBTSxJQUFJLElBQUk7QUFDcEIsTUFBSSxNQUFNLE1BQU0sTUFBTSxjQUFjO0FBQ2xDLFdBQU87QUFBQSxFQUNUO0FBQ0EsUUFBTSxTQUFVLEtBQXVCO0FBQ3ZDLFNBQU8sT0FBTyxXQUFXLFdBQVcsT0FBTyxZQUFZLElBQUk7QUFDN0Q7QUFFQSxTQUFTLGVBQWUsTUFBMEM7QUFDaEUsUUFBTSxNQUFNLElBQUksSUFBSTtBQUNwQixNQUFJLE1BQU0sTUFBTSxNQUFNLGNBQWM7QUFDbEMsV0FBTztBQUFBLEVBQ1Q7QUFDQSxTQUFRLEtBQXVCO0FBQ2pDO0FBRUEsU0FBUyxlQUFlLE1BQW1DO0FBQ3pELFFBQU0sTUFBTSxJQUFJLElBQUk7QUFDcEIsTUFBSSxNQUFNLE1BQU0sTUFBTSx5QkFBeUIsTUFBTSxNQUFNLE1BQU0sVUFBVTtBQUN6RSxXQUFPO0FBQUEsRUFDVDtBQUNBLFNBQU8sT0FBTyxJQUFJLE9BQU8sTUFBTSxXQUFXLElBQUksT0FBTyxJQUFJO0FBQzNEO0FBRUEsU0FBUyxl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
|
|
@@ -235,6 +235,21 @@ function checkSelect(selectAST, ctx, withTableName) {
|
|
|
235
235
|
const columns = resolveSelectColumns(select, selectCtx);
|
|
236
236
|
applyUnnestPost(deferredUnnest, columns);
|
|
237
237
|
log("resolved columns", [...columns.keys()]);
|
|
238
|
+
const allTables = [...selectCtx.tables.values()].flat();
|
|
239
|
+
if (select.where !== null) {
|
|
240
|
+
validateComplexColumnExpression(select.where, allTables, selectCtx);
|
|
241
|
+
}
|
|
242
|
+
if (select.having !== null) {
|
|
243
|
+
validateComplexColumnExpression(select.having, allTables, selectCtx);
|
|
244
|
+
}
|
|
245
|
+
for (const orderItem of select.orderby ?? []) {
|
|
246
|
+
validateComplexColumnExpression(orderItem.expr, allTables, selectCtx);
|
|
247
|
+
}
|
|
248
|
+
if (select.groupby?.columns !== void 0) {
|
|
249
|
+
for (const groupCol of select.groupby.columns) {
|
|
250
|
+
validateComplexColumnExpression(groupCol, allTables, selectCtx);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
238
253
|
if (select._next !== void 0) {
|
|
239
254
|
checkSelect(select._next, ctx, withTableName);
|
|
240
255
|
}
|
|
@@ -328,4 +343,4 @@ export {
|
|
|
328
343
|
athena_default as default,
|
|
329
344
|
ruleId
|
|
330
345
|
};
|
|
331
|
-
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2F0aGVuYS9hdGhlbmEudHMiXSwKICAibWFwcGluZ3MiOiAiO0FBUUEsU0FBUyxVQUFVLGNBQWM7QUFFakMsT0FBTyxXQUFXO0FBQ2xCLFNBQVMsZ0JBQWdCO0FBQ3pCLFNBQVMsbUJBQWtDO0FBRzNDLFNBQVMsYUFBYTtBQUV0QixTQUFTLGdCQUFnQjtBQUN6QixTQUFTLGlCQUFpQjtBQUMxQjtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsT0FJSztBQUNQLFNBQVMsMEJBQTBCO0FBQ25DO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBRUEsSUFBTSxTQUFTO0FBRXRCLElBQU0sTUFBTSxNQUFNLHNCQUFzQjtBQUN4QyxJQUFNLGFBQWEsWUFBWSxZQUFZLENBQUMsU0FBUyxJQUFJO0FBRXpELElBQU0sZ0JBQWdCO0FBQ3RCLElBQU0sZUFBZTtBQUVyQixJQUFNLGNBQU4sY0FBMEIsTUFBTTtBQUFBLEVBQ3ZCO0FBQUEsRUFDUCxZQUFZLE1BQWMsU0FBaUI7QUFDekMsVUFBTSxPQUFPO0FBQ2IsU0FBSyxPQUFPO0FBQ1osU0FBSyxPQUFPO0FBQUEsRUFDZDtBQUNGO0FBTUEsU0FBUyxZQUFZLE1BQWMsUUFBc0IsS0FBOEI7QUFDckYsU0FBTyxRQUFRLFNBQVksRUFBRSxNQUFNLFFBQVEsSUFBSSxJQUFJLEVBQUUsTUFBTSxPQUFPO0FBQ3BFO0FBR0EsU0FBUyxjQUFjLGFBQXFCLEtBQW1CO0FBQzdELE1BQUksVUFBVSxJQUFJLFdBQVcsSUFBSSxXQUFXO0FBQzVDLE1BQUksWUFBWSxRQUFXO0FBQ3pCLGNBQVUsVUFBVSxXQUFXO0FBQy9CLFFBQUksV0FBVyxJQUFJLGFBQWEsT0FBTztBQUFBLEVBQ3pDO0FBQ0EsU0FBTztBQUNUO0FBR0EsU0FBUyxhQUFhLGFBQXFCLEtBQW9DO0FBQzdFLFFBQU0sWUFBWSxJ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
|
|
346
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2F0aGVuYS9hdGhlbmEudHMiXSwKICAibWFwcGluZ3MiOiAiO0FBUUEsU0FBUyxVQUFVLGNBQWM7QUFFakMsT0FBTyxXQUFXO0FBQ2xCLFNBQVMsZ0JBQWdCO0FBQ3pCLFNBQVMsbUJBQWtDO0FBRzNDLFNBQVMsYUFBYTtBQUV0QixTQUFTLGdCQUFnQjtBQUN6QixTQUFTLGlCQUFpQjtBQUMxQjtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsT0FJSztBQUNQLFNBQVMsMEJBQTBCO0FBQ25DO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBRUEsSUFBTSxTQUFTO0FBRXRCLElBQU0sTUFBTSxNQUFNLHNCQUFzQjtBQUN4QyxJQUFNLGFBQWEsWUFBWSxZQUFZLENBQUMsU0FBUyxJQUFJO0FBRXpELElBQU0sZ0JBQWdCO0FBQ3RCLElBQU0sZUFBZTtBQUVyQixJQUFNLGNBQU4sY0FBMEIsTUFBTTtBQUFBLEVBQ3ZCO0FBQUEsRUFDUCxZQUFZLE1BQWMsU0FBaUI7QUFDekMsVUFBTSxPQUFPO0FBQ2IsU0FBSyxPQUFPO0FBQ1osU0FBSyxPQUFPO0FBQUEsRUFDZDtBQUNGO0FBTUEsU0FBUyxZQUFZLE1BQWMsUUFBc0IsS0FBOEI7QUFDckYsU0FBTyxRQUFRLFNBQVksRUFBRSxNQUFNLFFBQVEsSUFBSSxJQUFJLEVBQUUsTUFBTSxPQUFPO0FBQ3BFO0FBR0EsU0FBUyxjQUFjLGFBQXFCLEtBQW1CO0FBQzdELE1BQUksVUFBVSxJQUFJLFdBQVcsSUFBSSxXQUFXO0FBQzVDLE1BQUksWUFBWSxRQUFXO0FBQ3pCLGNBQVUsVUFBVSxXQUFXO0FBQy9CLFFBQUksV0FBVyxJQUFJLGFBQWEsT0FBTztBQUFBLEVBQ3pDO0FBQ0EsU0FBTztBQUNUO0FBR0EsU0FBUyxhQUFhLGFBQXFCLEtBQW9DO0FBQzdFLFFBQU0sWUFBWSxJQUFJLFFBQVEsSUFBSSxXQUFXLEtBQUs7QUFDbEQsU0FBTyxJQUFJLE9BQU8sSUFBSSxTQUFTLEtBQUssQ0FBQztBQUN2QztBQUdBLFNBQVMsZ0JBQWdCLFFBQXdCO0FBQy9DLE1BQUksTUFBTSxRQUFRLE9BQU8sSUFBSSxHQUFHO0FBQzlCLFdBQU8sT0FBTztBQUFBLEVBQ2hCO0FBQ0EsTUFBSSxPQUFPLFNBQVMsTUFBTTtBQUN4QixXQUFPLENBQUMsT0FBTyxJQUFJO0FBQUEsRUFDckI7QUFDQSxTQUFPLENBQUM7QUFDVjtBQU1BLFNBQVMsa0JBQWtCLFFBQWdCLEtBQXlCO0FBQ2xFLGFBQVcsUUFBUSxnQkFBZ0IsTUFBTSxHQUFHO0FBQzFDLFFBQUksYUFBYSxJQUFJLEdBQUc7QUFDdEI7QUFBQSxJQUNGO0FBRUEsUUFBSSxPQUFPLElBQUksR0FBRztBQUNoQixZQUFNLEVBQUUsT0FBT0EsWUFBVyxJQUFJQyxPQUFNLElBQUk7QUFDeEMsVUFBSUEsV0FBVSxNQUFNO0FBQ2xCLFlBQUksUUFBUSxJQUFJQSxRQUFPRCxVQUFTO0FBQUEsTUFDbEM7QUFDQSxVQUFJLENBQUMsSUFBSSxPQUFPLElBQUlBLFVBQVMsR0FBRztBQUM5QixjQUFNRSxjQUFhLGNBQWNGLFlBQVcsR0FBRztBQUMvQyxjQUFNRyxjQUFhLFNBQVMsUUFBUSxNQUFNRCxXQUFVLEtBQUssQ0FBQztBQUMxRCxZQUFJLE9BQU8sSUFBSUYsWUFBVyxtQkFBbUJBLFlBQVdHLFdBQVUsQ0FBQztBQUFBLE1BQ3JFO0FBQ0E7QUFBQSxJQUNGO0FBRUEsUUFBSSxDQUFDLFdBQVcsSUFBSSxHQUFHO0FBQ3JCO0FBQUEsSUFDRjtBQUVBLFVBQU0sRUFBRSxPQUFPLFdBQVcsSUFBSSxNQUFNLElBQUk7QUFFeEMsUUFBSSxVQUFVLE1BQU07QUFDbEIsVUFBSSxRQUFRLElBQUksT0FBTyxTQUFTO0FBQUEsSUFDbEM7QUFFQSxRQUFJLElBQUksT0FBTyxJQUFJLFNBQVMsR0FBRztBQUM3QjtBQUFBLElBQ0Y7QUFJQSxVQUFNLGFBQWEsY0FBYyxXQUFXLEdBQUc7QUFDL0MsVUFBTSxhQUFhLFNBQVMsUUFBUSxNQUFNLFVBQVUsS0FBSyxDQUFDO0FBQzFELFFBQUksT0FBTyxJQUFJLFdBQVcsbUJBQW1CLFdBQVcsVUFBVSxDQUFDO0FBQUEsRUFDckU7QUFDRjtBQVlBLFNBQVMsc0JBQXNCLFFBQWlDO0FBQzlELFFBQU0sV0FBNEIsQ0FBQztBQUVuQyxhQUFXLFFBQVEsZ0JBQWdCLE1BQU0sR0FBRztBQUMxQyxRQUFJLENBQUMsYUFBYSxJQUFJLEdBQUc7QUFDdkI7QUFBQSxJQUNGO0FBRUEsVUFBTSxhQUFhLE9BQU8sS0FBSyxLQUFLLFdBQVcsV0FBVyxLQUFLLEtBQUssU0FBUztBQUM3RSxXQUFPLEdBQUcsZUFBZSxRQUFXLDREQUE0RDtBQUdoRyxVQUFNLFdBQVcsS0FBSyxJQUFJLEtBQUssTUFBTSxDQUFDO0FBQ3RDLFVBQU0sWUFDSixhQUFhLFVBQWEsT0FBUSxTQUFrQyxXQUFXLFdBQzFFLFNBQWdDLFNBQ2pDO0FBQ04sV0FBTyxHQUFHLGNBQWMsUUFBVyw2REFBNkQ7QUFFaEcsYUFBUyxLQUFLLEVBQUUsWUFBWSxVQUFVLFVBQVUsQ0FBQztBQUFBLEVBQ25EO0FBRUEsU0FBTztBQUNUO0FBRUEsU0FBUyxlQUFlLFVBQTJCLEtBQW9DO0FBQ3JGLFFBQU0sV0FBNEIsQ0FBQztBQUVuQyxhQUFXLEVBQUUsWUFBWSxTQUFTLEtBQUssVUFBVTtBQUUvQyxVQUFNLGFBQWEsQ0FBQyxHQUFHLElBQUksT0FBTyxPQUFPLENBQUMsRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLFVBQVUsTUFBTSxRQUFRLElBQUksVUFBVSxDQUFDO0FBRWhHLFFBQUksZUFBZSxRQUFXO0FBQzVCLGVBQVMsS0FBSyxFQUFFLFlBQVksU0FBUyxDQUFDO0FBQ3RDO0FBQUEsSUFDRjtBQUVBLFVBQU0sZ0JBQWdCLFdBQVcsUUFBUSxJQUFJLFVBQVUsS0FBSyxDQUFDO0FBQzdELFVBQU0sZUFBZSxjQUFjLENBQUMsR0FBRztBQUN2QyxXQUFPLEdBQUcsY0FBYyxTQUFTLFNBQVMseUJBQXlCLFVBQVUsMkJBQTJCO0FBRXhHLFVBQU0sa0JBQWtCLEdBQUcsV0FBVyxRQUFRLGFBQWE7QUFDM0QsUUFBSSxPQUFPLElBQUksaUJBQWlCO0FBQUEsTUFDOUI7QUFBQSxRQUNFLE1BQU07QUFBQSxRQUNOLEdBQUksV0FBVyxpQkFBaUIsU0FBWSxFQUFFLGNBQWMsV0FBVyxhQUFhLElBQUksQ0FBQztBQUFBLFFBQ3pGLFNBQVMsb0JBQUksSUFBSSxDQUFDLENBQUMsVUFBVSxDQUFDLFlBQVksVUFBVSxhQUFhLE9BQU8sY0FBYyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQUEsTUFDbkc7QUFBQSxJQUNGLENBQUM7QUFBQSxFQUNIO0FBRUEsU0FBTztBQUNUO0FBRUEsU0FBUyxnQkFBZ0IsVUFBMkIsU0FBOEM7QUFDaEcsYUFBVyxFQUFFLFlBQVksU0FBUyxLQUFLLFVBQVU7QUFDL0MsVUFBTSxnQkFBZ0IsUUFBUSxJQUFJLFVBQVU7QUFDNUMsV0FBTyxHQUFHLGtCQUFrQixRQUFXLFVBQVUsVUFBVSxnQ0FBZ0M7QUFDM0YsVUFBTSxlQUFlLGNBQWMsQ0FBQyxHQUFHO0FBQ3ZDLFdBQU8sR0FBRyxjQUFjLFNBQVMsU0FBUyx5QkFBeUIsVUFBVSwyQkFBMkI7QUFDeEcsWUFBUSxJQUFJLFVBQVUsQ0FBQyxZQUFZLFVBQVUsYUFBYSxPQUFPLGNBQWMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDO0FBQUEsRUFDMUY7QUFDRjtBQU1BLFNBQVMsMkJBQ1AsYUFDQSxhQUNBLFdBQ0EsU0FDTTtBQUNOLFFBQU0sT0FBTyxlQUFlO0FBQzVCLFVBQVEsSUFBSSxNQUFNLENBQUMsWUFBWSxNQUFNLEVBQUUsTUFBTSxTQUFTLEdBQUcsU0FBbUIsQ0FBQyxDQUFDO0FBQ2hGO0FBRUEsU0FBUyxlQUFlLGtCQUFtQyxTQUE4QztBQUN2RyxhQUFXLFNBQVMsa0JBQWtCO0FBQ3BDLGVBQVcsQ0FBQyxTQUFTLElBQUksS0FBSyxNQUFNLFNBQVM7QUFDM0MsY0FBUSxJQUFJLFNBQVMsSUFBSTtBQUFBLElBQzNCO0FBQUEsRUFDRjtBQUNGO0FBRUEsU0FBUyxvQkFDUCxRQUNBLGtCQUNBLGlCQUNnQjtBQUdoQixRQUFNLGVBQWUsS0FBSyxpQkFBaUIsVUFBVSxDQUFDLEVBQUUsUUFBUSxhQUFhLGdCQUFnQixDQUFDO0FBQzlGLE1BQUksaUJBQWlCLFlBQVk7QUFFakMsUUFBTSxtQkFBbUIsZ0JBQWdCO0FBQUEsSUFBUSxDQUFDLFFBQ2hELFNBQXlCLEVBQUUsTUFBTSxJQUFJLFFBQVEsTUFBTSxhQUFhLENBQUM7QUFBQSxFQUNuRTtBQUNBLE1BQUkscUJBQXFCLGdCQUFnQjtBQUV6QyxNQUFJLGlCQUFpQixXQUFXLEdBQUc7QUFDakMsVUFBTSxJQUFJLFlBQVksY0FBYyxzQkFBc0IsTUFBTSxNQUFNLGdCQUFnQixFQUFFO0FBQUEsRUFDMUY7QUFDQSxTQUFPO0FBQ1Q7QUFFQSxTQUFTLG1CQUNQLFFBQ0Esa0JBQ0EsaUJBQ0EsU0FDQSxXQUNBLFNBQ007QUFDTixRQUFNLG1CQUFtQixvQkFBb0IsUUFBUSxrQkFBa0IsZUFBZTtBQUN0RixVQUFRO0FBQUEsSUFDTjtBQUFBLElBQ0EsaUJBQWlCLElBQUksQ0FBQyxXQUFXLFlBQVksU0FBUyxRQUFRLFNBQW1CLENBQUM7QUFBQSxFQUNwRjtBQUNGO0FBT0EsU0FBUyxnQ0FBZ0MsV0FBb0IsV0FBNEIsS0FBeUI7QUFDaEgsYUFBVyxFQUFFLEtBQUssS0FBSyxLQUFLLHdCQUF3QixTQUFTLEdBQUc7QUFDOUQsVUFBTSxXQUFXLElBQUksU0FBUztBQUM5QixVQUFNLFNBQVMsT0FBTyxJQUFJLFdBQVcsV0FBVyxJQUFJLFNBQVM7QUFDN0QsUUFBSSxXQUFXLFFBQVc7QUFDeEI7QUFBQSxJQUNGO0FBQ0EsVUFBTSxtQkFBbUIsYUFBYSxTQUFZLGFBQWEsVUFBVSxHQUFHLElBQUk7QUFDaEYsVUFBTSxrQkFBa0IsaUJBQWlCLFFBQVEsQ0FBQyxVQUFVLE1BQU0sUUFBUSxJQUFJLE1BQU0sS0FBSyxDQUFDLENBQUM7QUFDM0YsUUFBSSxnQkFBZ0IsU0FBUyxHQUFHO0FBQzlCLDBCQUFvQixRQUFRLE1BQU0sZUFBZTtBQUFBLElBQ25EO0FBQUEsRUFDRjtBQUNGO0FBR0EsU0FBUyx1QkFDUCxXQUNBLGFBQ0EsYUFDQSxLQUNBLFdBQ0EsS0FDQSxTQUNNO0FBQ04sUUFBTSxXQUFXLElBQUksU0FBUztBQUM5QixRQUFNLFNBQVMsT0FBTyxJQUFJLFdBQVcsV0FBVyxJQUFJLFNBQVM7QUFDN0QsU0FBTyxHQUFHLFdBQVcsUUFBVywyQ0FBMkM7QUFFM0UsUUFBTSxtQkFBbUIsYUFBYSxTQUFZLGFBQWEsVUFBVSxHQUFHLElBQUk7QUFDaEYsU0FBTyxHQUFHLGlCQUFpQixTQUFTLEdBQUcseUNBQXlDLE1BQU0sR0FBRztBQUV6RixNQUFJLFdBQVcsS0FBSztBQUNsQixtQkFBZSxrQkFBa0IsT0FBTztBQUN4QztBQUFBLEVBQ0Y7QUFFQSxRQUFNLGdCQUFnQixpQkFBaUIsU0FBUztBQUNoRCxRQUFNLFVBQVUsZ0JBQWdCLGdCQUFnQixjQUFjO0FBQzlELFFBQU0sa0JBQWtCLGlCQUFpQixRQUFRLENBQUMsVUFBVSxNQUFNLFFBQVEsSUFBSSxNQUFNLEtBQUssQ0FBQyxDQUFDO0FBRTNGLE1BQUksZ0JBQWdCLFdBQVcsR0FBRztBQUNoQyxVQUFNLGFBQWEsQ0FBQyxHQUFHLElBQUksT0FBTyxLQUFLLENBQUMsRUFBRSxLQUFLLElBQUk7QUFDbkQsVUFBTSxJQUFJLFlBQVksY0FBYyxzQkFBc0IsTUFBTSxlQUFlLFVBQVUsRUFBRTtBQUFBLEVBQzdGO0FBRUEsUUFBTSxtQkFBbUIsdUJBQXVCLFNBQVMsS0FBSywyQkFBMkIsU0FBUztBQUNsRyxNQUFJLHFCQUFxQixRQUFXO0FBQ2xDLHVCQUFtQixRQUFRLGtCQUFrQixpQkFBaUIsU0FBUyxXQUFXLE9BQU87QUFDekY7QUFBQSxFQUNGO0FBRUEsVUFBUTtBQUFBLElBQ047QUFBQSxJQUNBLGdCQUFnQixJQUFJLENBQUMsUUFBUSxZQUFZLFNBQVMsSUFBSSxRQUFRLFNBQW1CLENBQUM7QUFBQSxFQUNwRjtBQUNGO0FBRUEsU0FBUyxxQkFBcUIsUUFBZ0IsS0FBa0Q7QUFDOUYsUUFBTSxZQUFZLENBQUMsR0FBRyxJQUFJLE9BQU8sT0FBTyxDQUFDLEVBQUUsS0FBSztBQUNoRCxRQUFNLFVBQVUsb0JBQUksSUFBOEI7QUFFbEQsYUFBVyxDQUFDLE9BQU8sU0FBUyxLQUFLLE9BQU8sUUFBUSxRQUFRLEdBQUc7QUFDekQsUUFBSSxvQkFBb0IsU0FBUztBQUVqQyxVQUFNLGNBQWUsVUFBcUMsTUFBTTtBQUNoRSxVQUFNLGNBQWMsT0FBTyxPQUFPLEtBQUssQ0FBQztBQUN4QyxVQUFNLGFBQWEsa0JBQWtCLFNBQVM7QUFFOUMsUUFBSSxXQUFXLFdBQVcsR0FBRztBQUMzQixzQ0FBZ0MsV0FBVyxXQUFXLEdBQUc7QUFDekQsaUNBQTJCLGFBQWEsYUFBYSxXQUFXLE9BQU87QUFDdkU7QUFBQSxJQUNGO0FBRUEsVUFBTSxDQUFDLEdBQUcsSUFBSTtBQUNkLFdBQU8sR0FBRyxRQUFRLE1BQVM7QUFDM0IsMkJBQXVCLFdBQVcsYUFBYSxhQUFhLEtBQUssV0FBVyxLQUFLLE9BQU87QUFBQSxFQUMxRjtBQUVBLFNBQU87QUFDVDtBQU1BLFNBQVMsWUFBWSxXQUEwQixLQUFtQixlQUE4QjtBQUU5RixRQUFNLFNBQVMsVUFBVSxZQUFZLFVBQVUsS0FBSyxNQUFNO0FBRzFELFFBQU0sWUFBWSxtQkFBbUIsR0FBRztBQUd4QyxvQkFBa0IsUUFBUSxTQUFTO0FBR25DLFFBQU0saUJBQWlCLHNCQUFzQixNQUFNO0FBQ25ELFFBQU0saUJBQWlCLGVBQWUsZ0JBQWdCLFNBQVM7QUFHL0QsUUFBTSxVQUFVLHFCQUFxQixRQUFRLFNBQVM7QUFHdEQsa0JBQWdCLGdCQUFnQixPQUFPO0FBRXZDLE1BQUksb0JBQW9CLENBQUMsR0FBRyxRQUFRLEtBQUssQ0FBQyxDQUFDO0FBRzNDLFFBQU0sWUFBWSxDQUFDLEdBQUcsVUFBVSxPQUFPLE9BQU8sQ0FBQyxFQUFFLEtBQUs7QUFDdEQsTUFBSSxPQUFPLFVBQVUsTUFBTTtBQUN6QixvQ0FBZ0MsT0FBTyxPQUFPLFdBQVcsU0FBUztBQUFBLEVBQ3BFO0FBQ0EsTUFBSSxPQUFPLFdBQVcsTUFBTTtBQUMxQixvQ0FBZ0MsT0FBTyxRQUFRLFdBQVcsU0FBUztBQUFBLEVBQ3JFO0FBQ0EsYUFBVyxhQUFhLE9BQU8sV0FBVyxDQUFDLEdBQUc7QUFDNUMsb0NBQWdDLFVBQVUsTUFBTSxXQUFXLFNBQVM7QUFBQSxFQUN0RTtBQUNBLE1BQUksT0FBTyxTQUFTLFlBQVksUUFBVztBQUN6QyxlQUFXLFlBQVksT0FBTyxRQUFRLFNBQVM7QUFDN0Msc0NBQWdDLFVBQVUsV0FBVyxTQUFTO0FBQUEsSUFDaEU7QUFBQSxFQUNGO0FBR0EsTUFBSSxPQUFPLFVBQVUsUUFBVztBQUM5QixnQkFBWSxPQUFPLE9BQU8sS0FBSyxhQUFhO0FBQUEsRUFDOUM7QUFHQSxNQUFJLGtCQUFrQixRQUFXO0FBQy9CLFVBQU0sZ0JBQStCLEVBQUUsTUFBTSxlQUFlLFFBQVE7QUFDcEUsUUFBSSxPQUFPLElBQUksZUFBZSxDQUFDLGFBQWEsQ0FBQztBQUFBLEVBQy9DO0FBQ0Y7QUFFQSxTQUFTLGVBQWUsS0FBVSxLQUF5QjtBQUN6RCxTQUFPLEdBQUcsSUFBSSxTQUFTLFFBQVE7QUFDL0IsUUFBTSxTQUFTO0FBRWYsTUFBSSxPQUFPLFNBQVMsTUFBTTtBQUN4QixlQUFXLFlBQVksT0FBTyxNQUFNO0FBQ2xDLGtCQUFZLFNBQVMsS0FBSyxLQUFLLEtBQUssU0FBUyxLQUFLLEtBQUs7QUFBQSxJQUN6RDtBQUNBLFdBQU8sT0FBTztBQUFBLEVBQ2hCO0FBRUEsY0FBWSxRQUFRLEdBQUc7QUFDekI7QUFNQSxJQUFNLE9BQTJFLFdBQVc7QUFBQSxFQUMxRixNQUFNO0FBQUEsRUFDTixNQUFNO0FBQUEsSUFDSixNQUFNO0FBQUEsSUFDTixNQUFNO0FBQUEsTUFDSixhQUFhO0FBQUEsSUFDZjtBQUFBLElBQ0EsUUFBUSxDQUFDO0FBQUEsSUFDVCxVQUFVO0FBQUEsTUFDUixDQUFDLGFBQWEsR0FBRztBQUFBLE1BQ2pCLENBQUMsWUFBWSxHQUFHO0FBQUEsSUFDbEI7QUFBQSxFQUNGO0FBQUEsRUFDQSxnQkFBZ0IsQ0FBQztBQUFBLEVBQ2pCLE9BQU8sU0FBUztBQUNkLGFBQVMsU0FBUyxLQUFhLFNBQXdCO0FBQ3JELFVBQUksQ0FBQyxxRUFBcUUsS0FBSyxHQUFHLEdBQUc7QUFDbkYsWUFBSSxrQ0FBa0MsRUFBRSxJQUFJLENBQUM7QUFDN0M7QUFBQSxNQUNGO0FBRUEsVUFBSTtBQUNKLFVBQUk7QUFFRixTQUFDLEVBQUUsSUFBSSxJQUFJLE1BQU0sS0FBSyxFQUFFLGtCQUFrQixLQUFLLENBQUM7QUFBQSxNQUNsRCxTQUFTLE9BQU87QUFDZCxZQUFJLDZCQUE2QixFQUFFLE9BQU8sSUFBSSxDQUFDO0FBQy9DLGdCQUFRLE9BQU87QUFBQSxVQUNiLE1BQU07QUFBQSxVQUNOLFdBQVc7QUFBQSxVQUNYLE1BQU0sRUFBRSxjQUFjLEtBQUssVUFBVSxPQUFPLFFBQVcsQ0FBQyxHQUFHLElBQUk7QUFBQSxRQUNqRSxDQUFDO0FBQ0Q7QUFBQSxNQUNGO0FBRUEsWUFBTSxZQUFZLGtCQUFrQjtBQUNwQyxVQUFJO0FBRUYsdUJBQWUsTUFBTSxRQUFRLEdBQUcsSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLFNBQVM7QUFBQSxNQUM3RCxTQUFTLE9BQU87QUFDZCxZQUFJLDZCQUE2QixFQUFFLE9BQU8sSUFBSSxDQUFDO0FBQy9DLFlBQUksaUJBQWlCLGFBQWE7QUFDaEMsa0JBQVEsT0FBTztBQUFBLFlBQ2IsTUFBTTtBQUFBLFlBQ04sV0FBVztBQUFBLFlBQ1gsTUFBTSxFQUFFLGNBQWMsTUFBTSxRQUFRO0FBQUEsVUFDdEMsQ0FBQztBQUFBLFFBQ0gsT0FBTztBQUVMLGtCQUFRLE1BQU0sbUJBQW1CLE1BQU0sY0FBYyxRQUFRLFFBQVEsTUFBTSxLQUFLO0FBQ2hGLGtCQUFRLE9BQU87QUFBQSxZQUNiLE1BQU07QUFBQSxZQUNOLFdBQVc7QUFBQSxZQUNYLE1BQU07QUFBQSxjQUNKLGNBQWMsaUJBQWlCLFFBQVEsT0FBTyxLQUFLLElBQUksS0FBSyxVQUFVLE9BQU8sUUFBVyxDQUFDO0FBQUEsWUFDM0Y7QUFBQSxVQUNGLENBQUM7QUFBQSxRQUNIO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFFQSxXQUFPO0FBQUEsTUFDTCxnQkFBZ0IsU0FBUztBQUN2QixjQUFNLE1BQU0sUUFBUSxPQUNqQixJQUFJLENBQUMsVUFBVSxNQUFNLE1BQU0sTUFBTSxFQUNqQyxLQUFLLEVBQUUsRUFDUCxLQUFLO0FBQ1IsaUJBQVMsS0FBSyxPQUFPO0FBQUEsTUFDdkI7QUFBQSxNQUNBLFFBQVEsU0FBUztBQUNmLFlBQUksT0FBTyxRQUFRLFVBQVUsVUFBVTtBQUNyQztBQUFBLFFBQ0Y7QUFDQSxpQkFBUyxRQUFRLE9BQU8sT0FBTztBQUFBLE1BQ2pDO0FBQUEsSUFDRjtBQUFBLEVBQ0Y7QUFDRixDQUFDO0FBRUQsSUFBTyxpQkFBUTsiLAogICJuYW1lcyI6IFsidGFibGVOYW1lIiwgImFsaWFzIiwgImFwaVNjaGVtYXMiLCAib3BlcmF0aW9ucyJdCn0K
|
|
@@ -230,9 +230,9 @@ export interface Select {
|
|
|
230
230
|
from: From[] | TableExpr | null;
|
|
231
231
|
where: Binary | Function | null;
|
|
232
232
|
groupby: {
|
|
233
|
-
columns: ColumnRef[] |
|
|
233
|
+
columns: ColumnRef[] | undefined;
|
|
234
234
|
modifiers: ValueExpr<string>[];
|
|
235
|
-
};
|
|
235
|
+
} | undefined;
|
|
236
236
|
having: any[] | null;
|
|
237
237
|
orderby: OrderBy[] | null;
|
|
238
238
|
limit: Limit | null;
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@checkdigit/eslint-plugin","version":"7.18.0-PR.143-
|
|
1
|
+
{"name":"@checkdigit/eslint-plugin","version":"7.18.0-PR.143-0de2","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 .","peggy":"for file in ./src/peggy/*.peggy; do peggy \"$file\" --format es --output \"${file%.peggy}-peggy.ts\"; done","peggy-watch":"for file in ./src/peggy/*.peggy; do peggy \"$file\" --format=es --watch --output=\"${file%.peggy}-peggy.ts\"; done","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":{"@apidevtools/json-schema-ref-parser":"^15.3.5","@typescript-eslint/type-utils":"^8.60.1","@typescript-eslint/utils":"^8.60.1","ajv":"^8.20.0","debug":"^4.4.3","glob":"^13.0.6","http-status-codes":"^2.3.0","js-yaml":"^4.2.0","json-pointer":"^0.6.2","jsonpath-plus":"^10.4.0","ts-api-utils":"^2.5.0"},"devDependencies":{"@checkdigit/jest-config":"^6.0.2","@checkdigit/prettier-config":"^6.1.0","@checkdigit/typescript-config":"10.0.0","@eslint/js":"^9.37.0","@types/debug":"^4.1.13","@types/eslint":"^9.6.1","@types/eslint-config-prettier":"^6.11.3","@types/js-yaml":"^4.0.9","@types/json-pointer":"^1.0.34","@typescript-eslint/parser":"^8.60.1","@typescript-eslint/rule-tester":"^8.60.1","eslint":"^9.37.0","eslint-config-prettier":"^10.1.8","eslint-import-resolver-typescript":"^4.4.5","eslint-plugin-eslint-plugin":"^6.4.0","eslint-plugin-import":"^2.32.0","eslint-plugin-no-only-tests":"^3.4.0","eslint-plugin-no-secrets":"^2.3.3","eslint-plugin-node":"^11.1.0","eslint-plugin-sonarjs":"^1.0.4","openapi-types":"^12.1.3","peggy":"^4.2.0","rimraf":"^6.1.3","typescript-eslint":"^8.60.1"},"peerDependencies":{"eslint":">=9 <10"},"engines":{"node":">=22.18"},"service":{"api":{"root":"src","endpoints":["api/v1"]}},"wallaby":{"env":{"params":{"runner":"--experimental-vm-modules"}}}}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// athena/api-matcher.ts
|
|
2
2
|
|
|
3
3
|
import debug from 'debug';
|
|
4
|
-
import { JSONPath } from 'jsonpath-plus';
|
|
5
4
|
import type { SchemaObject } from 'ajv/dist/2020';
|
|
6
5
|
|
|
7
6
|
import type { ApiSchemas, OperationSchemas } from '../openapi/generate-schema';
|
|
7
|
+
import type { Binary, ColumnRefItem, Function as SqlFunction } from './types';
|
|
8
8
|
|
|
9
9
|
const log = debug('eslint-plugin:athena:api-matcher');
|
|
10
10
|
|
|
@@ -21,105 +21,226 @@ export interface MatchedOperation {
|
|
|
21
21
|
response: SchemaObject;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
// A predicate over an API operation candidate: (url path, HTTP method, HTTP response code)
|
|
25
|
+
type OperationPredicate = (path: string, method: string, responseCode: string) => boolean;
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
const ALWAYS_TRUE: OperationPredicate = () => true;
|
|
28
|
+
|
|
29
|
+
// --- AST accessor helpers (use Record<string,unknown> to avoid TypeScript narrowing conflicts) ---
|
|
30
|
+
|
|
31
|
+
function rec(node: unknown): Record<string, unknown> | undefined {
|
|
32
|
+
return typeof node === 'object' && node !== null ? (node as Record<string, unknown>) : undefined;
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
path: "$.where..[?(@ && @.type === 'binary_expr' && @.operator === '=' && @.left && @.left.type === 'function' && @.left.name && @.left.name.name && @.left.name.name[0] && @.left.name.name[0].value === 'split' && @.left.args && @.left.args.value && @.left.args.value[0] && @.left.args.value[0].type === 'column_ref' && @.left.args.value[0].column === 'url' && @.left.args.value[1] && @.left.args.value[1].type === 'single_quote_string' && @.left.args.value[1].value === '/' && @.left.array_index && @.left.array_index[0] && @.left.array_index[0].brackets === true && @.left.array_index[0].index && @.left.array_index[0].index.type === 'number')]",
|
|
36
|
-
}); /*?*/
|
|
37
|
-
// log('pathPartCondition', pathPartCondition);
|
|
38
|
-
|
|
39
|
-
if (pathPartCondition !== undefined) {
|
|
40
|
-
const [pathPartIndex]: [number] = JSONPath({
|
|
41
|
-
json: pathPartCondition,
|
|
42
|
-
path: '$.left.array_index[0].index.value',
|
|
43
|
-
}); /*?*/
|
|
44
|
-
const [pathPartMatch]: [string] = JSONPath({
|
|
45
|
-
json: pathPartCondition,
|
|
46
|
-
path: '$.right.value',
|
|
47
|
-
}); /*?*/
|
|
48
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
49
|
-
return (path: string, _method: string) => {
|
|
50
|
-
const parts = path.split('/'); /*?*/
|
|
51
|
-
const part = parts[pathPartIndex - 1]; //athena index is larger than js index by one /*?*/
|
|
52
|
-
log(`checking path part`, { path, pathPartIndex, part, pathPartMatch });
|
|
53
|
-
return part?.startsWith(':') === true
|
|
54
|
-
? true // ignore path part if it presents a dynamic input parameter
|
|
55
|
-
: parts[pathPartIndex - 1] === pathPartMatch; // try to match with static path part
|
|
56
|
-
};
|
|
35
|
+
function getFunctionName(node: unknown): string | undefined {
|
|
36
|
+
const fn = rec(node);
|
|
37
|
+
if (fn?.['type'] !== 'function') {
|
|
38
|
+
return undefined;
|
|
57
39
|
}
|
|
40
|
+
const name = fn['name'] as SqlFunction['name'] | undefined;
|
|
41
|
+
const firstName = name?.name[0];
|
|
42
|
+
return firstName === undefined ? undefined : firstName.value.toLowerCase();
|
|
43
|
+
}
|
|
58
44
|
|
|
59
|
-
|
|
45
|
+
function getColumnName(node: unknown): string | undefined {
|
|
46
|
+
const col = rec(node);
|
|
47
|
+
if (col?.['type'] !== 'column_ref') {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
const column = (node as ColumnRefItem).column;
|
|
51
|
+
return typeof column === 'string' ? column.toLowerCase() : undefined;
|
|
60
52
|
}
|
|
61
53
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
54
|
+
function getColumnTable(node: unknown): string | null | undefined {
|
|
55
|
+
const col = rec(node);
|
|
56
|
+
if (col?.['type'] !== 'column_ref') {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return (node as ColumnRefItem).table;
|
|
60
|
+
}
|
|
69
61
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return parts.length === pathPartCount;
|
|
75
|
-
};
|
|
62
|
+
function getStringValue(node: unknown): string | undefined {
|
|
63
|
+
const val = rec(node);
|
|
64
|
+
if (val?.['type'] !== 'single_quote_string' && val?.['type'] !== 'string') {
|
|
65
|
+
return undefined;
|
|
76
66
|
}
|
|
67
|
+
return typeof val['value'] === 'string' ? val['value'] : undefined;
|
|
68
|
+
}
|
|
77
69
|
|
|
78
|
-
|
|
70
|
+
function getNumberValue(node: unknown): number | undefined {
|
|
71
|
+
const val = rec(node);
|
|
72
|
+
return val?.['type'] === 'number' && typeof val['value'] === 'number' ? val['value'] : undefined;
|
|
79
73
|
}
|
|
80
74
|
|
|
81
|
-
|
|
82
|
-
|
|
75
|
+
// Matches: split(url, '/')[N] — a Function node carrying an array_index extension
|
|
76
|
+
interface SplitUrlIndexed extends SqlFunction {
|
|
77
|
+
array_index: { brackets: true; index: { type: string; value: unknown } }[];
|
|
78
|
+
}
|
|
79
|
+
function isSplitUrlIndexed(node: unknown): node is SplitUrlIndexed {
|
|
80
|
+
const fn = rec(node);
|
|
81
|
+
if (fn?.['type'] !== 'function') {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
if (getFunctionName(node) !== 'split') {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
const args = (fn['args'] as { value?: unknown[] } | undefined)?.value;
|
|
88
|
+
if (!Array.isArray(args) || args.length < 2) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
if (getColumnName(args[0]) !== 'url') {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
if (getStringValue(args[1]) !== '/') {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
return Array.isArray(fn['array_index']) && (fn['array_index'] as unknown[]).length > 0;
|
|
83
98
|
}
|
|
84
99
|
|
|
85
|
-
//
|
|
86
|
-
function
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
100
|
+
// Matches: cardinality(split(url, '/'))
|
|
101
|
+
function isCardinalitySplitUrl(node: unknown): node is SqlFunction {
|
|
102
|
+
const fn = rec(node);
|
|
103
|
+
if (fn?.['type'] !== 'function') {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
if (getFunctionName(node) !== 'cardinality') {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
const outerArgs = (fn['args'] as { value?: unknown[] } | undefined)?.value;
|
|
110
|
+
if (!Array.isArray(outerArgs) || outerArgs.length === 0) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
const innerFn = rec(outerArgs[0]);
|
|
114
|
+
if (innerFn?.['type'] !== 'function') {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
if (getFunctionName(outerArgs[0]) !== 'split') {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
const innerArgs = (innerFn['args'] as { value?: unknown[] } | undefined)?.value;
|
|
121
|
+
if (!Array.isArray(innerArgs) || innerArgs.length < 2) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
return getColumnName(innerArgs[0]) === 'url' && getStringValue(innerArgs[1]) === '/';
|
|
125
|
+
}
|
|
91
126
|
|
|
92
|
-
|
|
93
|
-
|
|
127
|
+
// Returns the table qualifier of the left-hand side of a matchable binary condition.
|
|
128
|
+
// null means unqualified (applies to every table); undefined means indeterminate.
|
|
129
|
+
function getConditionTableQualifier(left: unknown): string | null | undefined {
|
|
130
|
+
const colName = getColumnName(left);
|
|
131
|
+
if (colName !== undefined) {
|
|
132
|
+
return getColumnTable(left);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (isSplitUrlIndexed(left)) {
|
|
136
|
+
const args = (rec(left)?.['args'] as { value?: unknown[] } | undefined)?.value;
|
|
137
|
+
return getColumnTable(args?.[0]) ?? null;
|
|
138
|
+
}
|
|
139
|
+
if (isCardinalitySplitUrl(left)) {
|
|
140
|
+
const outerArgs = (rec(left)?.['args'] as { value?: unknown[] } | undefined)?.value;
|
|
141
|
+
const splitFn = rec(outerArgs?.[0]);
|
|
142
|
+
const innerArgs = (splitFn?.['args'] as { value?: unknown[] } | undefined)?.value;
|
|
143
|
+
return getColumnTable(innerArgs?.[0]) ?? null;
|
|
94
144
|
}
|
|
95
145
|
return undefined;
|
|
96
146
|
}
|
|
97
147
|
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
148
|
+
// --- Predicate builders ---
|
|
149
|
+
|
|
150
|
+
// tableAlias: the alias (or null if none) of the FROM-clause item we are currently matching.
|
|
151
|
+
// Conditions that explicitly reference a different alias are skipped (treated as ALWAYS_TRUE).
|
|
152
|
+
function buildLeafPredicate(node: Binary, tableAlias: string | null): OperationPredicate | undefined {
|
|
153
|
+
if (node.operator !== '=') {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
const { left, right } = node;
|
|
157
|
+
|
|
158
|
+
const conditionTable = getConditionTableQualifier(left);
|
|
159
|
+
// conditionTable === null → unqualified, applies to all tables
|
|
160
|
+
// conditionTable === string → qualified; skip if it names a different alias
|
|
161
|
+
if (conditionTable !== null && conditionTable !== undefined && tableAlias !== null && conditionTable !== tableAlias) {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// method = 'GET'
|
|
166
|
+
if (getColumnName(left) === 'method') {
|
|
167
|
+
const value = getStringValue(right);
|
|
168
|
+
if (value !== undefined) {
|
|
169
|
+
return (_path, method) => method === value;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// responsestatus = '200'
|
|
174
|
+
if (getColumnName(left) === 'responsestatus') {
|
|
175
|
+
const value = getStringValue(right);
|
|
176
|
+
if (value !== undefined) {
|
|
177
|
+
return (_path, _method, responseCode) => responseCode === value;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// split(url, '/')[N] = 'value'
|
|
182
|
+
if (isSplitUrlIndexed(left)) {
|
|
183
|
+
const index = left.array_index[0]?.index.value;
|
|
184
|
+
const value = getStringValue(right);
|
|
185
|
+
if (typeof index === 'number' && value !== undefined) {
|
|
186
|
+
return (path) => {
|
|
187
|
+
const parts = path.split('/');
|
|
188
|
+
const part = parts[index - 1]; // athena index is 1-based
|
|
189
|
+
log(`checking path part`, { path, index, part, value });
|
|
190
|
+
return part?.startsWith(':') === true ? true : part === value;
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
104
194
|
|
|
105
|
-
|
|
195
|
+
// cardinality(split(url, '/')) = N
|
|
196
|
+
if (isCardinalitySplitUrl(left)) {
|
|
197
|
+
const count = getNumberValue(right);
|
|
198
|
+
if (count !== undefined) {
|
|
199
|
+
return (path) => path.split('/').length === count;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function buildPredicate(expr: unknown, tableAlias: string | null): OperationPredicate {
|
|
207
|
+
const node = rec(expr);
|
|
208
|
+
if (node?.['type'] !== 'binary_expr') {
|
|
209
|
+
return ALWAYS_TRUE;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const binary = expr as Binary;
|
|
213
|
+
|
|
214
|
+
switch (binary.operator) {
|
|
215
|
+
case 'AND': {
|
|
216
|
+
const leftPred = buildPredicate(binary.left, tableAlias);
|
|
217
|
+
const rightPred = buildPredicate(binary.right, tableAlias);
|
|
218
|
+
return (path, method, code) => leftPred(path, method, code) && rightPred(path, method, code);
|
|
219
|
+
}
|
|
220
|
+
case 'OR': {
|
|
221
|
+
const leftPred = buildPredicate(binary.left, tableAlias);
|
|
222
|
+
const rightPred = buildPredicate(binary.right, tableAlias);
|
|
223
|
+
return (path, method, code) => leftPred(path, method, code) || rightPred(path, method, code);
|
|
224
|
+
}
|
|
225
|
+
case 'NOT': {
|
|
226
|
+
const innerPred = buildPredicate(binary.left, tableAlias);
|
|
227
|
+
return (path, method, code) => !innerPred(path, method, code);
|
|
228
|
+
}
|
|
229
|
+
default: {
|
|
230
|
+
return buildLeafPredicate(binary, tableAlias) ?? ALWAYS_TRUE;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
106
233
|
}
|
|
107
234
|
|
|
108
|
-
// [TODO:] match only relevent table in case multiple tables are joined
|
|
109
235
|
export function matchApi(
|
|
110
236
|
selectAST: object,
|
|
111
237
|
tableAST: object,
|
|
112
238
|
apiSchemas: ApiSchemas[],
|
|
113
239
|
): MatchedOperation[] | undefined {
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
]
|
|
119
|
-
.flat()
|
|
120
|
-
.filter<Matcher>((matcher) => matcher !== undefined);
|
|
121
|
-
|
|
122
|
-
const allOperationSchemas: OperationToMatch[] = apiSchemas
|
|
240
|
+
const tableAlias = (tableAST as { as?: string | null }).as ?? null;
|
|
241
|
+
const predicate = buildPredicate((selectAST as { where?: unknown }).where ?? null, tableAlias);
|
|
242
|
+
|
|
243
|
+
const allOperations: OperationToMatch[] = apiSchemas
|
|
123
244
|
.flatMap((apiSchema) => Object.entries(apiSchema.apis))
|
|
124
245
|
.flatMap(([path, operations]) =>
|
|
125
246
|
Object.entries(operations).map(([method, operationSchemas]) => ({
|
|
@@ -128,41 +249,19 @@ export function matchApi(
|
|
|
128
249
|
operationSchemas,
|
|
129
250
|
})),
|
|
130
251
|
);
|
|
131
|
-
log('total operation schemas',
|
|
252
|
+
log('total operation schemas', allOperations.length);
|
|
132
253
|
|
|
133
|
-
const
|
|
134
|
-
|
|
254
|
+
const matchedApis = allOperations.flatMap(({ path, method, operationSchemas }) =>
|
|
255
|
+
Object.entries(operationSchemas.responses).flatMap(([responseCode, responseSchema]) =>
|
|
256
|
+
predicate(path, method, responseCode)
|
|
257
|
+
? [{ path, method, request: operationSchemas.request, response: responseSchema }]
|
|
258
|
+
: [],
|
|
259
|
+
),
|
|
135
260
|
);
|
|
136
|
-
log('matched
|
|
137
|
-
|
|
138
|
-
if (matchedOperationSchemas.length === 0) {
|
|
139
|
-
log('no matched operation schema');
|
|
140
|
-
throw new Error('no matched operation schema');
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const matchedResponseStatus = getResponseStatusToMatch(selectAST, tableAST);
|
|
144
|
-
// [TODO:] should we allow multiple response status?
|
|
145
|
-
// assert.ok(matchedResponseStatus !== undefined);
|
|
146
|
-
log('matchedResponseStatus', matchedResponseStatus);
|
|
147
|
-
|
|
148
|
-
const matchedApis = matchedOperationSchemas
|
|
149
|
-
.flatMap((operation) =>
|
|
150
|
-
Object.entries(operation.operationSchemas.responses).map(([responseCode, responseSchema]) => {
|
|
151
|
-
const matchedResponseSchema =
|
|
152
|
-
matchedResponseStatus === undefined || responseCode === matchedResponseStatus ? responseSchema : undefined;
|
|
153
|
-
return matchedResponseSchema === undefined
|
|
154
|
-
? undefined
|
|
155
|
-
: {
|
|
156
|
-
path: operation.path,
|
|
157
|
-
method: operation.method,
|
|
158
|
-
request: operation.operationSchemas.request,
|
|
159
|
-
response: matchedResponseSchema,
|
|
160
|
-
};
|
|
161
|
-
}),
|
|
162
|
-
)
|
|
163
|
-
.filter((api) => api !== undefined);
|
|
261
|
+
log('matched apis', matchedApis.length);
|
|
262
|
+
|
|
164
263
|
if (matchedApis.length === 0) {
|
|
165
|
-
log('no api
|
|
264
|
+
log('no matched api');
|
|
166
265
|
throw new Error('no matched api');
|
|
167
266
|
}
|
|
168
267
|
return matchedApis;
|
package/src/athena/athena.ts
CHANGED
|
@@ -379,6 +379,23 @@ function checkSelect(selectAST: Select | With, ctx: VisitContext, withTableName?
|
|
|
379
379
|
|
|
380
380
|
log('resolved columns', [...columns.keys()]);
|
|
381
381
|
|
|
382
|
+
// Pass 3: validate JSON paths in WHERE / HAVING / GROUP BY / ORDER BY
|
|
383
|
+
const allTables = [...selectCtx.tables.values()].flat();
|
|
384
|
+
if (select.where !== null) {
|
|
385
|
+
validateComplexColumnExpression(select.where, allTables, selectCtx);
|
|
386
|
+
}
|
|
387
|
+
if (select.having !== null) {
|
|
388
|
+
validateComplexColumnExpression(select.having, allTables, selectCtx);
|
|
389
|
+
}
|
|
390
|
+
for (const orderItem of select.orderby ?? []) {
|
|
391
|
+
validateComplexColumnExpression(orderItem.expr, allTables, selectCtx);
|
|
392
|
+
}
|
|
393
|
+
if (select.groupby?.columns !== undefined) {
|
|
394
|
+
for (const groupCol of select.groupby.columns) {
|
|
395
|
+
validateComplexColumnExpression(groupCol, allTables, selectCtx);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
382
399
|
// UNION ALL — next SELECT in the chain
|
|
383
400
|
if (select._next !== undefined) {
|
|
384
401
|
checkSelect(select._next, ctx, withTableName);
|
package/src/athena/types.ts
CHANGED
|
@@ -268,7 +268,7 @@ export interface Select {
|
|
|
268
268
|
columns: any[] | Column[];
|
|
269
269
|
from: From[] | TableExpr | null;
|
|
270
270
|
where: Binary | Function | null;
|
|
271
|
-
groupby: { columns: ColumnRef[] |
|
|
271
|
+
groupby: { columns: ColumnRef[] | undefined; modifiers: ValueExpr<string>[] } | undefined;
|
|
272
272
|
having: any[] | null;
|
|
273
273
|
orderby: OrderBy[] | null;
|
|
274
274
|
limit: Limit | null;
|