@checkdigit/eslint-plugin 7.17.1 → 7.18.0-PR.143-9946

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 (80) hide show
  1. package/dist-mjs/athena/api-locator.mjs +30 -0
  2. package/dist-mjs/athena/api-matcher.mjs +108 -0
  3. package/dist-mjs/athena/athena.mjs +328 -0
  4. package/dist-mjs/athena/column.mjs +1 -0
  5. package/dist-mjs/athena/context.mjs +21 -0
  6. package/dist-mjs/athena/index.mjs +1 -0
  7. package/dist-mjs/athena/service-table.mjs +32 -0
  8. package/dist-mjs/athena/types.mjs +1 -0
  9. package/dist-mjs/athena/visitor.mjs +258 -0
  10. package/dist-mjs/index.mjs +8 -4
  11. package/dist-mjs/no-status-code-assert.mjs +1 -1
  12. package/dist-mjs/openapi/deref-schema.mjs +14 -0
  13. package/dist-mjs/openapi/generate-schema.mjs +273 -0
  14. package/dist-mjs/openapi/service-schema-generator.mjs +147 -0
  15. package/dist-mjs/peggy/athena-peggy.mjs +20629 -0
  16. package/dist-types/athena/api-locator.d.ts +2 -0
  17. package/dist-types/athena/api-matcher.d.ts +14 -0
  18. package/dist-types/athena/athena.d.ts +6 -0
  19. package/dist-types/athena/column.d.ts +1 -0
  20. package/dist-types/athena/context.d.ts +21 -0
  21. package/dist-types/athena/index.d.ts +8 -0
  22. package/dist-types/athena/service-table.d.ts +8 -0
  23. package/dist-types/athena/types.d.ts +474 -0
  24. package/dist-types/athena/visitor.d.ts +63 -0
  25. package/dist-types/no-status-code-assert.d.ts +1 -1
  26. package/dist-types/openapi/deref-schema.d.ts +1 -0
  27. package/dist-types/openapi/generate-schema.d.ts +33 -0
  28. package/dist-types/openapi/service-schema-generator.d.ts +5 -0
  29. package/dist-types/peggy/athena-peggy.d.ts +13 -0
  30. package/package.json +1 -96
  31. package/src/athena/ATHENA.md +387 -0
  32. package/src/athena/PLAN.md +355 -0
  33. package/src/athena/api-locator.ts +39 -0
  34. package/src/athena/api-matcher.ts +169 -0
  35. package/src/athena/athena.ts +488 -0
  36. package/src/athena/column.ts +2 -0
  37. package/src/athena/context.ts +47 -0
  38. package/src/athena/index.ts +11 -0
  39. package/src/athena/service-table.ts +55 -0
  40. package/src/athena/types.ts +526 -0
  41. package/src/athena/visitor.ts +365 -0
  42. package/src/index.ts +4 -0
  43. package/src/no-side-effects.ts +1 -1
  44. package/src/no-status-code-assert.ts +2 -2
  45. package/src/openapi/deref-schema.ts +14 -0
  46. package/src/openapi/generate-schema.ts +422 -0
  47. package/src/openapi/service-schema-generator.ts +189 -0
  48. package/src/peggy/athena-chat.peggy +608 -0
  49. package/src/peggy/athena-peggy.ts +22078 -0
  50. package/src/peggy/athena.peggy +2967 -0
  51. package/src/require-service-call-response-declaration.ts +2 -2
  52. package/src/services/interchange/v1/swagger.schema.deref.json +849 -0
  53. package/src/services/interchange/v1/swagger.schema.json +473 -0
  54. package/src/services/interchange/v1/swagger.yml +414 -0
  55. package/src/services/ledger/v1/swagger.schema.deref.json +6694 -0
  56. package/src/services/ledger/v1/swagger.schema.json +1820 -0
  57. package/src/services/ledger/v1/swagger.yml +1094 -0
  58. package/src/services/link/v1/swagger.schema.deref.json +648 -0
  59. package/src/services/link/v1/swagger.schema.json +444 -0
  60. package/src/services/link/v1/swagger.yml +343 -0
  61. package/src/services/message/v1/swagger.schema.deref.json +22049 -0
  62. package/src/services/message/v1/swagger.schema.json +3470 -0
  63. package/src/services/message/v1/swagger.yml +2798 -0
  64. package/src/services/message/v2/swagger.schema.deref.json +72221 -0
  65. package/src/services/message/v2/swagger.schema.json +3558 -0
  66. package/src/services/message/v2/swagger.yml +3009 -0
  67. package/src/services/paymentCard/v1/swagger.schema.deref.json +4346 -0
  68. package/src/services/paymentCard/v1/swagger.schema.json +2181 -0
  69. package/src/services/paymentCard/v1/swagger.yml +1161 -0
  70. package/src/services/paymentCard/v2/swagger.schema.deref.json +4336 -0
  71. package/src/services/paymentCard/v2/swagger.schema.json +2155 -0
  72. package/src/services/paymentCard/v2/swagger.yml +1149 -0
  73. package/src/services/person/v1/swagger.schema.deref.json +6786 -0
  74. package/src/services/person/v1/swagger.schema.json +1445 -0
  75. package/src/services/person/v1/swagger.yml +1157 -0
  76. package/src/services/teampayApproval/v1/swagger.schema.deref.json +9898 -0
  77. package/src/services/teampayCardManagement/v1/swagger.schema.deref.json +6187 -0
  78. package/src/services/teampayClientManagement/v1/swagger.schema.deref.json +4914 -0
  79. package/src/services/teampayClientManagement/v1/swagger.schema.json +1964 -0
  80. package/src/services/teampayClientManagement/v1/swagger.yml +1376 -0
