@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.
Files changed (66) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.md +17 -0
  3. package/SECURITY.md +13 -0
  4. package/dist-mjs/athena/api-locator.mjs +66 -0
  5. package/dist-mjs/athena/api-matcher.mjs +206 -0
  6. package/dist-mjs/athena/athena.mjs +165 -0
  7. package/dist-mjs/athena/column.mjs +1 -0
  8. package/dist-mjs/athena/context.mjs +21 -0
  9. package/dist-mjs/athena/index.mjs +1 -0
  10. package/dist-mjs/athena/service-table.mjs +45 -0
  11. package/dist-mjs/athena/sql-file.mjs +123 -0
  12. package/dist-mjs/athena/types.mjs +1 -0
  13. package/dist-mjs/athena/validate.mjs +619 -0
  14. package/dist-mjs/athena/visitor.mjs +291 -0
  15. package/dist-mjs/get-documentation-url.mjs +9 -0
  16. package/dist-mjs/index.mjs +56 -0
  17. package/dist-mjs/openapi/deref-schema.mjs +20 -0
  18. package/dist-mjs/openapi/generate-schema.mjs +375 -0
  19. package/dist-mjs/openapi/service-schema-generator.mjs +176 -0
  20. package/dist-mjs/peggy/athena-peggy.mjs +20700 -0
  21. package/dist-mjs/service.mjs +9 -0
  22. package/dist-mjs/sql-parser.mjs +28 -0
  23. package/dist-types/athena/api-locator.d.ts +2 -0
  24. package/dist-types/athena/api-matcher.d.ts +14 -0
  25. package/dist-types/athena/athena.d.ts +5 -0
  26. package/dist-types/athena/column.d.ts +1 -0
  27. package/dist-types/athena/context.d.ts +21 -0
  28. package/dist-types/athena/index.d.ts +8 -0
  29. package/dist-types/athena/service-table.d.ts +8 -0
  30. package/dist-types/athena/sql-file.d.ts +5 -0
  31. package/dist-types/athena/types.d.ts +493 -0
  32. package/dist-types/athena/validate.d.ts +14 -0
  33. package/dist-types/athena/visitor.d.ts +75 -0
  34. package/dist-types/get-documentation-url.d.ts +1 -0
  35. package/dist-types/index.d.ts +5 -0
  36. package/dist-types/openapi/deref-schema.d.ts +1 -0
  37. package/dist-types/openapi/generate-schema.d.ts +33 -0
  38. package/dist-types/openapi/service-schema-generator.d.ts +5 -0
  39. package/dist-types/peggy/athena-peggy.d.ts +13 -0
  40. package/dist-types/service.d.ts +2 -0
  41. package/dist-types/sql-parser.d.ts +25 -0
  42. package/package.json +1 -0
  43. package/src/api/v1/swagger.yml +619 -0
  44. package/src/api/v2/swagger.yml +477 -0
  45. package/src/athena/api-locator.ts +78 -0
  46. package/src/athena/api-matcher.ts +323 -0
  47. package/src/athena/athena.ts +224 -0
  48. package/src/athena/column.ts +4 -0
  49. package/src/athena/context.ts +47 -0
  50. package/src/athena/index.ts +13 -0
  51. package/src/athena/service-table.ts +78 -0
  52. package/src/athena/sql-file.ts +161 -0
  53. package/src/athena/types.ts +568 -0
  54. package/src/athena/validate.ts +902 -0
  55. package/src/athena/visitor.ts +406 -0
  56. package/src/get-documentation-url.ts +7 -0
  57. package/src/index.ts +67 -0
  58. package/src/openapi/deref-schema.ts +20 -0
  59. package/src/openapi/generate-schema.ts +553 -0
  60. package/src/openapi/service-schema-generator.ts +241 -0
  61. package/src/peggy/athena-peggy.ts +22149 -0
  62. package/src/peggy/athena.peggy +2971 -0
  63. package/src/service.ts +11 -0
  64. package/src/services/eslintAthenaPlugin/v1/swagger.schema.deref.json +1931 -0
  65. package/src/services/eslintAthenaPlugin/v2/swagger.schema.deref.json +978 -0
  66. 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,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2F0aGVuYS9hcGktbWF0Y2hlci50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFFQSxPQUFPLFdBQVc7QUFNbEIsSUFBTSxNQUFNLE1BQU0seUNBQXlDO0FBc0IzRCxJQUFNLGNBQWtDLE1BQU07QUFJOUMsU0FBUyxJQUFJLE1BQW9EO0FBQy9ELFNBQU8sT0FBTyxTQUFTLFlBQVksU0FBUyxPQUN2QyxPQUNEO0FBQ047QUFFQSxTQUFTLGdCQUFnQixNQUFtQztBQUMxRCxRQUFNLEtBQUssSUFBSSxJQUFJO0FBQ25CLE1BQUksS0FBSyxNQUFNLE1BQU0sWUFBWTtBQUMvQixXQUFPO0FBQUEsRUFDVDtBQUNBLFFBQU0sT0FBTyxHQUFHLE1BQU07QUFDdEIsUUFBTSxZQUFZLE1BQU0sS0FBSyxDQUFDO0FBQzlCLFNBQU8sY0FBYyxTQUFZLFNBQVksVUFBVSxNQUFNLFlBQVk7QUFDM0U7QUFFQSxTQUFTLGFBQWEsTUFBMEM7QUFDOUQsUUFBTSxNQUFNLElBQUksSUFBSTtBQUNwQixTQUFPLE1BQU0sTUFBTSxNQUFNLGVBQWdCLE9BQXlCO0FBQ3BFO0FBRUEsU0FBUyxjQUFjLE1BQW1DO0FBQ3hELFFBQU0sU0FBUyxhQUFhLElBQUksR0FBRztBQUNuQyxTQUFPLE9BQU8sV0FBVyxXQUFXLE9BQU8sWUFBWSxJQUFJO0FBQzdEO0FBRUEsU0FBUyxlQUFlLE1BQW1DO0FBQ3pELFNBQU8sYUFBYSxJQUFJLEdBQUcsU0FBUztBQUN0QztBQUVBLFNBQVMsZUFBZSxNQUFtQztBQUN6RCxRQUFNLE1BQU0sSUFBSSxJQUFJO0FBQ3BCLE1BQUksTUFBTSxNQUFNLE1BQU0seUJBQXlCLE1BQU0sTUFBTSxNQUFNLFVBQVU7QUFDekUsV0FBTztBQUFBLEVBQ1Q7QUFDQSxTQUFPLE9BQU8sSUFBSSxPQUFPLE1BQU0sV0FBVyxJQUFJLE9BQU8sSUFBSTtBQUMzRDtBQUVBLFNBQVMsZUFBZSxNQUFtQztBQUN6RCxRQUFNLE1BQU0sSUFBSSxJQUFJO0FBQ3BCLFNBQU8sTUFBTSxNQUFNLE1BQU0sWUFBWSxPQUFPLElBQUksT0FBTyxNQUFNLFdBQ3pELElBQUksT0FBTyxJQUNYO0FBQ047QUFHQSxTQUFTLHdCQUNQLE1BQ0EsY0FDdUI7QUFDdkIsTUFBSSxnQkFBZ0IsSUFBSSxNQUFNLGNBQWM7QUFDMUMsV0FBTztBQUFBLEVBQ1Q7QUFDQSxRQUFNLE9BQVEsSUFBSSxJQUFJLElBQUksTUFBTSxHQUM1QjtBQUNKLE1BQUksQ0FBQyxNQUFNLFFBQVEsSUFBSSxLQUFLLEtBQUssU0FBUyxHQUFHO0FBQzNDLFdBQU87QUFBQSxFQUNUO0FBQ0EsTUFBSSxjQUFjLEtBQUssQ0FBQyxDQUFDLE1BQU0sU0FBUyxlQUFlLEtBQUssQ0FBQyxDQUFDLE1BQU0sS0FBSztBQUN2RSxXQUFPO0FBQUEsRUFDVDtBQUNBLFNBQU87QUFDVDtBQU1BLFNBQVMsa0JBQWtCLE1BQXdDO0FBQ2pFLE1BQUksd0JBQXdCLE1BQU0sT0FBTyxNQUFNLFFBQVc7QUFDeEQsV0FBTztBQUFBLEVBQ1Q7QUFDQSxRQUFNLEtBQUssSUFBSSxJQUFJO0FBQ25CLFNBQ0UsTUFBTSxRQUFRLEtBQUssYUFBYSxDQUFDLEtBQ2hDLEdBQUcsYUFBYSxFQUFnQixTQUFTO0FBRTlDO0FBR0EsU0FBUyxlQUFlLE1BQW9DO0FBQzFELFFBQU0sT0FBTyx3QkFBd0IsTUFBTSxZQUFZO0FBQ3ZELFNBQU8sZUFBZSxPQUFPLENBQUMsQ0FBQyxNQUFNO0FBQ3ZDO0FBR0EsU0FBUyxzQkFBc0IsTUFBb0M7QUFDakUsTUFBSSxnQkFBZ0IsSUFBSSxNQUFNLGVBQWU7QUFDM0MsV0FBTztBQUFBLEVBQ1Q7QUFDQSxRQUFNLFlBQWEsSUFBSSxJQUFJLElBQUksTUFBTSxHQUNqQztBQUNKLE1BQUksQ0FBQyxNQUFNLFFBQVEsU0FBUyxLQUFLLFVBQVUsV0FBVyxHQUFHO0FBQ3ZELFdBQU87QUFBQSxFQUNUO0FBQ0EsU0FBTyx3QkFBd0IsVUFBVSxDQUFDLEdBQUcsT0FBTyxNQUFNO0FBQzVEO0FBSUEsU0FBUywyQkFBMkIsTUFBbUM7QUFDckUsUUFBTSxVQUFVLGNBQWMsSUFBSTtBQUNsQyxNQUFJLFlBQVksUUFBVztBQUN6QixXQUFPLGVBQWUsSUFBSTtBQUFBLEVBQzVCO0FBRUEsUUFBTSxZQUNKLHdCQUF3QixNQUFNLE9BQU8sS0FDckMsd0JBQXdCLE1BQU0sWUFBWTtBQUM1QyxNQUFJLGNBQWMsUUFBVztBQUMzQixXQUFPLGVBQWUsVUFBVSxDQUFDLENBQUM7QUFBQSxFQUNwQztBQUNBLE1BQUksc0JBQXNCLElBQUksR0FBRztBQUMvQixVQUFNLFlBQWEsSUFBSSxJQUFJLElBQUksTUFBTSxHQUNqQztBQUNKLFVBQU0sVUFBVSxJQUFJLFlBQVksQ0FBQyxDQUFDO0FBQ2xDLFVBQU0sWUFBYSxVQUFVLE1BQU0sR0FDL0I7QUFDSixXQUFPLGVBQWUsWUFBWSxDQUFDLENBQUM7QUFBQSxFQUN0QztBQUNBLFNBQU87QUFDVDtBQU1BLFNBQVMsMEJBQ1AsT0FDQSxPQUNvQjtBQUNwQixTQUFPLENBQUMsU0FBUztBQUNmLFVBQU0sT0FBTyxLQUFLLE1BQU0sR0FBRyxFQUFFLFFBQVEsQ0FBQztBQUN0QyxRQUFJLHlCQUF5QixFQUFFLE1BQU0sT0FBTyxNQUFNLE1BQU0sQ0FBQztBQUN6RCxXQUFPLE1BQU0sV0FBVyxHQUFHLE1BQU0sT0FBTyxPQUFPLFNBQVM7QUFBQSxFQUMxRDtBQUNGO0FBSUEsU0FBUyxtQkFDUCxNQUNBLFlBQ2dDO0FBQ2hDLE1BQUksS0FBSyxhQUFhLEtBQUs7QUFDekIsV0FBTztBQUFBLEVBQ1Q7QUFDQSxRQUFNLEVBQUUsTUFBTSxNQUFNLElBQUk7QUFFeEIsUUFBTSxpQkFBaUIsMkJBQTJCLElBQUk7QUFHdEQsTUFDRSxtQkFBbUIsVUFDbkIsZUFBZSxVQUNmLG1CQUFtQixZQUNuQjtBQUNBLFdBQU87QUFBQSxFQUNUO0FBR0EsTUFBSSxjQUFjLElBQUksTUFBTSxVQUFVO0FBQ3BDLFVBQU0sUUFBUSxlQUFlLEtBQUs7QUFDbEMsUUFBSSxVQUFVLFFBQVc7QUFDdkIsYUFBTyxDQUFDLE9BQU8sV0FBVyxXQUFXO0FBQUEsSUFDdkM7QUFBQSxFQUNGO0FBR0EsTUFBSSxjQUFjLElBQUksTUFBTSxrQkFBa0I7QUFDNUMsVUFBTSxRQUFRLGVBQWUsS0FBSztBQUNsQyxRQUFJLFVBQVUsUUFBVztBQUN2QixhQUFPLENBQUMsT0FBTyxTQUFTLGlCQUFpQixpQkFBaUI7QUFBQSxJQUM1RDtBQUFBLEVBQ0Y7QUFHQSxNQUFJLGtCQUFrQixJQUFJLEdBQUc7QUFDM0IsVUFBTSxRQUFRLEtBQUssWUFBWSxDQUFDLEdBQUcsTUFBTTtBQUN6QyxVQUFNLFFBQVEsZUFBZSxLQUFLO0FBQ2xDLFFBQUksT0FBTyxVQUFVLFlBQVksVUFBVSxRQUFXO0FBQ3BELGFBQU8sMEJBQTBCLE9BQU8sS0FBSztBQUFBLElBQy9DO0FBQUEsRUFDRjtBQUdBLE1BQUksZUFBZSxJQUFJLEdBQUc7QUFDeEIsVUFBTSxRQUFRO0FBQUEsTUFDWix3QkFBd0IsTUFBTSxZQUFZLElBQUksQ0FBQztBQUFBLElBQ2pEO0FBQ0EsVUFBTSxRQUFRLGVBQWUsS0FBSztBQUNsQyxRQUFJLFVBQVUsVUFBYSxVQUFVLFFBQVc7QUFDOUMsYUFBTywwQkFBMEIsT0FBTyxLQUFLO0FBQUEsSUFDL0M7QUFBQSxFQUNGO0FBR0EsTUFBSSxzQkFBc0IsSUFBSSxHQUFHO0FBQy9CLFVBQU0sUUFBUSxlQUFlLEtBQUs7QUFDbEMsUUFBSSxVQUFVLFFBQVc7QUFDdkIsYUFBTyxDQUFDLFNBQVMsS0FBSyxNQUFNLEdBQUcsRUFBRSxXQUFXO0FBQUEsSUFDOUM7QUFBQSxFQUNGO0FBRUEsU0FBTztBQUNUO0FBRUEsU0FBUyxlQUNQLE1BQ0EsWUFDb0I7QUFDcEIsUUFBTSxPQUFPLElBQUksSUFBSTtBQUNyQixNQUFJLE9BQU8sTUFBTSxNQUFNLGVBQWU7QUFDcEMsV0FBTztBQUFBLEVBQ1Q7QUFFQSxRQUFNLFNBQVM7QUFFZixVQUFRLE9BQU8sVUFBVTtBQUFBLElBQ3ZCLEtBQUssT0FBTztBQUNWLFlBQU0sV0FBVyxlQUFlLE9BQU8sTUFBTSxVQUFVO0FBQ3ZELFlBQU0sWUFBWSxlQUFlLE9BQU8sT0FBTyxVQUFVO0FBQ3pELGFBQU8sQ0FBQyxNQUFNLFFBQVEsU0FDcEIsU0FBUyxNQUFNLFFBQVEsSUFBSSxLQUFLLFVBQVUsTUFBTSxRQUFRLElBQUk7QUFBQSxJQUNoRTtBQUFBLElBQ0EsS0FBSyxNQUFNO0FBQ1QsWUFBTSxXQUFXLGVBQWUsT0FBTyxNQUFNLFVBQVU7QUFDdkQsWUFBTSxZQUFZLGVBQWUsT0FBTyxPQUFPLFVBQVU7QUFDekQsYUFBTyxDQUFDLE1BQU0sUUFBUSxTQUNwQixTQUFTLE1BQU0sUUFBUSxJQUFJLEtBQUssVUFBVSxNQUFNLFFBQVEsSUFBSTtBQUFBLElBQ2hFO0FBQUEsSUFDQSxLQUFLLE9BQU87QUFDVixZQUFNLFlBQVksZUFBZSxPQUFPLE1BQU0sVUFBVTtBQUN4RCxhQUFPLENBQUMsTUFBTSxRQUFRLFNBQVMsQ0FBQyxVQUFVLE1BQU0sUUFBUSxJQUFJO0FBQUEsSUFDOUQ7QUFBQSxJQUNBLFNBQVM7QUFDUCxhQUFPLG1CQUFtQixRQUFRLFVBQVUsS0FBSztBQUFBLElBQ25EO0FBQUEsRUFDRjtBQUNGO0FBRU8sU0FBUyxTQUNkLFdBQ0EsVUFDQSxZQUNnQztBQUNoQyxRQUFNLGFBQWMsU0FBb0MsTUFBTTtBQUM5RCxRQUFNLFlBQVk7QUFBQSxJQUNmLFVBQWtDO0FBQUEsSUFDbkM7QUFBQSxFQUNGO0FBRUEsUUFBTSxnQkFBb0MsV0FDdkMsUUFBUSxDQUFDLGNBQWMsT0FBTyxRQUFRLFVBQVUsSUFBSSxDQUFDLEVBQ3JEO0FBQUEsSUFBUSxDQUFDLENBQUMsTUFBTSxVQUFVLE1BQ3pCLE9BQU8sUUFBUSxVQUFVLEVBQUUsSUFBSSxDQUFDLENBQUMsUUFBUSxnQkFBZ0IsT0FBTztBQUFBLE1BQzlEO0FBQUEsTUFDQSxRQUFRLE9BQU8sWUFBWTtBQUFBLE1BQzNCO0FBQUEsSUFDRixFQUFFO0FBQUEsRUFDSjtBQUNGLE1BQUksMkJBQTJCLGNBQWMsTUFBTTtBQUVuRCxRQUFNLGNBQWMsY0FBYztBQUFBLElBQ2hDLENBQUMsRUFBRSxNQUFNLFFBQVEsaUJBQWlCLE1BQ2hDLE9BQU8sUUFBUSxpQkFBaUIsU0FBUyxFQUFFO0FBQUEsTUFDekMsQ0FBQyxDQUFDLGNBQWMsY0FBYyxNQUM1QixVQUFVLE1BQU0sUUFBUSxZQUFZLElBQ2hDO0FBQUEsUUFDRTtBQUFBLFVBQ0U7QUFBQSxVQUNBO0FBQUEsVUFDQSxTQUFTLGlCQUFpQjtBQUFBLFVBQzFCLFVBQVU7QUFBQSxRQUNaO0FBQUEsTUFDRixJQUNBLENBQUM7QUFBQSxJQUNUO0FBQUEsRUFDSjtBQUNBLE1BQUksZ0JBQWdCLFlBQVksTUFBTTtBQUV0QyxNQUFJLFlBQVksV0FBVyxHQUFHO0FBQzVCLFFBQUksZ0JBQWdCO0FBQ3BCLFVBQU0sSUFBSTtBQUFBLE1BQ1I7QUFBQSxJQUNGO0FBQUEsRUFDRjtBQUNBLFNBQU87QUFDVDsiLAogICJuYW1lcyI6IFtdCn0K
@@ -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=