@checkdigit/eslint-athena-plugin 1.0.0-PR.2-dcdf
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/LICENSE.txt +21 -0
- package/README.md +17 -0
- package/SECURITY.md +13 -0
- package/dist-mjs/athena/api-locator.mjs +66 -0
- package/dist-mjs/athena/api-matcher.mjs +206 -0
- package/dist-mjs/athena/athena.mjs +165 -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 +45 -0
- package/dist-mjs/athena/sql-file.mjs +123 -0
- package/dist-mjs/athena/types.mjs +1 -0
- package/dist-mjs/athena/validate.mjs +619 -0
- package/dist-mjs/athena/visitor.mjs +291 -0
- package/dist-mjs/get-documentation-url.mjs +9 -0
- package/dist-mjs/index.mjs +56 -0
- package/dist-mjs/openapi/deref-schema.mjs +20 -0
- package/dist-mjs/openapi/generate-schema.mjs +375 -0
- package/dist-mjs/openapi/service-schema-generator.mjs +176 -0
- package/dist-mjs/peggy/athena-peggy.mjs +20700 -0
- package/dist-mjs/service.mjs +9 -0
- package/dist-mjs/sql-parser.mjs +28 -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 +5 -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/sql-file.d.ts +5 -0
- package/dist-types/athena/types.d.ts +493 -0
- package/dist-types/athena/validate.d.ts +14 -0
- package/dist-types/athena/visitor.d.ts +75 -0
- package/dist-types/get-documentation-url.d.ts +1 -0
- package/dist-types/index.d.ts +5 -0
- 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/dist-types/service.d.ts +2 -0
- package/dist-types/sql-parser.d.ts +25 -0
- package/package.json +1 -0
- package/src/api/v1/swagger.yml +619 -0
- package/src/api/v2/swagger.yml +477 -0
- package/src/athena/api-locator.ts +78 -0
- package/src/athena/api-matcher.ts +323 -0
- package/src/athena/athena.ts +224 -0
- package/src/athena/column.ts +4 -0
- package/src/athena/context.ts +47 -0
- package/src/athena/index.ts +13 -0
- package/src/athena/service-table.ts +78 -0
- package/src/athena/sql-file.ts +161 -0
- package/src/athena/types.ts +568 -0
- package/src/athena/validate.ts +902 -0
- package/src/athena/visitor.ts +406 -0
- package/src/get-documentation-url.ts +7 -0
- package/src/index.ts +67 -0
- package/src/openapi/deref-schema.ts +20 -0
- package/src/openapi/generate-schema.ts +553 -0
- package/src/openapi/service-schema-generator.ts +241 -0
- package/src/peggy/athena-peggy.ts +22149 -0
- package/src/peggy/athena.peggy +2971 -0
- package/src/service.ts +11 -0
- package/src/services/eslintAthenaPlugin/v1/swagger.schema.deref.json +1931 -0
- package/src/services/eslintAthenaPlugin/v2/swagger.schema.deref.json +978 -0
- package/src/sql-parser.ts +53 -0
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021-2026 Check Digit, LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# @checkdigit/eslint-athena-plugin
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021-2026 [Check Digit, LLC](https://checkdigit.com)
|
|
4
|
+
|
|
5
|
+
## Rules
|
|
6
|
+
|
|
7
|
+
- `@checkdigit/athena`
|
|
8
|
+
- `@checkdigit/sql-file`
|
|
9
|
+
|
|
10
|
+
## Configurations
|
|
11
|
+
|
|
12
|
+
- `@checkdigit/all`
|
|
13
|
+
- `@checkdigit/recommended`
|
|
14
|
+
|
|
15
|
+
## License
|
|
16
|
+
|
|
17
|
+
MIT
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
These versions of `@checkdigit/eslint-athena-plugin` are currently being supported with security updates.
|
|
6
|
+
|
|
7
|
+
| Version | Supported |
|
|
8
|
+
| ------- | ------------------ |
|
|
9
|
+
| \>= 1.0 | :white_check_mark: |
|
|
10
|
+
|
|
11
|
+
## Reporting a Vulnerability
|
|
12
|
+
|
|
13
|
+
Please create an issue at https://github.com/checkdigit/eslint-athena-plugin/issues
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// src/athena/api-locator.ts
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import debug from "debug";
|
|
4
|
+
import {
|
|
5
|
+
generateSchemasForService
|
|
6
|
+
} from "../openapi/generate-schema.mjs";
|
|
7
|
+
var log = debug("eslint-athena-plugin:athena:api-locator");
|
|
8
|
+
var SERVICES_ROOT_FOLDER = "src/services";
|
|
9
|
+
var LEGACY_TABLE_SUFFIX = "_logs";
|
|
10
|
+
var SCHEMA_MAX_AGE_MS = 60 * 60 * 1e3;
|
|
11
|
+
function locateApi(originalServiceName) {
|
|
12
|
+
log("locating API for service", originalServiceName);
|
|
13
|
+
let serviceName = originalServiceName;
|
|
14
|
+
if (serviceName.endsWith(LEGACY_TABLE_SUFFIX)) {
|
|
15
|
+
log(
|
|
16
|
+
'service table is a legacy table name, looking for API schemas after removing "_logs" suffix',
|
|
17
|
+
serviceName
|
|
18
|
+
);
|
|
19
|
+
serviceName = serviceName.slice(0, -LEGACY_TABLE_SUFFIX.length);
|
|
20
|
+
}
|
|
21
|
+
const camelCaseServiceName = serviceName.replace(
|
|
22
|
+
/-(?<letter>[a-z])/gu,
|
|
23
|
+
(_, letter) => letter.toUpperCase()
|
|
24
|
+
);
|
|
25
|
+
const allSchemaFilenames = fs.globSync(
|
|
26
|
+
`${SERVICES_ROOT_FOLDER}/${camelCaseServiceName}/*/swagger.schema.deref.json`
|
|
27
|
+
);
|
|
28
|
+
log(
|
|
29
|
+
`${allSchemaFilenames.length.toString()} versions of API schemas located for service ${serviceName}`,
|
|
30
|
+
allSchemaFilenames
|
|
31
|
+
);
|
|
32
|
+
const outputDir = `${SERVICES_ROOT_FOLDER}/${camelCaseServiceName}`;
|
|
33
|
+
if (allSchemaFilenames.length > 0) {
|
|
34
|
+
const hasStaleSchema = allSchemaFilenames.some(
|
|
35
|
+
(schemaFilename) => Date.now() - fs.statSync(schemaFilename).mtimeMs > SCHEMA_MAX_AGE_MS
|
|
36
|
+
);
|
|
37
|
+
if (hasStaleSchema) {
|
|
38
|
+
log(
|
|
39
|
+
"cached schema(s) are stale (older than 1 hour), regenerating for service",
|
|
40
|
+
serviceName
|
|
41
|
+
);
|
|
42
|
+
const regenerated = generateSchemasForService(serviceName, outputDir);
|
|
43
|
+
if (regenerated.length > 0) {
|
|
44
|
+
return regenerated.map(({ schema }) => schema);
|
|
45
|
+
}
|
|
46
|
+
log(
|
|
47
|
+
"regeneration failed, falling back to stale cached schemas for service",
|
|
48
|
+
serviceName
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return allSchemaFilenames.map(
|
|
52
|
+
(schemaFilename) => JSON.parse(fs.readFileSync(schemaFilename, "utf-8"))
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
log(
|
|
56
|
+
"no pre-generated schemas found, attempting on-demand generation for service",
|
|
57
|
+
serviceName
|
|
58
|
+
);
|
|
59
|
+
return generateSchemasForService(serviceName, outputDir).map(
|
|
60
|
+
({ schema }) => schema
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
locateApi
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2F0aGVuYS9hcGktbG9jYXRvci50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFFQSxPQUFPLFFBQVE7QUFFZixPQUFPLFdBQVc7QUFFbEI7QUFBQSxFQUVFO0FBQUEsT0FDSztBQUVQLElBQU0sTUFBTSxNQUFNLHlDQUF5QztBQUUzRCxJQUFNLHVCQUF1QjtBQUM3QixJQUFNLHNCQUFzQjtBQUU1QixJQUFNLG9CQUFvQixLQUFLLEtBQUs7QUFFN0IsU0FBUyxVQUFVLHFCQUEyQztBQUNuRSxNQUFJLDRCQUE0QixtQkFBbUI7QUFFbkQsTUFBSSxjQUFjO0FBQ2xCLE1BQUksWUFBWSxTQUFTLG1CQUFtQixHQUFHO0FBQzdDO0FBQUEsTUFDRTtBQUFBLE1BQ0E7QUFBQSxJQUNGO0FBQ0Esa0JBQWMsWUFBWSxNQUFNLEdBQUcsQ0FBQyxvQkFBb0IsTUFBTTtBQUFBLEVBQ2hFO0FBRUEsUUFBTSx1QkFBdUIsWUFBWTtBQUFBLElBQ3ZDO0FBQUEsSUFDQSxDQUFDLEdBQUcsV0FBbUIsT0FBTyxZQUFZO0FBQUEsRUFDNUM7QUFFQSxRQUFNLHFCQUFxQixHQUFHO0FBQUEsSUFDNUIsR0FBRyxvQkFBb0IsSUFBSSxvQkFBb0I7QUFBQSxFQUNqRDtBQUNBO0FBQUEsSUFDRSxHQUFHLG1CQUFtQixPQUFPLFNBQVMsQ0FBQyxnREFBZ0QsV0FBVztBQUFBLElBQ2xHO0FBQUEsRUFDRjtBQUVBLFFBQU0sWUFBWSxHQUFHLG9CQUFvQixJQUFJLG9CQUFvQjtBQUVqRSxNQUFJLG1CQUFtQixTQUFTLEdBQUc7QUFDakMsVUFBTSxpQkFBaUIsbUJBQW1CO0FBQUEsTUFDeEMsQ0FBQyxtQkFDQyxLQUFLLElBQUksSUFBSSxHQUFHLFNBQVMsY0FBYyxFQUFFLFVBQVU7QUFBQSxJQUN2RDtBQUNBLFFBQUksZ0JBQWdCO0FBQ2xCO0FBQUEsUUFDRTtBQUFBLFFBQ0E7QUFBQSxNQUNGO0FBQ0EsWUFBTSxjQUFjLDBCQUEwQixhQUFhLFNBQVM7QUFDcEUsVUFBSSxZQUFZLFNBQVMsR0FBRztBQUMxQixlQUFPLFlBQVksSUFBSSxDQUFDLEVBQUUsT0FBTyxNQUFNLE1BQU07QUFBQSxNQUMvQztBQUNBO0FBQUEsUUFDRTtBQUFBLFFBQ0E7QUFBQSxNQUNGO0FBQUEsSUFDRjtBQUNBLFdBQU8sbUJBQW1CO0FBQUEsTUFDeEIsQ0FBQyxtQkFDQyxLQUFLLE1BQU0sR0FBRyxhQUFhLGdCQUFnQixPQUFPLENBQUM7QUFBQSxJQUN2RDtBQUFBLEVBQ0Y7QUFFQTtBQUFBLElBQ0U7QUFBQSxJQUNBO0FBQUEsRUFDRjtBQUNBLFNBQU8sMEJBQTBCLGFBQWEsU0FBUyxFQUFFO0FBQUEsSUFDdkQsQ0FBQyxFQUFFLE9BQU8sTUFBTTtBQUFBLEVBQ2xCO0FBQ0Y7IiwKICAibmFtZXMiOiBbXQp9Cg==
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// src/athena/api-matcher.ts
|
|
2
|
+
import debug from "debug";
|
|
3
|
+
var log = debug("eslint-athena-plugin:athena:api-matcher");
|
|
4
|
+
var ALWAYS_TRUE = () => true;
|
|
5
|
+
function rec(node) {
|
|
6
|
+
return typeof node === "object" && node !== null ? node : void 0;
|
|
7
|
+
}
|
|
8
|
+
function getFunctionName(node) {
|
|
9
|
+
const fn = rec(node);
|
|
10
|
+
if (fn?.["type"] !== "function") {
|
|
11
|
+
return void 0;
|
|
12
|
+
}
|
|
13
|
+
const name = fn["name"];
|
|
14
|
+
const firstName = name?.name[0];
|
|
15
|
+
return firstName === void 0 ? void 0 : firstName.value.toLowerCase();
|
|
16
|
+
}
|
|
17
|
+
function getColumnRef(node) {
|
|
18
|
+
const col = rec(node);
|
|
19
|
+
return col?.["type"] === "column_ref" ? node : void 0;
|
|
20
|
+
}
|
|
21
|
+
function getColumnName(node) {
|
|
22
|
+
const column = getColumnRef(node)?.column;
|
|
23
|
+
return typeof column === "string" ? column.toLowerCase() : void 0;
|
|
24
|
+
}
|
|
25
|
+
function getColumnTable(node) {
|
|
26
|
+
return getColumnRef(node)?.table ?? void 0;
|
|
27
|
+
}
|
|
28
|
+
function getStringValue(node) {
|
|
29
|
+
const val = rec(node);
|
|
30
|
+
if (val?.["type"] !== "single_quote_string" && val?.["type"] !== "string") {
|
|
31
|
+
return void 0;
|
|
32
|
+
}
|
|
33
|
+
return typeof val["value"] === "string" ? val["value"] : void 0;
|
|
34
|
+
}
|
|
35
|
+
function getNumberValue(node) {
|
|
36
|
+
const val = rec(node);
|
|
37
|
+
return val?.["type"] === "number" && typeof val["value"] === "number" ? val["value"] : void 0;
|
|
38
|
+
}
|
|
39
|
+
function getSplitUrlFunctionArgs(node, functionName) {
|
|
40
|
+
if (getFunctionName(node) !== functionName) {
|
|
41
|
+
return void 0;
|
|
42
|
+
}
|
|
43
|
+
const args = rec(node)?.["args"]?.value;
|
|
44
|
+
if (!Array.isArray(args) || args.length < 2) {
|
|
45
|
+
return void 0;
|
|
46
|
+
}
|
|
47
|
+
if (getColumnName(args[0]) !== "url" || getStringValue(args[1]) !== "/") {
|
|
48
|
+
return void 0;
|
|
49
|
+
}
|
|
50
|
+
return args;
|
|
51
|
+
}
|
|
52
|
+
function isSplitUrlIndexed(node) {
|
|
53
|
+
if (getSplitUrlFunctionArgs(node, "split") === void 0) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const fn = rec(node);
|
|
57
|
+
return Array.isArray(fn?.["array_index"]) && fn["array_index"].length > 0;
|
|
58
|
+
}
|
|
59
|
+
function isSplitPartUrl(node) {
|
|
60
|
+
const args = getSplitUrlFunctionArgs(node, "split_part");
|
|
61
|
+
return getNumberValue(args?.[2]) !== void 0;
|
|
62
|
+
}
|
|
63
|
+
function isCardinalitySplitUrl(node) {
|
|
64
|
+
if (getFunctionName(node) !== "cardinality") {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
const outerArgs = rec(node)?.["args"]?.value;
|
|
68
|
+
if (!Array.isArray(outerArgs) || outerArgs.length === 0) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
return getSplitUrlFunctionArgs(outerArgs[0], "split") !== void 0;
|
|
72
|
+
}
|
|
73
|
+
function getConditionTableQualifier(left) {
|
|
74
|
+
const colName = getColumnName(left);
|
|
75
|
+
if (colName !== void 0) {
|
|
76
|
+
return getColumnTable(left);
|
|
77
|
+
}
|
|
78
|
+
const splitArgs = getSplitUrlFunctionArgs(left, "split") ?? getSplitUrlFunctionArgs(left, "split_part");
|
|
79
|
+
if (splitArgs !== void 0) {
|
|
80
|
+
return getColumnTable(splitArgs[0]);
|
|
81
|
+
}
|
|
82
|
+
if (isCardinalitySplitUrl(left)) {
|
|
83
|
+
const outerArgs = rec(left)?.["args"]?.value;
|
|
84
|
+
const splitFn = rec(outerArgs?.[0]);
|
|
85
|
+
const innerArgs = splitFn?.["args"]?.value;
|
|
86
|
+
return getColumnTable(innerArgs?.[0]);
|
|
87
|
+
}
|
|
88
|
+
return void 0;
|
|
89
|
+
}
|
|
90
|
+
function buildPathSegmentPredicate(index, value) {
|
|
91
|
+
return (path) => {
|
|
92
|
+
const part = path.split("/")[index - 1];
|
|
93
|
+
log("checking path segment", { path, index, part, value });
|
|
94
|
+
return part?.startsWith(":") === true ? true : part === value;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function buildLeafPredicate(node, tableAlias) {
|
|
98
|
+
if (node.operator !== "=") {
|
|
99
|
+
return void 0;
|
|
100
|
+
}
|
|
101
|
+
const { left, right } = node;
|
|
102
|
+
const conditionTable = getConditionTableQualifier(left);
|
|
103
|
+
if (conditionTable !== void 0 && tableAlias !== void 0 && conditionTable !== tableAlias) {
|
|
104
|
+
return void 0;
|
|
105
|
+
}
|
|
106
|
+
if (getColumnName(left) === "method") {
|
|
107
|
+
const value = getStringValue(right);
|
|
108
|
+
if (value !== void 0) {
|
|
109
|
+
return (_path, method) => method === value;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (getColumnName(left) === "responsestatus") {
|
|
113
|
+
const value = getStringValue(right);
|
|
114
|
+
if (value !== void 0) {
|
|
115
|
+
return (_path, _method, responseCode) => responseCode === value;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (isSplitUrlIndexed(left)) {
|
|
119
|
+
const index = left.array_index[0]?.index.value;
|
|
120
|
+
const value = getStringValue(right);
|
|
121
|
+
if (typeof index === "number" && value !== void 0) {
|
|
122
|
+
return buildPathSegmentPredicate(index, value);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (isSplitPartUrl(left)) {
|
|
126
|
+
const index = getNumberValue(
|
|
127
|
+
getSplitUrlFunctionArgs(left, "split_part")?.[2]
|
|
128
|
+
);
|
|
129
|
+
const value = getStringValue(right);
|
|
130
|
+
if (index !== void 0 && value !== void 0) {
|
|
131
|
+
return buildPathSegmentPredicate(index, value);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (isCardinalitySplitUrl(left)) {
|
|
135
|
+
const count = getNumberValue(right);
|
|
136
|
+
if (count !== void 0) {
|
|
137
|
+
return (path) => path.split("/").length === count;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return void 0;
|
|
141
|
+
}
|
|
142
|
+
function buildPredicate(expr, tableAlias) {
|
|
143
|
+
const node = rec(expr);
|
|
144
|
+
if (node?.["type"] !== "binary_expr") {
|
|
145
|
+
return ALWAYS_TRUE;
|
|
146
|
+
}
|
|
147
|
+
const binary = expr;
|
|
148
|
+
switch (binary.operator) {
|
|
149
|
+
case "AND": {
|
|
150
|
+
const leftPred = buildPredicate(binary.left, tableAlias);
|
|
151
|
+
const rightPred = buildPredicate(binary.right, tableAlias);
|
|
152
|
+
return (path, method, code) => leftPred(path, method, code) && rightPred(path, method, code);
|
|
153
|
+
}
|
|
154
|
+
case "OR": {
|
|
155
|
+
const leftPred = buildPredicate(binary.left, tableAlias);
|
|
156
|
+
const rightPred = buildPredicate(binary.right, tableAlias);
|
|
157
|
+
return (path, method, code) => leftPred(path, method, code) || rightPred(path, method, code);
|
|
158
|
+
}
|
|
159
|
+
case "NOT": {
|
|
160
|
+
const innerPred = buildPredicate(binary.left, tableAlias);
|
|
161
|
+
return (path, method, code) => !innerPred(path, method, code);
|
|
162
|
+
}
|
|
163
|
+
default: {
|
|
164
|
+
return buildLeafPredicate(binary, tableAlias) ?? ALWAYS_TRUE;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function matchApi(selectAST, tableAST, apiSchemas) {
|
|
169
|
+
const tableAlias = tableAST.as ?? void 0;
|
|
170
|
+
const predicate = buildPredicate(
|
|
171
|
+
selectAST.where,
|
|
172
|
+
tableAlias
|
|
173
|
+
);
|
|
174
|
+
const allOperations = apiSchemas.flatMap((apiSchema) => Object.entries(apiSchema.apis)).flatMap(
|
|
175
|
+
([path, operations]) => Object.entries(operations).map(([method, operationSchemas]) => ({
|
|
176
|
+
path,
|
|
177
|
+
method: method.toUpperCase(),
|
|
178
|
+
operationSchemas
|
|
179
|
+
}))
|
|
180
|
+
);
|
|
181
|
+
log("total operation schemas", allOperations.length);
|
|
182
|
+
const matchedApis = allOperations.flatMap(
|
|
183
|
+
({ path, method, operationSchemas }) => Object.entries(operationSchemas.responses).flatMap(
|
|
184
|
+
([responseCode, responseSchema]) => predicate(path, method, responseCode) ? [
|
|
185
|
+
{
|
|
186
|
+
path,
|
|
187
|
+
method,
|
|
188
|
+
request: operationSchemas.request,
|
|
189
|
+
response: responseSchema
|
|
190
|
+
}
|
|
191
|
+
] : []
|
|
192
|
+
)
|
|
193
|
+
);
|
|
194
|
+
log("matched apis", matchedApis.length);
|
|
195
|
+
if (matchedApis.length === 0) {
|
|
196
|
+
log("no matched api");
|
|
197
|
+
throw new Error(
|
|
198
|
+
"No matched api, please adjust your query conditions to match with at least one API endpoints with firehose enabled."
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
return matchedApis;
|
|
202
|
+
}
|
|
203
|
+
export {
|
|
204
|
+
matchApi
|
|
205
|
+
};
|
|
206
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2F0aGVuYS9hcGktbWF0Y2hlci50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFFQSxPQUFPLFdBQVc7QUFNbEIsSUFBTSxNQUFNLE1BQU0seUNBQXlDO0FBc0IzRCxJQUFNLGNBQWtDLE1BQU07QUFJOUMsU0FBUyxJQUFJLE1BQW9EO0FBQy9ELFNBQU8sT0FBTyxTQUFTLFlBQVksU0FBUyxPQUN2QyxPQUNEO0FBQ047QUFFQSxTQUFTLGdCQUFnQixNQUFtQztBQUMxRCxRQUFNLEtBQUssSUFBSSxJQUFJO0FBQ25CLE1BQUksS0FBSyxNQUFNLE1BQU0sWUFBWTtBQUMvQixXQUFPO0FBQUEsRUFDVDtBQUNBLFFBQU0sT0FBTyxHQUFHLE1BQU07QUFDdEIsUUFBTSxZQUFZLE1BQU0sS0FBSyxDQUFDO0FBQzlCLFNBQU8sY0FBYyxTQUFZLFNBQVksVUFBVSxNQUFNLFlBQVk7QUFDM0U7QUFFQSxTQUFTLGFBQWEsTUFBMEM7QUFDOUQsUUFBTSxNQUFNLElBQUksSUFBSTtBQUNwQixTQUFPLE1BQU0sTUFBTSxNQUFNLGVBQWdCLE9BQXlCO0FBQ3BFO0FBRUEsU0FBUyxjQUFjLE1BQW1DO0FBQ3hELFFBQU0sU0FBUyxhQUFhLElBQUksR0FBRztBQUNuQyxTQUFPLE9BQU8sV0FBVyxXQUFXLE9BQU8sWUFBWSxJQUFJO0FBQzdEO0FBRUEsU0FBUyxlQUFlLE1BQW1DO0FBQ3pELFNBQU8sYUFBYSxJQUFJLEdBQUcsU0FBUztBQUN0QztBQUVBLFNBQVMsZUFBZSxNQUFtQztBQUN6RCxRQUFNLE1BQU0sSUFBSSxJQUFJO0FBQ3BCLE1BQUksTUFBTSxNQUFNLE1BQU0seUJBQXlCLE1BQU0sTUFBTSxNQUFNLFVBQVU7QUFDekUsV0FBTztBQUFBLEVBQ1Q7QUFDQSxTQUFPLE9BQU8sSUFBSSxPQUFPLE1BQU0sV0FBVyxJQUFJLE9BQU8sSUFBSTtBQUMzRDtBQUVBLFNBQVMsZUFBZSxNQUFtQztBQUN6RCxRQUFNLE1BQU0sSUFBSSxJQUFJO0FBQ3BC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
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// src/athena/athena.ts
|
|
2
|
+
import debug from "debug";
|
|
3
|
+
import {
|
|
4
|
+
AST_NODE_TYPES,
|
|
5
|
+
ESLintUtils
|
|
6
|
+
} from "@typescript-eslint/utils";
|
|
7
|
+
import { parse } from "../peggy/athena-peggy.mjs";
|
|
8
|
+
import { createRootContext } from "./context.mjs";
|
|
9
|
+
import {
|
|
10
|
+
ATHENA_ERROR,
|
|
11
|
+
AthenaError,
|
|
12
|
+
checkAthenaAst,
|
|
13
|
+
offsetToLoc,
|
|
14
|
+
SYNTAXT_ERROR
|
|
15
|
+
} from "./validate.mjs";
|
|
16
|
+
var ruleId = "athena";
|
|
17
|
+
var log = debug("eslint-athena-plugin:athena");
|
|
18
|
+
var createRule = ESLintUtils.RuleCreator((name) => name);
|
|
19
|
+
function buildSqlMapping(sqlNode) {
|
|
20
|
+
if (sqlNode.type !== AST_NODE_TYPES.TemplateLiteral) {
|
|
21
|
+
return [{ sqlStart: 0, srcStart: sqlNode.range[0] + 1 }];
|
|
22
|
+
}
|
|
23
|
+
const rawSql = sqlNode.quasis.map((quasi) => quasi.value.cooked ?? "").join("");
|
|
24
|
+
const trimStart = rawSql.length - rawSql.trimStart().length;
|
|
25
|
+
const segments = [];
|
|
26
|
+
let sqlCursor = 0;
|
|
27
|
+
for (const [index, quasi] of sqlNode.quasis.entries()) {
|
|
28
|
+
const cooked = quasi.value.cooked ?? "";
|
|
29
|
+
const localTrim = index === 0 ? trimStart : 0;
|
|
30
|
+
segments.push({
|
|
31
|
+
sqlStart: sqlCursor,
|
|
32
|
+
srcStart: quasi.range[0] + 1 + localTrim
|
|
33
|
+
});
|
|
34
|
+
sqlCursor += cooked.length - localTrim;
|
|
35
|
+
}
|
|
36
|
+
return segments;
|
|
37
|
+
}
|
|
38
|
+
function sqlOffsetToSource(sqlOffset, segments) {
|
|
39
|
+
for (let index = segments.length - 1; index >= 0; index--) {
|
|
40
|
+
const seg = segments[index];
|
|
41
|
+
if (seg !== void 0 && sqlOffset >= seg.sqlStart) {
|
|
42
|
+
return seg.srcStart + (sqlOffset - seg.sqlStart);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return segments[0]?.srcStart ?? 0;
|
|
46
|
+
}
|
|
47
|
+
var rule = createRule({
|
|
48
|
+
name: ruleId,
|
|
49
|
+
meta: {
|
|
50
|
+
type: "problem",
|
|
51
|
+
docs: {
|
|
52
|
+
description: "Validate Athena SQL strings against OpenAPI schemas at lint time"
|
|
53
|
+
},
|
|
54
|
+
schema: [],
|
|
55
|
+
messages: {
|
|
56
|
+
[SYNTAXT_ERROR]: `SyntaxError {{ errorMessage }}`,
|
|
57
|
+
[ATHENA_ERROR]: `AthenaError {{ errorMessage }}`
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
defaultOptions: [],
|
|
61
|
+
create(context) {
|
|
62
|
+
function checkSql(sql, sqlNode) {
|
|
63
|
+
if (!/^\s*(?:SELECT\b[\s\S]*\bFROM\b|WITH\b[\s\S]*\bSELECT\b[\s\S]*\b)/iu.test(
|
|
64
|
+
sql
|
|
65
|
+
)) {
|
|
66
|
+
log("skipping non-SELECT SQL string", { sql });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const sqlMapping = buildSqlMapping(sqlNode);
|
|
70
|
+
let ast;
|
|
71
|
+
try {
|
|
72
|
+
({ ast } = parse(sql, { includeLocations: true }));
|
|
73
|
+
} catch (error) {
|
|
74
|
+
log("error parsing Athena SQL", { error, sql });
|
|
75
|
+
const pegLoc = error.location;
|
|
76
|
+
if (pegLoc !== void 0) {
|
|
77
|
+
const sourceText = context.sourceCode.getText();
|
|
78
|
+
context.report({
|
|
79
|
+
loc: {
|
|
80
|
+
start: offsetToLoc(
|
|
81
|
+
sourceText,
|
|
82
|
+
sqlOffsetToSource(pegLoc.start.offset, sqlMapping)
|
|
83
|
+
),
|
|
84
|
+
end: offsetToLoc(
|
|
85
|
+
sourceText,
|
|
86
|
+
sqlOffsetToSource(pegLoc.end.offset, sqlMapping)
|
|
87
|
+
)
|
|
88
|
+
},
|
|
89
|
+
messageId: SYNTAXT_ERROR,
|
|
90
|
+
data: { errorMessage: error.message }
|
|
91
|
+
});
|
|
92
|
+
} else {
|
|
93
|
+
context.report({
|
|
94
|
+
node: sqlNode,
|
|
95
|
+
messageId: SYNTAXT_ERROR,
|
|
96
|
+
data: { errorMessage: error.message }
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const athenaCtx = createRootContext();
|
|
102
|
+
try {
|
|
103
|
+
checkAthenaAst(Array.isArray(ast) ? ast[0] : ast, athenaCtx);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
log("error checking Athena AST", { error, sql });
|
|
106
|
+
if (error instanceof AthenaError) {
|
|
107
|
+
const astLoc = error.ast?.loc;
|
|
108
|
+
if (astLoc !== void 0) {
|
|
109
|
+
const sourceText = context.sourceCode.getText();
|
|
110
|
+
context.report({
|
|
111
|
+
loc: {
|
|
112
|
+
start: offsetToLoc(
|
|
113
|
+
sourceText,
|
|
114
|
+
sqlOffsetToSource(astLoc.start.offset, sqlMapping)
|
|
115
|
+
),
|
|
116
|
+
end: offsetToLoc(
|
|
117
|
+
sourceText,
|
|
118
|
+
sqlOffsetToSource(astLoc.end.offset, sqlMapping)
|
|
119
|
+
)
|
|
120
|
+
},
|
|
121
|
+
messageId: ATHENA_ERROR,
|
|
122
|
+
data: { errorMessage: error.message }
|
|
123
|
+
});
|
|
124
|
+
} else {
|
|
125
|
+
context.report({
|
|
126
|
+
node: sqlNode,
|
|
127
|
+
messageId: ATHENA_ERROR,
|
|
128
|
+
data: { errorMessage: error.message }
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
console.error(
|
|
133
|
+
`Failed to apply ${ruleId} rule for "${context.filename}":`,
|
|
134
|
+
error
|
|
135
|
+
);
|
|
136
|
+
context.report({
|
|
137
|
+
node: sqlNode,
|
|
138
|
+
messageId: ATHENA_ERROR,
|
|
139
|
+
data: {
|
|
140
|
+
errorMessage: error instanceof Error ? String(error) : JSON.stringify(error, void 0, 2)
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
TemplateLiteral(sqlNode) {
|
|
148
|
+
const sql = sqlNode.quasis.map((quasi) => quasi.value.cooked).join("").trim();
|
|
149
|
+
checkSql(sql, sqlNode);
|
|
150
|
+
},
|
|
151
|
+
Literal(sqlNode) {
|
|
152
|
+
if (typeof sqlNode.value !== "string") {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
checkSql(sqlNode.value, sqlNode);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
var athena_default = rule;
|
|
161
|
+
export {
|
|
162
|
+
athena_default as default,
|
|
163
|
+
ruleId
|
|
164
|
+
};
|
|
165
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2F0aGVuYS9hdGhlbmEudHMiXSwKICAibWFwcGluZ3MiOiAiO0FBUUEsT0FBTyxXQUFXO0FBQ2xCO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxPQUVLO0FBRVAsU0FBUyxhQUFhO0FBRXRCLFNBQVMseUJBQXlCO0FBQ2xDO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBRUEsSUFBTSxTQUFTO0FBRXRCLElBQU0sTUFBTSxNQUFNLDZCQUE2QjtBQUMvQyxJQUFNLGFBQWEsWUFBWSxZQUFZLENBQUMsU0FBUyxJQUFJO0FBV3pELFNBQVMsZ0JBQWdCLFNBQTRDO0FBQ25FLE1BQUksUUFBUSxTQUFTLGVBQWUsaUJBQWlCO0FBRW5ELFdBQU8sQ0FBQyxFQUFFLFVBQVUsR0FBRyxVQUFVLFFBQVEsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO0FBQUEsRUFDekQ7QUFDQSxRQUFNLFNBQVMsUUFBUSxPQUNwQixJQUFJLENBQUMsVUFBVSxNQUFNLE1BQU0sVUFBVSxFQUFFLEVBQ3ZDLEtBQUssRUFBRTtBQUNWLFFBQU0sWUFBWSxPQUFPLFNBQVMsT0FBTyxVQUFVLEVBQUU7QUFDckQsUUFBTSxXQUErQixDQUFDO0FBQ3RDLE1BQUksWUFBWTtBQUNoQixhQUFXLENBQUMsT0FBTyxLQUFLLEtBQUssUUFBUSxPQUFPLFFBQVEsR0FBRztBQUNyRCxVQUFNLFNBQVMsTUFBTSxNQUFNLFVBQVU7QUFDckMsVUFBTSxZQUFZLFVBQVUsSUFBSSxZQUFZO0FBRTVDLGFBQVMsS0FBSztBQUFBLE1BQ1osVUFBVTtBQUFBLE1BQ1YsVUFBVSxNQUFNLE1BQU0sQ0FBQyxJQUFJLElBQUk7QUFBQSxJQUNqQyxDQUFDO0FBQ0QsaUJBQWEsT0FBTyxTQUFTO0FBQUEsRUFDL0I7QUFDQSxTQUFPO0FBQ1Q7QUFFQSxTQUFTLGtCQUNQLFdBQ0EsVUFDUTtBQUNSLFdBQVMsUUFBUSxTQUFTLFNBQVMs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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFtdLAogICJtYXBwaW5ncyI6ICIiLAogICJuYW1lcyI6IFtdCn0K
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// src/athena/context.ts
|
|
2
|
+
function createRootContext() {
|
|
3
|
+
return {
|
|
4
|
+
tables: /* @__PURE__ */ new Map(),
|
|
5
|
+
aliases: /* @__PURE__ */ new Map(),
|
|
6
|
+
apiSchemas: /* @__PURE__ */ new Map()
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function createChildContext(parent) {
|
|
10
|
+
return {
|
|
11
|
+
tables: new Map(parent.tables),
|
|
12
|
+
aliases: /* @__PURE__ */ new Map(),
|
|
13
|
+
apiSchemas: parent.apiSchemas,
|
|
14
|
+
parent
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
createChildContext,
|
|
19
|
+
createRootContext
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2F0aGVuYS9jb250ZXh0LnRzIl0sCiAgIm1hcHBpbmdzIjogIjtBQThCTyxTQUFTLG9CQUFrQztBQUNoRCxTQUFPO0FBQUEsSUFDTCxRQUFRLG9CQUFJLElBQUk7QUFBQSxJQUNoQixTQUFTLG9CQUFJLElBQUk7QUFBQSxJQUNqQixZQUFZLG9CQUFJLElBQUk7QUFBQSxFQUN0QjtBQUNGO0FBR08sU0FBUyxtQkFBbUIsUUFBb0M7QUFDckUsU0FBTztBQUFBLElBQ0wsUUFBUSxJQUFJLElBQUksT0FBTyxNQUFNO0FBQUEsSUFDN0IsU0FBUyxvQkFBSSxJQUFJO0FBQUEsSUFDakIsWUFBWSxPQUFPO0FBQUEsSUFDbkI7QUFBQSxFQUNGO0FBQ0Y7IiwKICAibmFtZXMiOiBbXQp9Cg==
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFtdLAogICJtYXBwaW5ncyI6ICIiLAogICJuYW1lcyI6IFtdCn0K
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// src/athena/service-table.ts
|
|
2
|
+
var SCHEMA_STRING = { type: "string" };
|
|
3
|
+
var SCHEMA_OBJECT = { type: "object" };
|
|
4
|
+
function col(name, schema) {
|
|
5
|
+
return { name, schema };
|
|
6
|
+
}
|
|
7
|
+
function bodySchema(envelope, field) {
|
|
8
|
+
return envelope["properties"]?.[field] ?? SCHEMA_OBJECT;
|
|
9
|
+
}
|
|
10
|
+
function buildServiceTables(tableName, operations) {
|
|
11
|
+
return operations.map((operation) => ({
|
|
12
|
+
name: tableName,
|
|
13
|
+
apiOperation: [operation],
|
|
14
|
+
columns: /* @__PURE__ */ new Map([
|
|
15
|
+
["method", [col("method", SCHEMA_STRING)]],
|
|
16
|
+
["started", [col("started", SCHEMA_STRING)]],
|
|
17
|
+
["ended", [col("ended", SCHEMA_STRING)]],
|
|
18
|
+
["url", [col("url", SCHEMA_STRING)]],
|
|
19
|
+
[
|
|
20
|
+
"requestbody",
|
|
21
|
+
[col("requestbody", bodySchema(operation.request, "body"))]
|
|
22
|
+
],
|
|
23
|
+
[
|
|
24
|
+
"requestheaders",
|
|
25
|
+
[col("requestheaders", bodySchema(operation.request, "headers"))]
|
|
26
|
+
],
|
|
27
|
+
["responsestatus", [col("responsestatus", SCHEMA_STRING)]],
|
|
28
|
+
["responsemessage", [col("responsemessage", SCHEMA_STRING)]],
|
|
29
|
+
["responsetype", [col("responsetype", SCHEMA_STRING)]],
|
|
30
|
+
[
|
|
31
|
+
"responsebody",
|
|
32
|
+
[col("responsebody", bodySchema(operation.response, "body"))]
|
|
33
|
+
],
|
|
34
|
+
[
|
|
35
|
+
"responseheaders",
|
|
36
|
+
[col("responseheaders", bodySchema(operation.response, "headers"))]
|
|
37
|
+
],
|
|
38
|
+
["partition_date", [col("partition_date", SCHEMA_STRING)]]
|
|
39
|
+
])
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
export {
|
|
43
|
+
buildServiceTables
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2F0aGVuYS9zZXJ2aWNlLXRhYmxlLnRzIl0sCiAgIm1hcHBpbmdzIjogIjtBQW9CQSxJQUFNLGdCQUE4QixFQUFFLE1BQU0sU0FBUztBQUNyRCxJQUFNLGdCQUE4QixFQUFFLE1BQU0sU0FBUztBQUVyRCxTQUFTLElBQUksTUFBYyxRQUF5QztBQUNsRSxTQUFPLEVBQUUsTUFBTSxPQUFPO0FBQ3hCO0FBRUEsU0FBUyxXQUNQLFVBQ0EsT0FDaUI7QUFDakIsU0FDRyxTQUNDLFlBQ0YsSUFBSSxLQUFLLEtBQUs7QUFFbEI7QUFPTyxTQUFTLG1CQUNkLFdBQ0EsWUFDaUI7QUFDakIsU0FBTyxXQUFXLElBQUksQ0FBQyxlQUFlO0FBQUEsSUFDcEMsTUFBTTtBQUFBLElBQ04sY0FBYyxDQUFDLFNBQVM7QUFBQSxJQUN4QixTQUFTLG9CQUFJLElBQThCO0FBQUEsTUFDekMsQ0FBQyxVQUFVLENBQUMsSUFBSSxVQUFVLGFBQWEsQ0FBQyxDQUFDO0FBQUEsTUFDekMsQ0FBQyxXQUFXLENBQUMsSUFBSSxXQUFXLGFBQWEsQ0FBQyxDQUFDO0FBQUEsTUFDM0MsQ0FBQyxTQUFTLENBQUMsSUFBSSxTQUFTLGFBQWEsQ0FBQyxDQUFDO0FBQUEsTUFDdkMsQ0FBQyxPQUFPLENBQUMsSUFBSSxPQUFPLGFBQWEsQ0FBQyxDQUFDO0FBQUEsTUFDbkM7QUFBQSxRQUNFO0FBQUEsUUFDQSxDQUFDLElBQUksZUFBZSxXQUFXLFVBQVUsU0FBUyxNQUFNLENBQUMsQ0FBQztBQUFBLE1BQzVEO0FBQUEsTUFDQTtBQUFBLFFBQ0U7QUFBQSxRQUNBLENBQUMsSUFBSSxrQkFBa0IsV0FBVyxVQUFVLFNBQVMsU0FBUyxDQUFDLENBQUM7QUFBQSxNQUNsRTtBQUFBLE1BQ0EsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLGtCQUFrQixhQUFhLENBQUMsQ0FBQztBQUFBLE1BQ3pELENBQUMsbUJBQW1CLENBQUMsSUFBSSxtQkFBbUIsYUFBYSxDQUFDLENBQUM7QUFBQSxNQUMzRCxDQUFDLGdCQUFnQixDQUFDLElBQUksZ0JBQWdCLGFBQWEsQ0FBQyxDQUFDO0FBQUEsTUFDckQ7QUFBQSxRQUNFO0FBQUEsUUFDQSxDQUFDLElBQUksZ0JBQWdCLFdBQVcsVUFBVSxVQUFVLE1BQU0sQ0FBQyxDQUFDO0FBQUEsTUFDOUQ7QUFBQSxNQUNBO0FBQUEsUUFDRTtBQUFBLFFBQ0EsQ0FBQyxJQUFJLG1CQUFtQixXQUFXLFVBQVUsVUFBVSxTQUFTLENBQUMsQ0FBQztBQUFBLE1BQ3BFO0FBQUEsTUFDQSxDQUFDLGtCQUFrQixDQUFDLElBQUksa0JBQWtCLGFBQWEsQ0FBQyxDQUFDO0FBQUEsSUFDM0QsQ0FBQztBQUFBLEVBQ0gsRUFBRTtBQUNKOyIsCiAgIm5hbWVzIjogW10KfQo=
|