@@ -0,0 +1,608 @@
1
+ {
2
+ // ===== Helpers =====
3
+ function node(type, props) { return Object.assign({ type }, props); }
4
+ function list(first, rest) { return [first, ...rest.map(r => r[3])]; }
5
+ function qname(first, rest) { return [first, ...rest.map(r => r[3])].join('.'); }
6
+ }
7
+
8
+ Start
9
+ = _ stmts:StatementList _ EOF { return stmts; }
10
+
11
+ EOF
12
+ = !.
13
+
14
+ StatementList
15
+ = head:Statement tail:(_ ";" _ Statement)* _ ";"? {
16
+ return [head, ...tail.map(t => t[3])];
17
+ }
18
+
19
+ Statement
20
+ = Query
21
+ / DDL
22
+ / ShowStmt
23
+ / DescribeStmt
24
+ / MsckRepair
25
+ / UseStmt
26
+
27
+ // ======================
28
+ // DML (Trino-style)
29
+ // ======================
30
+
31
+ Query
32
+ = WithQuery / QueryTerm
33
+
34
+ WithQuery
35
+ = "WITH"i __ ctes:CTEList __ body:QueryTerm {
36
+ return node("WithQuery", { ctes, body });
37
+ }
38
+
39
+ CTEList
40
+ = first:CTE rest:(_ "," _ CTE)* { return list(first, rest); }
41
+
42
+ CTE
43
+ = name:Ident _ "AS"i _ "(" _ q:Query _ ")" {
44
+ return node("CTE", { name, query: q });
45
+ }
46
+
47
+ QueryTerm
48
+ = left:QueryPrimary rest:(_ SetOp _ QueryPrimary)+ {
49
+ return rest.reduce((acc, r) => node("SetOp", { op: r[1], left: acc, right: r[3] }), left);
50
+ }
51
+ / QueryPrimary
52
+
53
+ SetOp
54
+ = "UNION ALL"i { return "UNION ALL"; }
55
+ / "UNION"i { return "UNION"; }
56
+ / "INTERSECT"i { return "INTERSECT"; }
57
+ / "EXCEPT"i { return "EXCEPT"; }
58
+
59
+ QueryPrimary
60
+ = SelectStmt
61
+ / "(" _ q:Query _ ")" { return q; }
62
+
63
+ SelectStmt
64
+ = "SELECT"i _ "DISTINCT"i _ sel:SelectList from:FromClause? where:WhereClause?
65
+ group:GroupByClause? having:HavingClause? window:WindowClause?
66
+ order:OrderByClause? limit:LimitClause?
67
+ {
68
+ return node("Select", {
69
+ distinct: true, select: sel,
70
+ from, where, groupBy: group ?? null, having: having ?? null,
71
+ window: window ?? null, orderBy: order ?? null, limit: limit ?? null
72
+ });
73
+ }
74
+ / "SELECT"i _ sel:SelectList from:FromClause? where:WhereClause?
75
+ group:GroupByClause? having:HavingClause? window:WindowClause?
76
+ order:OrderByClause? limit:LimitClause?
77
+ {
78
+ return node("Select", {
79
+ distinct: false, select: sel,
80
+ from, where, groupBy: group ?? null, having: having ?? null,
81
+ window: window ?? null, orderBy: order ?? null, limit: limit ?? null
82
+ });
83
+ }
84
+
85
+ SelectList
86
+ = first:SelectItem rest:(_ "," _ SelectItem)* { return list(first, rest); }
87
+
88
+ SelectItem
89
+ = e:Expression _ "AS"i __ a:Ident { return node("SelectItem", { expr: e, alias: a }); }
90
+ / e:Expression __ a:Ident { return node("SelectItem", { expr: e, alias: a }); }
91
+ / e:Expression { return node("SelectItem", { expr: e }); }
92
+ / "*" { return node("Star", {}); }
93
+ / q:QualifiedStar { return node("QualifiedStar", { prefix: q }); }
94
+
95
+ QualifiedStar
96
+ = first:Ident rest:(_ "." _ Ident)+ _ "." _ "*" {
97
+ return [first, ...rest.map(r => r[3])];
98
+ }
99
+
100
+ FromClause
101
+ = _ "FROM"i _ src:Relation { return src; }
102
+
103
+ Relation
104
+ = JoinedRelation
105
+ / TableOrSubquery
106
+
107
+ JoinedRelation
108
+ = left:TableOrSubquery rest:(_ JoinSpec _ TableOrSubquery)+ {
109
+ return rest.reduce((acc, r) => node("Join", {
110
+ kind: r[1].kind, lateral: r[1].lateral, criteria: r[1].criteria ?? null,
111
+ left: acc, right: r[3]
112
+ }), left);
113
+ }
114
+
115
+ JoinSpec
116
+ = "JOIN"i _ on:JoinCriteria? { return { kind:"INNER", lateral:false, criteria:on ?? null }; }
117
+ / "INNER JOIN"i _ on:JoinCriteria? { return { kind:"INNER", lateral:false, criteria:on ?? null }; }
118
+ / "LEFT JOIN"i _ on:JoinCriteria? { return { kind:"LEFT", lateral:false, criteria:on ?? null }; }
119
+ / "LEFT OUTER JOIN"i _ on:JoinCriteria? { return { kind:"LEFT", lateral:false, criteria:on ?? null }; }
120
+ / "RIGHT JOIN"i _ on:JoinCriteria? { return { kind:"RIGHT", lateral:false, criteria:on ?? null }; }
121
+ / "FULL JOIN"i _ on:JoinCriteria? { return { kind:"FULL", lateral:false, criteria:on ?? null }; }
122
+ / "FULL OUTER JOIN"i _ on:JoinCriteria? { return { kind:"FULL", lateral:false, criteria:on ?? null }; }
123
+ / "CROSS JOIN"i { return { kind:"CROSS", lateral:false, criteria:null }; }
124
+ / "LATERAL VIEW JOIN"i _ on:JoinCriteria? { return { kind:"LATERAL VIEW", lateral:true, criteria:on ?? null }; }
125
+
126
+ JoinCriteria
127
+ = "ON"i _ e:Expression { return { type:"ON", expr:e }; }
128
+ / "USING"i _ "(" _ cols:IdentList _ ")" { return { type:"USING", columns: cols }; }
129
+
130
+ TableOrSubquery
131
+ = "(" _ q:Query _ ")" __ a:Ident { return node("Subquery", { query:q, alias:a }); }
132
+ / "(" _ q:Query _ ")" { return node("Subquery", { query:q }); }
133
+ / t:TableName __ a:Ident { return node("Table", { name:t, alias:a }); }
134
+ / t:TableName { return node("Table", { name:t }); }
135
+ / "UNNEST"i _ "(" _ args:ExprList _ ")" __ a:Ident {
136
+ return node("Unnest", { args, alias:a });
137
+ }
138
+ / "UNNEST"i _ "(" _ args:ExprList _ ")" {
139
+ return node("Unnest", { args });
140
+ }
141
+
142
+ TableName
143
+ = first:Ident rest:(_ "." _ Ident)* { return qname(first, rest); }
144
+
145
+ WhereClause
146
+ = _ "WHERE"i _ e:Expression { return e; }
147
+
148
+ GroupByClause
149
+ = _ "GROUP BY"i __ items:GroupByItemList { return items; }
150
+
151
+ GroupByItemList
152
+ = first:GroupByItem rest:(_ "," _ GroupByItem)* { return list(first, rest); }
153
+
154
+ GroupByItem
155
+ = "ROLLUP"i _ "(" _ l:ExprList _ ")" { return node("Rollup", { items:l }); }
156
+ / "CUBE"i _ "(" _ l:ExprList _ ")" { return node("Cube", { items:l }); }
157
+ / "GROUPING SETS"i _ "(" _ sets:GroupingSets _ ")" { return node("GroupingSets", { sets }); }
158
+ / e:Expression { return e; }
159
+
160
+ GroupingSets
161
+ = first:GroupingSet rest:(_ "," _ GroupingSet)* { return list(first, rest); }
162
+
163
+ GroupingSet
164
+ = "(" _ ")" { return []; }
165
+ / "(" _ l:ExprList _ ")" { return l; }
166
+
167
+ HavingClause
168
+ = _ "HAVING"i _ e:Expression { return e; }
169
+
170
+ WindowClause
171
+ = _ "WINDOW"i _ defs:WindowDefList { return defs; }
172
+
173
+ WindowDefList
174
+ = first:WindowDef rest:(_ "," _ WindowDef)* { return list(first, rest); }
175
+
176
+ WindowDef
177
+ = name:Ident _ "AS"i _ spec:WindowSpec { return node("WindowDef", { name, spec }); }
178
+
179
+ WindowSpec
180
+ = "(" _ p:PartitionBy? o:OrderByClause? f:FrameSpec? _ ")" {
181
+ return node("WindowSpec", { partitionBy: p ?? [], orderBy: o ?? null, frame: f ?? null });
182
+ }
183
+
184
+ PartitionBy
185
+ = "PARTITION BY"i __ l:ExprList { return l; }
186
+
187
+ FrameSpec
188
+ = "ROWS"i _ FrameExtent
189
+ / "RANGE"i _ FrameExtent
190
+
191
+ FrameExtent
192
+ = "BETWEEN"i __ a:FrameBound __ "AND"i __ b:FrameBound { return { between:true, start:a, end:b }; }
193
+ / b:FrameBound { return { between:false, end:b }; }
194
+
195
+ FrameBound
196
+ = "UNBOUNDED PRECEDING"i { return { type:"UNBOUNDED_PRECEDING" }; }
197
+ / "UNBOUNDED FOLLOWING"i { return { type:"UNBOUNDED_FOLLOWING" }; }
198
+ / n:Integer __ "PRECEDING"i { return { type:"PRECEDING", value:n }; }
199
+ / n:Integer __ "FOLLOWING"i { return { type:"FOLLOWING", value:n }; }
200
+ / "CURRENT ROW"i { return { type:"CURRENT_ROW" }; }
201
+
202
+ OrderByClause
203
+ = _ "ORDER BY"i __ first:SortItem rest:(_ "," _ SortItem)* { return list(first, rest); }
204
+
205
+ SortItem
206
+ = e:Expression _ dir:SortDir? _ nulls:NullsOrder? {
207
+ return node("SortItem", { expr:e, direction: dir ?? "ASC", nulls: nulls ?? null });
208
+ }
209
+
210
+ SortDir
211
+ = "ASC"i { return "ASC"; } / "DESC"i { return "DESC"; }
212
+
213
+ NullsOrder
214
+ = "NULLS FIRST"i { return "NULLS FIRST"; }
215
+ / "NULLS LAST"i { return "NULLS LAST"; }
216
+
217
+ LimitClause
218
+ = _ "LIMIT"i __ n:Integer { return n; }
219
+
220
+ // ======================
221
+ // Expressions
222
+ // ======================
223
+
224
+ ExprList
225
+ = first:Expression rest:(_ "," _ Expression)* { return list(first, rest); }
226
+
227
+ Expression
228
+ = LogicalOr
229
+
230
+ LogicalOr
231
+ = left:LogicalAnd rest:(_ "OR"i _ LogicalAnd)* {
232
+ return rest.reduce((acc, r) => node("BinaryOp", { op:"OR", left:acc, right:r[3] }), left);
233
+ }
234
+
235
+ LogicalAnd
236
+ = left:NotExpr rest:(_ "AND"i _ NotExpr)* {
237
+ return rest.reduce((acc, r) => node("BinaryOp", { op:"AND", left:acc, right:r[3] }), left);
238
+ }
239
+
240
+ NotExpr
241
+ = "NOT"i __ e:NotExpr { return node("UnaryOp", { op:"NOT", expr:e }); }
242
+ / Predicate
243
+
244
+ Predicate
245
+ = left:ValueExpr tail:PredicateTail? {
246
+ if (!tail) return left;
247
+ return node("Predicate", Object.assign({ left }, tail));
248
+ }
249
+
250
+ PredicateTail
251
+ = _ "IS NULL"i { return { kind:"IS NULL" }; }
252
+ / _ "IS NOT NULL"i { return { kind:"IS NOT NULL" }; }
253
+ / _ "IS TRUE"i { return { kind:"IS TRUE" }; }
254
+ / _ "IS FALSE"i { return { kind:"IS FALSE" }; }
255
+ / _ "IS NOT TRUE"i { return { kind:"IS NOT TRUE" }; }
256
+ / _ "IS NOT FALSE"i { return { kind:"IS NOT FALSE" }; }
257
+ / _ "IN"i _ "(" _ l:ExprList _ ")" { return { kind:"IN", list:l }; }
258
+ / _ "NOT IN"i _ "(" _ l:ExprList _ ")" { return { kind:"NOT IN", list:l }; }
259
+ / _ "BETWEEN"i __ a:ValueExpr __ "AND"i __ b:ValueExpr { return { kind:"BETWEEN", lower:a, upper:b }; }
260
+ / _ "LIKE"i __ p:ValueExpr ( __ "ESCAPE"i __ e:ValueExpr )? {
261
+ return { kind:"LIKE", pattern:p, escape: e ?? null };
262
+ }
263
+ / _ "REGEXP_LIKE"i _ "(" _ v:Expression _ "," _ r:Expression ( _ "," _ f:Expression )? _ ")" {
264
+ return { kind:"REGEXP_LIKE", args: [v, r].concat(f ? [f] : []) };
265
+ }
266
+ / _ op:CmpOp _ r:ValueExpr { return { kind:"COMPARE", op, right:r }; }
267
+
268
+ CmpOp
269
+ = "=" / "<>" / "!=" / "<=" / ">=" / "<" / ">"
270
+
271
+ ValueExpr
272
+ = Additive
273
+
274
+ Additive
275
+ = left:Multiplicative rest:(_ ("+" / "-") _ Multiplicative)* {
276
+ return rest.reduce((acc, r) => node("BinaryOp", { op:r[1], left:acc, right:r[3] }), left);
277
+ }
278
+
279
+ Multiplicative
280
+ = left:Unary rest:(_ ("*" / "/" / "%") _ Unary)* {
281
+ return rest.reduce((acc, r) => node("BinaryOp", { op:r[1], left:acc, right:r[3] }), left);
282
+ }
283
+
284
+ Unary
285
+ = "+" _ u:Unary { return node("UnaryOp", { op:"+", expr:u }); }
286
+ / "-" _ u:Unary { return node("UnaryOp", { op:"-", expr:u }); }
287
+ / Primary
288
+
289
+ Primary
290
+ = Literal
291
+ / QualifiedName
292
+ / FunctionCall
293
+ / "CASE"i __ CaseExpr "END"i
294
+ / "(" _ Expression _ ")"
295
+ / ArrayLiteral
296
+ / MapLiteral
297
+ / StructLiteral
298
+ / CastExpr
299
+ / TryExpr
300
+ / SubselectPrimary
301
+
302
+ SubselectPrimary
303
+ = "(" _ q:Query _ ")" { return node("SubqueryExpr", { query:q }); }
304
+
305
+ CaseExpr
306
+ = value:Expression? _ branches:WhenThen+ _ elsePart:ElsePart? {
307
+ return node("Case", { value: value ?? null, whens: branches, else: elsePart ?? null });
308
+ }
309
+
310
+ WhenThen
311
+ = "WHEN"i __ c:Expression __ "THEN"i __ v:Expression { return { when:c, then:v }; }
312
+
313
+ ElsePart
314
+ = "ELSE"i __ e:Expression { return e; }
315
+
316
+ FunctionCall
317
+ = name:QualifiedName _ "(" _ args:StarOrDistinctArgs? _ ")" filter:FilterClause? over:OverClause? {
318
+ return node("FunctionCall", { name, args: args ?? [], filter: filter ?? null, over: over ?? null });
319
+ }
320
+
321
+ StarOrDistinctArgs
322
+ = "*" { return [{ type:"StarArg" }]; }
323
+ / "DISTINCT"i __ l:ExprList { return [{ type:"DistinctArgs", args:l }]; }
324
+ / l:ExprList { return l; }
325
+
326
+ FilterClause
327
+ = _ "FILTER"i _ "(" _ "WHERE"i __ e:Expression _ ")" { return e; }
328
+
329
+ OverClause
330
+ = _ "OVER"i _ spec:WindowSpec { return spec; }
331
+
332
+ CastExpr
333
+ = "CAST"i _ "(" _ e:Expression _ "AS"i __ t:TypeSpec _ ")" {
334
+ return node("Cast", { expr:e, type:t });
335
+ }
336
+
337
+ TryExpr
338
+ = "TRY"i _ "(" _ e:Expression _ ")" { return node("Try", { expr:e }); }
339
+
340
+ // ======================
341
+ // Literals & Types
342
+ // ======================
343
+
344
+ Literal
345
+ = StringLiteral
346
+ / NumericLiteral
347
+ / "NULL"i { return node("Null", {}); }
348
+ / "TRUE"i { return node("Boolean", { value:true }); }
349
+ / "FALSE"i { return node("Boolean", { value:false }); }
350
+ / "INTERVAL"i __ s:StringLiteral __ u:Ident { return node("Interval", { value:s.value, unit:u }); }
351
+ / DateTimeLiteral
352
+
353
+ DateTimeLiteral
354
+ = "DATE"i __ s:StringLiteral { return node("Date", { value:s.value }); }
355
+ / "TIME"i __ s:StringLiteral { return node("Time", { value:s.value }); }
356
+ / "TIMESTAMP"i __ s:StringLiteral { return node("Timestamp", { value:s.value }); }
357
+
358
+ ArrayLiteral
359
+ = "ARRAY"i _ "[" _ l:ExprList? _ "]" { return node("Array", { elements: l ?? [] }); }
360
+
361
+ MapLiteral
362
+ = "MAP"i _ "(" _ pairs:KeyValueList _ ")" { return node("Map", { entries:pairs }); }
363
+
364
+ KeyValueList
365
+ = first:KeyValue rest:(_ "," _ KeyValue)* { return list(first, rest); }
366
+
367
+ KeyValue
368
+ = k:Expression _ "," _ v:Expression { return { key:k, value:v }; }
369
+
370
+ StructLiteral
371
+ = "ROW"i _ "(" _ l:ExprList _ ")" { return node("Row", { fields:l }); }
372
+
373
+ NumericLiteral
374
+ = n:Float { return node("Number", { value:parseFloat(n) }); }
375
+ / n:Integer { return node("Number", { value:parseInt(n,10) }); }
376
+
377
+ StringLiteral
378
+ = "'" chars:("''" { return "'"; } / [^'])* "'" {
379
+ return node("String", { value: chars.join("") });
380
+ }
381
+
382
+ Integer
383
+ = digits:[0-9]+ { return digits.join(""); }
384
+
385
+ Float
386
+ = [0-9]+ "." [0-9]* ([eE] [+\-]? [0-9]+)? { return text(); }
387
+ / "." [0-9]+ ([eE] [+\-]? [0-9]+)? { return text(); }
388
+ / [0-9]+ [eE] [+\-]? [0-9]+ { return text(); }
389
+
390
+ TypeSpec
391
+ = SimpleType / ComplexType
392
+
393
+ SimpleType
394
+ = "BOOLEAN"i { return {name:"BOOLEAN"}; }
395
+ / "TINYINT"i { return {name:"TINYINT"}; }
396
+ / "SMALLINT"i { return {name:"SMALLINT"}; }
397
+ / "INT"i { return {name:"INT"}; }
398
+ / "INTEGER"i { return {name:"INTEGER"}; }
399
+ / "BIGINT"i { return {name:"BIGINT"}; }
400
+ / "REAL"i { return {name:"REAL"}; }
401
+ / "FLOAT"i { return {name:"FLOAT"}; }
402
+ / "DOUBLE"i { return {name:"DOUBLE"}; }
403
+ / "DECIMAL"i _ "(" _ p:Integer _ "," _ s:Integer _ ")" { return {name:"DECIMAL", precision:+p, scale:+s}; }
404
+ / "VARCHAR"i _ "(" _ n:Integer _ ")" { return {name:"VARCHAR", length:+n}; }
405
+ / "VARCHAR"i { return {name:"VARCHAR"}; }
406
+ / "CHAR"i _ "(" _ n:Integer _ ")" { return {name:"CHAR", length:+n}; }
407
+ / "VARBINARY"i { return {name:"VARBINARY"}; }
408
+ / "JSON"i { return {name:"JSON"}; }
409
+ / "DATE"i { return {name:"DATE"}; }
410
+ / "TIME"i { return {name:"TIME"}; }
411
+ / "TIMESTAMP"i { return {name:"TIMESTAMP"}; }
412
+
413
+ ComplexType
414
+ = "ARRAY"i _ "(" _ t:TypeSpec _ ")" { return {name:"ARRAY", element:t}; }
415
+ / "MAP"i _ "(" _ k:TypeSpec _ "," _ v:TypeSpec _ ")" { return {name:"MAP", key:k, value:v}; }
416
+ / "ROW"i _ "(" _ fields:RowTypeFields _ ")" { return {name:"ROW", fields}; }
417
+
418
+ RowTypeFields
419
+ = first:RowTypeField rest:(_ "," _ RowTypeField)* { return list(first, rest); }
420
+
421
+ RowTypeField
422
+ = n:Ident _ t:TypeSpec { return { name:n, type:t }; }
423
+
424
+ // ======================
425
+ // Names & identifiers
426
+ // ======================
427
+
428
+ QualifiedName
429
+ = first:Ident rest:(_ "." _ Ident)* {
430
+ return node("Identifier", { name: qname(first, rest) });
431
+ }
432
+
433
+ IdentList
434
+ = first:Ident rest:(_ "," _ Ident)* { return list(first, rest); }
435
+
436
+ Ident
437
+ = DQuotedIdent
438
+ / BacktickIdent
439
+ / UnquotedIdent
440
+
441
+ // double-quoted; "" escapes "
442
+ DQuotedIdent
443
+ = '"' chars:('""' { return '"'; } / [^"])* '"' {
444
+ return chars.join("");
445
+ }
446
+
447
+ // backtick-quoted; `` escapes `
448
+ BacktickIdent
449
+ = '`' chars:('``' { return '`'; } / [^`])* '`' {
450
+ return chars.join("");
451
+ }
452
+
453
+ // unquoted: start letter/_ ; continue letter/digit/_
454
+ UnquotedIdent
455
+ = $([A-Za-z_][A-Za-z0-9_]*) { return text(); }
456
+
457
+ // ======================
458
+ // DDL (Hive-style in Athena)
459
+ // ======================
460
+
461
+ DDL
462
+ = CreateDatabase
463
+ / DropDatabase
464
+ / CreateTable
465
+ / DropTable
466
+ / CreateView
467
+ / DropView
468
+ / AlterTable
469
+
470
+ UseStmt
471
+ = "USE"i __ n:Ident { return node("Use", { database:n }); }
472
+
473
+ CreateDatabase
474
+ = "CREATE DATABASE"i _ ifn:IfNotExists? n:Ident props:DbProperties? {
475
+ return node("CreateDatabase", { name:n, ifNotExists: !!ifn, properties: props ?? {} });
476
+ }
477
+
478
+ IfNotExists
479
+ = "IF NOT EXISTS"i _
480
+
481
+ DbProperties
482
+ = _ "WITH DBPROPERTIES"i _ "(" _ pairs:TblProperties _ ")" { return pairs; }
483
+
484
+ DropDatabase
485
+ = "DROP DATABASE"i _ ife:IfExists? n:Ident (_ ("CASCADE"i / "RESTRICT"i))? {
486
+ return node("DropDatabase", { name:n, ifExists: !!ife });
487
+ }
488
+
489
+ IfExists
490
+ = "IF EXISTS"i _
491
+
492
+ CreateTable
493
+ = "CREATE"i __ ext:("EXTERNAL"i __)? "TABLE"i _ ifn:IfNotExists? name:TableName
494
+ _ "(" _ cols:ColumnDefs _ ")"
495
+ part:PartitionSpec? fmt:RowFormat? loc:LocationSpec? tblProps:TableProperties? asSelect:CreateTableAsSelect?
496
+ {
497
+ return node("CreateTable", {
498
+ external: !!ext, ifNotExists: !!ifn, name,
499
+ columns: cols, partitionedBy: part ?? null, rowFormat: fmt ?? null,
500
+ location: loc ?? null, tableProperties: tblProps ?? null,
501
+ asSelect: asSelect ?? null
502
+ });
503
+ }
504
+
505
+ CreateTableAsSelect
506
+ = _ "AS"i _ q:Query { return q; }
507
+
508
+ ColumnDefs
509
+ = first:ColumnDef rest:(_ "," _ ColumnDef)* { return list(first, rest); }
510
+
511
+ ColumnDef
512
+ = n:Ident _ t:TypeSpec c:ColumnComment? { return { name:n, type:t, comment: c ?? null }; }
513
+
514
+ ColumnComment
515
+ = _ "COMMENT"i __ s:StringLiteral { return s.value; }
516
+
517
+ PartitionSpec
518
+ = _ "PARTITIONED BY"i _ "(" _ cols:ColumnDefs _ ")" { return cols; }
519
+
520
+ RowFormat
521
+ = _ "ROW FORMAT SERDE"i __ s:QuotedString
522
+ _ "WITH SERDEPROPERTIES"i _ "(" _ p:TblProperties _ ")" {
523
+ return { serde: s, serdeProperties: p };
524
+ }
525
+ / _ "ROW FORMAT DELIMITED"i ( (!("LOCATION"i) .) )* { return { delimited: true, raw: text() }; }
526
+
527
+ LocationSpec
528
+ = _ "LOCATION"i __ s:QuotedString { return s; }
529
+
530
+ TableProperties
531
+ = _ "TBLPROPERTIES"i _ "(" _ p:TblProperties _ ")" { return p; }
532
+
533
+ TblProperties
534
+ = first:TblProp rest:(_ "," _ TblProp)* { return Object.fromEntries([first, ...rest.map(r => r[3])]); }
535
+
536
+ TblProp
537
+ = k:QuotedString _ "=" _ v:QuotedString { return [k, v]; }
538
+
539
+ QuotedString
540
+ = s:StringLiteral { return s.value; }
541
+
542
+ DropTable
543
+ = "DROP TABLE"i _ ife:IfExists? n:TableName {
544
+ return node("DropTable", { name:n, ifExists: !!ife });
545
+ }
546
+
547
+ AlterTable
548
+ = "ALTER TABLE"i __ n:TableName __ a:AlterAction {
549
+ return node("AlterTable", { name:n, action:a });
550
+ }
551
+
552
+ AlterAction
553
+ = "ADD PARTITION"i _ "(" _ p:TblProperties _ ")" { return { type:"ADD PARTITION", spec:p }; }
554
+ / "RENAME TO"i __ newName:TableName { return { type:"RENAME TO", name:newName }; }
555
+ / "SET TBLPROPERTIES"i _ "(" _ t:TblProperties _ ")" { return { type:"SET TBLPROPERTIES", props:t }; }
556
+
557
+ CreateView
558
+ = "CREATE OR REPLACE VIEW"i __ n:TableName _ "AS"i _ q:Query {
559
+ return node("CreateView", { name:n, query:q, orReplace:true });
560
+ }
561
+ / "CREATE VIEW"i __ n:TableName _ "AS"i _ q:Query {
562
+ return node("CreateView", { name:n, query:q, orReplace:false });
563
+ }
564
+
565
+ DropView
566
+ = "DROP VIEW"i _ ife:IfExists? n:TableName { return node("DropView", { name:n, ifExists: !!ife }); }
567
+
568
+ // ======================
569
+ // SHOW / DESCRIBE / MSCK
570
+ // ======================
571
+
572
+ ShowStmt
573
+ = "SHOW TABLES"i (_ "IN"i __ db:Ident)? {
574
+ return node("ShowTables", { database: db ?? null });
575
+ }
576
+ / "SHOW DATABASES"i { return node("ShowDatabases", {}); }
577
+ / "SHOW COLUMNS FROM"i __ t:TableName { return node("ShowColumns", { table:t }); }
578
+ / "SHOW PARTITIONS"i __ t:TableName { return node("ShowPartitions", { table:t }); }
579
+ / "SHOW VIEWS"i (_ "IN"i __ db2:Ident)? {
580
+ return node("ShowViews", { database: db2 ?? null });
581
+ }
582
+ / "SHOW CREATE TABLE"i __ t2:TableName { return node("ShowCreateTable", { table:t2 }); }
583
+ / "SHOW CREATE VIEW"i __ v:TableName { return node("ShowCreateView", { view:v }); }
584
+
585
+ DescribeStmt
586
+ = "DESCRIBE"i __ "VIEW"i __ v:TableName { return node("DescribeView", { target:v }); }
587
+ / "DESCRIBE"i __ t:TableName { return node("Describe", { target:t }); }
588
+
589
+ MsckRepair
590
+ = "MSCK REPAIR TABLE"i __ t:TableName { return node("MsckRepair", { table:t }); }
591
+
592
+ // ======================
593
+ // Whitespace & Comments
594
+ // ======================
595
+
596
+ _ = (WS / Comment)*
597
+ __ = (WS / Comment)+
598
+
599
+ WS = [ \t\r\n\f\v\u00A0]
600
+
601
+ Comment
602
+ = LineComment / BlockComment
603
+
604
+ LineComment
605
+ = "--" [^\n\r]*
606
+
607
+ BlockComment
608
+ = "/*" (!"*/" .)* "*/"