eslint-plugin-slonik 1.0.0

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 (35) hide show
  1. package/LICENSE +48 -0
  2. package/README.md +368 -0
  3. package/dist/config.cjs +61 -0
  4. package/dist/config.cjs.map +1 -0
  5. package/dist/config.d.cts +192 -0
  6. package/dist/config.d.mts +192 -0
  7. package/dist/config.d.ts +192 -0
  8. package/dist/config.mjs +59 -0
  9. package/dist/config.mjs.map +1 -0
  10. package/dist/index.cjs +27 -0
  11. package/dist/index.cjs.map +1 -0
  12. package/dist/index.d.cts +319 -0
  13. package/dist/index.d.mts +319 -0
  14. package/dist/index.d.ts +319 -0
  15. package/dist/index.mjs +20 -0
  16. package/dist/index.mjs.map +1 -0
  17. package/dist/shared/eslint-plugin-slonik.1m1xlVmw.d.cts +611 -0
  18. package/dist/shared/eslint-plugin-slonik.1m1xlVmw.d.mts +611 -0
  19. package/dist/shared/eslint-plugin-slonik.1m1xlVmw.d.ts +611 -0
  20. package/dist/shared/eslint-plugin-slonik.BxexVlk1.cjs +1539 -0
  21. package/dist/shared/eslint-plugin-slonik.BxexVlk1.cjs.map +1 -0
  22. package/dist/shared/eslint-plugin-slonik.C0xTyWZ2.mjs +2866 -0
  23. package/dist/shared/eslint-plugin-slonik.C0xTyWZ2.mjs.map +1 -0
  24. package/dist/shared/eslint-plugin-slonik.DbzoLz5_.mjs +1514 -0
  25. package/dist/shared/eslint-plugin-slonik.DbzoLz5_.mjs.map +1 -0
  26. package/dist/shared/eslint-plugin-slonik.rlOTrCdf.cjs +2929 -0
  27. package/dist/shared/eslint-plugin-slonik.rlOTrCdf.cjs.map +1 -0
  28. package/dist/workers/check-sql.worker.cjs +2436 -0
  29. package/dist/workers/check-sql.worker.cjs.map +1 -0
  30. package/dist/workers/check-sql.worker.d.cts +171 -0
  31. package/dist/workers/check-sql.worker.d.mts +171 -0
  32. package/dist/workers/check-sql.worker.d.ts +171 -0
  33. package/dist/workers/check-sql.worker.mjs +2412 -0
  34. package/dist/workers/check-sql.worker.mjs.map +1 -0
  35. package/package.json +103 -0
@@ -0,0 +1,1539 @@
1
+ 'use strict';
2
+
3
+ const checkSql_utils = require('./eslint-plugin-slonik.rlOTrCdf.cjs');
4
+ const utils = require('@typescript-eslint/utils');
5
+ const tsPattern = require('ts-pattern');
6
+ const E = require('fp-ts/lib/Either.js');
7
+ const function_js = require('fp-ts/lib/function.js');
8
+ require('fp-ts/lib/Option.js');
9
+ require('fp-ts/lib/TaskEither.js');
10
+ const J = require('fp-ts/lib/Json.js');
11
+ const ts = require('typescript');
12
+ const path = require('path');
13
+ const fs = require('fs');
14
+ const synckit = require('synckit');
15
+ const node_url = require('node:url');
16
+ const z = require('zod');
17
+ const module$1 = require('module');
18
+
19
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
20
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
21
+
22
+ function _interopNamespaceCompat(e) {
23
+ if (e && typeof e === 'object' && 'default' in e) return e;
24
+ const n = Object.create(null);
25
+ if (e) {
26
+ for (const k in e) {
27
+ n[k] = e[k];
28
+ }
29
+ }
30
+ n.default = e;
31
+ return n;
32
+ }
33
+
34
+ const E__namespace = /*#__PURE__*/_interopNamespaceCompat(E);
35
+ const J__namespace = /*#__PURE__*/_interopNamespaceCompat(J);
36
+ const ts__default = /*#__PURE__*/_interopDefaultCompat(ts);
37
+ const path__default = /*#__PURE__*/_interopDefaultCompat(path);
38
+ const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
39
+ const z__default = /*#__PURE__*/_interopDefaultCompat(z);
40
+
41
+ const PRIMITIVES = {
42
+ string: "string",
43
+ number: "number",
44
+ boolean: "boolean",
45
+ false: "false",
46
+ true: "true",
47
+ null: "null",
48
+ undefined: "undefined",
49
+ any: "any"
50
+ };
51
+ function getResolvedTargetByTypeNode(params) {
52
+ const typeText = params.parser.esTreeNodeToTSNodeMap.get(params.typeNode).getText();
53
+ if (isReservedType(typeText, params.reservedTypes)) {
54
+ return { kind: "type", value: typeText };
55
+ }
56
+ switch (params.typeNode.type) {
57
+ case utils.TSESTree.AST_NODE_TYPES.TSLiteralType:
58
+ return handleLiteralType(params.typeNode);
59
+ case utils.TSESTree.AST_NODE_TYPES.TSUnionType:
60
+ return {
61
+ kind: "union",
62
+ value: params.typeNode.types.map(
63
+ (type) => getResolvedTargetByTypeNode({ ...params, typeNode: type })
64
+ )
65
+ };
66
+ case utils.TSESTree.AST_NODE_TYPES.TSNullKeyword:
67
+ return { kind: "type", value: "null" };
68
+ case utils.TSESTree.AST_NODE_TYPES.TSUndefinedKeyword:
69
+ return { kind: "type", value: "undefined" };
70
+ case utils.TSESTree.AST_NODE_TYPES.TSTypeLiteral:
71
+ return handleTypeLiteral(params.typeNode, params);
72
+ case utils.TSESTree.AST_NODE_TYPES.TSTypeReference:
73
+ return handleTypeReference(params.typeNode, params);
74
+ case utils.TSESTree.AST_NODE_TYPES.TSIntersectionType:
75
+ return handleIntersectionType(params.typeNode, params);
76
+ case utils.TSESTree.AST_NODE_TYPES.TSArrayType:
77
+ return {
78
+ kind: "array",
79
+ value: getResolvedTargetByTypeNode({
80
+ ...params,
81
+ typeNode: params.typeNode.elementType
82
+ })
83
+ };
84
+ default:
85
+ return { kind: "type", value: typeText };
86
+ }
87
+ }
88
+ function isReservedType(typeText, reservedTypes) {
89
+ return reservedTypes.has(typeText) || reservedTypes.has(`${typeText}[]`);
90
+ }
91
+ function handleLiteralType(typeNode) {
92
+ return typeNode.literal.type === utils.TSESTree.AST_NODE_TYPES.Literal ? { kind: "type", value: `'${typeNode.literal.value}'` } : { kind: "type", value: "unknown" };
93
+ }
94
+ function handleTypeLiteral(typeNode, params) {
95
+ const properties = typeNode.members.flatMap((member) => {
96
+ if (member.type !== utils.TSESTree.AST_NODE_TYPES.TSPropertySignature || !member.typeAnnotation) {
97
+ return [];
98
+ }
99
+ const key = extractPropertyKey(member.key);
100
+ if (!key) return [];
101
+ const propertyName = member.optional ? `${key}?` : key;
102
+ const propertyType = getResolvedTargetByTypeNode({
103
+ ...params,
104
+ typeNode: member.typeAnnotation.typeAnnotation
105
+ });
106
+ return [[propertyName, propertyType]];
107
+ });
108
+ return { kind: "object", value: properties };
109
+ }
110
+ function extractPropertyKey(key) {
111
+ switch (key.type) {
112
+ case utils.TSESTree.AST_NODE_TYPES.Identifier:
113
+ return key.name;
114
+ case utils.TSESTree.AST_NODE_TYPES.Literal:
115
+ return String(key.value);
116
+ default:
117
+ return void 0;
118
+ }
119
+ }
120
+ function handleTypeReference(typeNode, params) {
121
+ if (typeNode.typeName.type !== utils.TSESTree.AST_NODE_TYPES.Identifier && typeNode.typeName.type !== utils.TSESTree.AST_NODE_TYPES.TSQualifiedName) {
122
+ return { kind: "type", value: "unknown" };
123
+ }
124
+ const typeNameText = params.parser.esTreeNodeToTSNodeMap.get(typeNode.typeName).getText();
125
+ if (params.reservedTypes.has(typeNameText)) {
126
+ return { kind: "type", value: typeNameText };
127
+ }
128
+ if (typeNameText === "Array" && typeNode.typeArguments?.params[0]) {
129
+ return {
130
+ kind: "array",
131
+ syntax: "type-reference",
132
+ value: getResolvedTargetByTypeNode({
133
+ ...params,
134
+ typeNode: typeNode.typeArguments.params[0]
135
+ })
136
+ };
137
+ }
138
+ const type = params.checker.getTypeFromTypeNode(
139
+ params.parser.esTreeNodeToTSNodeMap.get(typeNode)
140
+ );
141
+ return resolveType(type, { ...params, typeNode });
142
+ }
143
+ function handleIntersectionType(typeNode, params) {
144
+ const allProperties = typeNode.types.flatMap((type) => {
145
+ const resolved = getResolvedTargetByTypeNode({ ...params, typeNode: type });
146
+ return resolved.kind === "object" ? resolved.value : [];
147
+ });
148
+ return { kind: "object", value: Array.from(new Map(allProperties).entries()) };
149
+ }
150
+ function resolveType(type, params) {
151
+ const typeAsString = params.checker.typeToString(type);
152
+ if (params.reservedTypes.has(typeAsString)) {
153
+ return { kind: "type", value: typeAsString };
154
+ }
155
+ if (params.reservedTypes.has(`${typeAsString}[]`)) {
156
+ return { kind: "array", value: { kind: "type", value: typeAsString.replace("[]", "") } };
157
+ }
158
+ const primitive = getPrimitiveType(type, typeAsString);
159
+ if (primitive) return primitive;
160
+ if (type.isLiteral()) {
161
+ return { kind: "type", value: `'${type.value}'` };
162
+ }
163
+ if (type.isUnion()) {
164
+ return handleUnionTypeReference(type, params);
165
+ }
166
+ if (type.isIntersection()) {
167
+ return handleIntersectionTypeReference(type, params);
168
+ }
169
+ if (params.checker.isArrayType(type)) {
170
+ return handleArrayTypeReferenceFromType(type, params);
171
+ }
172
+ return handleObjectType(type, params);
173
+ }
174
+ function getPrimitiveType(type, typeAsString) {
175
+ if (PRIMITIVES[typeAsString]) {
176
+ return { kind: "type", value: PRIMITIVES[typeAsString] };
177
+ }
178
+ const flagMap = {
179
+ [ts__default.TypeFlags.String]: "string",
180
+ [ts__default.TypeFlags.Number]: "number",
181
+ [ts__default.TypeFlags.Boolean]: "boolean",
182
+ [ts__default.TypeFlags.Null]: "null",
183
+ [ts__default.TypeFlags.Undefined]: "undefined",
184
+ [ts__default.TypeFlags.Any]: "any"
185
+ };
186
+ return flagMap[type.flags] ? { kind: "type", value: flagMap[type.flags] } : null;
187
+ }
188
+ function handleUnionTypeReference(type, params) {
189
+ const types = type.types.map((t) => resolveType(t, params));
190
+ const isBooleanUnionWithNull = types.length === 3 && types.some((t) => t.value === "false") && types.some((t) => t.value === "true") && types.some((t) => t.value === "null");
191
+ if (isBooleanUnionWithNull) {
192
+ return {
193
+ kind: "union",
194
+ value: [
195
+ { kind: "type", value: "boolean" },
196
+ { kind: "type", value: "null" }
197
+ ]
198
+ };
199
+ }
200
+ return { kind: "union", value: types };
201
+ }
202
+ function handleIntersectionTypeReference(type, params) {
203
+ const properties = type.types.flatMap((t) => {
204
+ const resolved = resolveType(t, params);
205
+ return resolved.kind === "object" ? resolved.value : [];
206
+ });
207
+ return { kind: "object", value: properties };
208
+ }
209
+ function handleArrayTypeReferenceFromType(type, params) {
210
+ const typeArguments = type.typeArguments;
211
+ const firstArgument = typeArguments?.[0];
212
+ if (firstArgument) {
213
+ const elementType = resolveType(firstArgument, params);
214
+ return { kind: "array", value: elementType };
215
+ }
216
+ return { kind: "array", value: { kind: "type", value: "unknown" } };
217
+ }
218
+ function handleObjectType(type, params) {
219
+ if (!type.symbol) {
220
+ return { kind: "type", value: type.aliasSymbol?.escapedName.toString() ?? "unknown" };
221
+ }
222
+ if (type.symbol.valueDeclaration) {
223
+ const declaration = type.symbol.valueDeclaration;
224
+ const sourceFile = declaration.getSourceFile();
225
+ const filePath = sourceFile.fileName;
226
+ if (!filePath.includes("node_modules")) {
227
+ return extractObjectProperties(type, params);
228
+ }
229
+ return { kind: "type", value: type.symbol.name };
230
+ }
231
+ if (type.flags === ts__default.TypeFlags.Object) {
232
+ return extractObjectProperties(type, params);
233
+ }
234
+ return { kind: "object", value: [] };
235
+ }
236
+ function extractObjectProperties(type, params) {
237
+ const properties = type.getProperties().map((property) => {
238
+ const key = property.escapedName.toString();
239
+ const propType = params.checker.getTypeOfSymbolAtLocation(
240
+ property,
241
+ params.parser.esTreeNodeToTSNodeMap.get(params.typeNode)
242
+ );
243
+ const resolvedType = resolveType(propType, params);
244
+ return [key, resolvedType];
245
+ });
246
+ return { kind: "object", value: properties };
247
+ }
248
+
249
+ function isInEditorEnv() {
250
+ if (process.env.CI) return false;
251
+ if (isInGitHooksOrLintStaged()) return false;
252
+ return !!(process.env.VSCODE_PID || process.env.VSCODE_CWD || process.env.JETBRAINS_IDE || process.env.VIM || process.env.NVIM);
253
+ }
254
+ function isInGitHooksOrLintStaged() {
255
+ return !!(process.env.GIT_PARAMS || process.env.VSCODE_GIT_COMMAND || process.env.npm_lifecycle_script?.startsWith("lint-staged"));
256
+ }
257
+
258
+ const memoized = /* @__PURE__ */ new Map();
259
+ function memoize(params) {
260
+ const { key, value } = params;
261
+ if (memoized.has(key)) {
262
+ return memoized.get(key);
263
+ }
264
+ const result = value();
265
+ memoized.set(key, result);
266
+ return result;
267
+ }
268
+
269
+ function locateNearestPackageJsonDir(filePath) {
270
+ const dir = path__default.dirname(filePath);
271
+ const packageJsonFile = path__default.join(dir, "package.json");
272
+ if (fs__default.existsSync(packageJsonFile)) {
273
+ return dir;
274
+ }
275
+ return locateNearestPackageJsonDir(dir);
276
+ }
277
+
278
+ const TSUtils = {
279
+ isTypeUnion: (typeNode) => {
280
+ return typeNode?.kind === ts__default.SyntaxKind.UnionType;
281
+ },
282
+ isTsUnionType(type) {
283
+ return type.flags === ts__default.TypeFlags.Union;
284
+ },
285
+ isTsTypeReference(type) {
286
+ return TSUtils.isTsObjectType(type) && type.objectFlags === ts__default.ObjectFlags.Reference;
287
+ },
288
+ isTsArrayUnionType(checker, type) {
289
+ if (!TSUtils.isTsTypeReference(type)) {
290
+ return false;
291
+ }
292
+ const firstArgument = checker.getTypeArguments(type)[0];
293
+ if (firstArgument === void 0) {
294
+ return false;
295
+ }
296
+ return TSUtils.isTsUnionType(firstArgument);
297
+ },
298
+ isTsObjectType(type) {
299
+ return type.flags === ts__default.TypeFlags.Object;
300
+ },
301
+ getEnumKind(type) {
302
+ const symbol = type.getSymbol();
303
+ if (!symbol || !(symbol.flags & ts__default.SymbolFlags.Enum)) {
304
+ return void 0;
305
+ }
306
+ const declarations = symbol.getDeclarations();
307
+ if (!declarations) {
308
+ return void 0;
309
+ }
310
+ let hasString = false;
311
+ let hasNumeric = false;
312
+ const stringValues = [];
313
+ for (const declaration of declarations) {
314
+ if (ts__default.isEnumDeclaration(declaration)) {
315
+ for (const member of declaration.members) {
316
+ const initializer = member.initializer;
317
+ if (initializer) {
318
+ if (ts__default.isStringLiteralLike(initializer)) {
319
+ hasString = true;
320
+ stringValues.push(initializer.text);
321
+ }
322
+ if (initializer.kind === ts__default.SyntaxKind.NumericLiteral) {
323
+ hasNumeric = true;
324
+ }
325
+ } else {
326
+ hasNumeric = true;
327
+ }
328
+ }
329
+ }
330
+ }
331
+ if (symbol.flags & ts__default.SymbolFlags.ConstEnum) {
332
+ return { kind: "Const" };
333
+ }
334
+ if (hasString && hasNumeric) {
335
+ return { kind: "Heterogeneous" };
336
+ }
337
+ if (hasString) {
338
+ return { kind: "String", values: stringValues };
339
+ }
340
+ return { kind: "Numeric" };
341
+ }
342
+ };
343
+
344
+ const keywords = [
345
+ "WITH",
346
+ "SELECT",
347
+ "FROM",
348
+ "WHERE",
349
+ "GROUP BY",
350
+ "HAVING",
351
+ "WINDOW",
352
+ "ORDER BY",
353
+ "PARTITION BY",
354
+ "LIMIT",
355
+ "OFFSET",
356
+ "INSERT INTO",
357
+ "VALUES",
358
+ "UPDATE",
359
+ "SET",
360
+ "RETURNING",
361
+ "ON",
362
+ "JOIN",
363
+ "INNER JOIN",
364
+ "LEFT JOIN",
365
+ "RIGHT JOIN",
366
+ "FULL JOIN",
367
+ "FULL OUTER JOIN",
368
+ "CROSS JOIN",
369
+ "WHEN",
370
+ "USING",
371
+ "UNION",
372
+ "UNION ALL",
373
+ "INTERSECT",
374
+ "EXCEPT"
375
+ ];
376
+ const keywordSet = new Set(keywords);
377
+ function isLastQueryContextOneOf(queryText, keywords2) {
378
+ const contextKeywords = getLastQueryContext(queryText);
379
+ const lastKeyword = contextKeywords[contextKeywords.length - 1];
380
+ return keywords2.some((keyword) => keyword === lastKeyword);
381
+ }
382
+ function getLastQueryContext(queryText) {
383
+ const context = getQueryContext(queryText);
384
+ const iterate = (ctx) => {
385
+ const last = ctx[ctx.length - 1];
386
+ if (Array.isArray(last)) {
387
+ return iterate(last);
388
+ }
389
+ return ctx;
390
+ };
391
+ return iterate(context);
392
+ }
393
+ function getQueryContext(queryText) {
394
+ const tokens = removePgComments(queryText).split(/(\s+|\(|\))/).filter((token) => token.trim() !== "");
395
+ let index = 0;
396
+ function parseQuery() {
397
+ const context = [];
398
+ while (index < tokens.length) {
399
+ const token = tokens[index++].toUpperCase();
400
+ if (token === ")") {
401
+ return context;
402
+ }
403
+ if (token === "(") {
404
+ const subquery = parseQuery();
405
+ if (subquery.length > 0) {
406
+ context.push(subquery);
407
+ }
408
+ continue;
409
+ }
410
+ const previousToken = tokens[index - 2]?.toUpperCase();
411
+ const nextToken = tokens[index]?.toUpperCase();
412
+ if (isOneOf(["ORDER", "GROUP", "PARTITION"], token) && nextToken === "BY") {
413
+ index++;
414
+ context.push(`${token} BY`);
415
+ continue;
416
+ }
417
+ if (token === "JOIN") {
418
+ switch (previousToken) {
419
+ case "INNER":
420
+ case "LEFT":
421
+ case "RIGHT":
422
+ case "FULL":
423
+ case "CROSS":
424
+ context.push(`${previousToken} JOIN`);
425
+ break;
426
+ case "OUTER":
427
+ context.push("FULL OUTER JOIN");
428
+ break;
429
+ }
430
+ continue;
431
+ }
432
+ if (keywordSet.has(token)) {
433
+ context.push(token);
434
+ continue;
435
+ }
436
+ }
437
+ return context;
438
+ }
439
+ return parseQuery();
440
+ }
441
+ function removePgComments(query) {
442
+ return query.replace(/--.*(\r?\n|$)|\/\*[\s\S]*?\*\//g, "").trim();
443
+ }
444
+ function isOneOf(values, value) {
445
+ return values.includes(value);
446
+ }
447
+
448
+ const SLONIK_SQL_TOKEN_TYPES = /* @__PURE__ */ new Set([
449
+ // Core SQL tokens from Slonik
450
+ "SqlToken",
451
+ "SqlSqlToken",
452
+ "QuerySqlToken",
453
+ "FragmentSqlToken",
454
+ "SqlFragmentToken",
455
+ "SqlFragment",
456
+ // Return type of sql.fragment
457
+ "ListSqlToken",
458
+ "UnnestSqlToken",
459
+ "IdentifierSqlToken",
460
+ "ArraySqlToken",
461
+ "JsonSqlToken",
462
+ "JsonBinarySqlToken",
463
+ "BinarySqlToken",
464
+ "DateSqlToken",
465
+ "TimestampSqlToken",
466
+ "IntervalSqlToken",
467
+ "UuidSqlToken",
468
+ // Return type of sql.uuid
469
+ // Generic/union types
470
+ "PrimitiveValueExpression",
471
+ "ValueExpression",
472
+ "SqlTokenType"
473
+ ]);
474
+ function isSlonikSqlTokenType(typeStr) {
475
+ if (SLONIK_SQL_TOKEN_TYPES.has(typeStr)) {
476
+ return true;
477
+ }
478
+ for (const tokenType of SLONIK_SQL_TOKEN_TYPES) {
479
+ if (typeStr.includes(tokenType)) {
480
+ return true;
481
+ }
482
+ }
483
+ return false;
484
+ }
485
+ function extractSlonikArrayType(expression) {
486
+ if (expression.type !== "CallExpression") {
487
+ return null;
488
+ }
489
+ const callee = expression.callee;
490
+ if (callee.type !== "MemberExpression") {
491
+ return null;
492
+ }
493
+ if (callee.property.type !== "Identifier" || callee.property.name !== "array") {
494
+ return null;
495
+ }
496
+ const objectName = getMemberExpressionObjectName(callee.object);
497
+ if (objectName !== "sql") {
498
+ return null;
499
+ }
500
+ const typeArg = expression.arguments[1];
501
+ if (!typeArg) {
502
+ return null;
503
+ }
504
+ if (typeArg.type === "Literal" && typeof typeArg.value === "string") {
505
+ return `${typeArg.value}[]`;
506
+ }
507
+ return null;
508
+ }
509
+ function getMemberExpressionObjectName(node) {
510
+ if (node.type === "Identifier") {
511
+ return node.name;
512
+ }
513
+ if (node.type === "MemberExpression" && node.object.type === "ThisExpression" && node.property.type === "Identifier") {
514
+ return node.property.name;
515
+ }
516
+ return null;
517
+ }
518
+ function extractSlonikIdentifier(expression) {
519
+ if (expression.type !== "CallExpression") {
520
+ return null;
521
+ }
522
+ const callee = expression.callee;
523
+ if (callee.type !== "MemberExpression") {
524
+ return null;
525
+ }
526
+ if (callee.property.type !== "Identifier" || callee.property.name !== "identifier") {
527
+ return null;
528
+ }
529
+ const objectName = getMemberExpressionObjectName(callee.object);
530
+ if (objectName !== "sql") {
531
+ return null;
532
+ }
533
+ const partsArg = expression.arguments[0];
534
+ if (!partsArg) {
535
+ return null;
536
+ }
537
+ if (partsArg.type === "ArrayExpression") {
538
+ const parts = [];
539
+ for (const element of partsArg.elements) {
540
+ if (element && element.type === "Literal" && typeof element.value === "string") {
541
+ parts.push(element.value);
542
+ } else {
543
+ return null;
544
+ }
545
+ }
546
+ if (parts.length === 0) {
547
+ return null;
548
+ }
549
+ return parts.map((part) => `"${part}"`).join(".");
550
+ }
551
+ return null;
552
+ }
553
+ function isSlonikJoinCall(expression) {
554
+ if (expression.type !== "CallExpression") {
555
+ return false;
556
+ }
557
+ const callee = expression.callee;
558
+ if (callee.type !== "MemberExpression") {
559
+ return false;
560
+ }
561
+ if (callee.property.type !== "Identifier" || callee.property.name !== "join") {
562
+ return false;
563
+ }
564
+ const objectName = getMemberExpressionObjectName(callee.object);
565
+ return objectName === "sql";
566
+ }
567
+ function extractSlonikFragment(expression) {
568
+ if (expression.type !== "TaggedTemplateExpression") {
569
+ return null;
570
+ }
571
+ const tag = expression.tag;
572
+ if (tag.type !== "MemberExpression") {
573
+ return null;
574
+ }
575
+ if (tag.property.type !== "Identifier" || tag.property.name !== "fragment") {
576
+ return null;
577
+ }
578
+ const objectName = getMemberExpressionObjectName(tag.object);
579
+ if (objectName !== "sql") {
580
+ return null;
581
+ }
582
+ const quasi = expression.quasi;
583
+ let sqlText = "";
584
+ const nestedExpressions = [];
585
+ for (const [i, templateElement] of quasi.quasis.entries()) {
586
+ sqlText += templateElement.value.raw;
587
+ if (!templateElement.tail && quasi.expressions[i]) {
588
+ nestedExpressions.push(quasi.expressions[i]);
589
+ sqlText += `\${__FRAGMENT_EXPR_${nestedExpressions.length - 1}__}`;
590
+ }
591
+ }
592
+ return { sqlText, expressions: nestedExpressions };
593
+ }
594
+ function extractSlonikUnnestTypes(expression) {
595
+ if (expression.type !== "CallExpression") {
596
+ return null;
597
+ }
598
+ const callee = expression.callee;
599
+ if (callee.type !== "MemberExpression") {
600
+ return null;
601
+ }
602
+ if (callee.property.type !== "Identifier" || callee.property.name !== "unnest") {
603
+ return null;
604
+ }
605
+ const objectName = getMemberExpressionObjectName(callee.object);
606
+ if (objectName !== "sql") {
607
+ return null;
608
+ }
609
+ const typeArg = expression.arguments[1];
610
+ if (!typeArg) {
611
+ return null;
612
+ }
613
+ if (typeArg.type === "ArrayExpression") {
614
+ const types = [];
615
+ for (const element of typeArg.elements) {
616
+ if (element && element.type === "Literal" && typeof element.value === "string") {
617
+ types.push(`${element.value}[]`);
618
+ } else {
619
+ return null;
620
+ }
621
+ }
622
+ return types.length > 0 ? types : null;
623
+ }
624
+ return null;
625
+ }
626
+ function mapTemplateLiteralToQueryText(quasi, parser, checker, options, sourceCode) {
627
+ let $idx = 0;
628
+ let $queryText = "";
629
+ const sourcemaps = [];
630
+ for (const [quasiIdx, $quasi] of quasi.quasis.entries()) {
631
+ $queryText += $quasi.value.raw;
632
+ if ($quasi.tail) {
633
+ break;
634
+ }
635
+ const position = $queryText.length;
636
+ const expression = quasi.expressions[quasiIdx];
637
+ const slonikArrayType = extractSlonikArrayType(expression);
638
+ if (slonikArrayType !== null) {
639
+ const placeholder2 = `$${++$idx}::${slonikArrayType}`;
640
+ $queryText += placeholder2;
641
+ sourcemaps.push({
642
+ original: {
643
+ start: expression.range[0] - quasi.range[0] - 2,
644
+ end: expression.range[1] - quasi.range[0],
645
+ text: sourceCode.text.slice(expression.range[0] - 2, expression.range[1] + 1)
646
+ },
647
+ generated: {
648
+ start: position,
649
+ end: position + placeholder2.length,
650
+ text: placeholder2
651
+ },
652
+ offset: 0
653
+ });
654
+ continue;
655
+ }
656
+ const slonikIdentifier = extractSlonikIdentifier(expression);
657
+ if (slonikIdentifier !== null) {
658
+ $queryText += slonikIdentifier;
659
+ sourcemaps.push({
660
+ original: {
661
+ start: expression.range[0] - quasi.range[0] - 2,
662
+ end: expression.range[1] - quasi.range[0],
663
+ text: sourceCode.text.slice(expression.range[0] - 2, expression.range[1] + 1)
664
+ },
665
+ generated: {
666
+ start: position,
667
+ end: position + slonikIdentifier.length,
668
+ text: slonikIdentifier
669
+ },
670
+ offset: 0
671
+ });
672
+ continue;
673
+ }
674
+ if (isSlonikJoinCall(expression)) {
675
+ const placeholder2 = `$${++$idx}`;
676
+ $queryText += placeholder2;
677
+ sourcemaps.push({
678
+ original: {
679
+ start: expression.range[0] - quasi.range[0] - 2,
680
+ end: expression.range[1] - quasi.range[0],
681
+ text: sourceCode.text.slice(expression.range[0] - 2, expression.range[1] + 1)
682
+ },
683
+ generated: {
684
+ start: position,
685
+ end: position + placeholder2.length,
686
+ text: placeholder2
687
+ },
688
+ offset: 0
689
+ });
690
+ continue;
691
+ }
692
+ const slonikUnnestTypes = extractSlonikUnnestTypes(expression);
693
+ if (slonikUnnestTypes !== null) {
694
+ const placeholders = slonikUnnestTypes.map((type) => `$${++$idx}::${type}`);
695
+ const placeholder2 = `unnest(${placeholders.join(", ")})`;
696
+ $queryText += placeholder2;
697
+ sourcemaps.push({
698
+ original: {
699
+ start: expression.range[0] - quasi.range[0] - 2,
700
+ end: expression.range[1] - quasi.range[0],
701
+ text: sourceCode.text.slice(expression.range[0] - 2, expression.range[1] + 1)
702
+ },
703
+ generated: {
704
+ start: position,
705
+ end: position + placeholder2.length,
706
+ text: placeholder2
707
+ },
708
+ offset: 0
709
+ });
710
+ continue;
711
+ }
712
+ const slonikFragment = extractSlonikFragment(expression);
713
+ if (slonikFragment !== null) {
714
+ let fragmentSql = slonikFragment.sqlText;
715
+ for (let i = 0; i < slonikFragment.expressions.length; i++) {
716
+ const nestedExpr = slonikFragment.expressions[i];
717
+ const nestedPgType = function_js.pipe(
718
+ mapExpressionToTsTypeString({ expression: nestedExpr, parser, checker }),
719
+ (params) => getPgTypeFromTsType({ ...params, checker, options })
720
+ );
721
+ let nestedPlaceholder;
722
+ if (E__namespace.isLeft(nestedPgType) || nestedPgType.right === null) {
723
+ nestedPlaceholder = `$${++$idx}`;
724
+ } else if (nestedPgType.right.kind === "literal") {
725
+ nestedPlaceholder = nestedPgType.right.value;
726
+ } else {
727
+ nestedPlaceholder = `$${++$idx}::${nestedPgType.right.cast}`;
728
+ }
729
+ fragmentSql = fragmentSql.replace(`\${__FRAGMENT_EXPR_${i}__}`, nestedPlaceholder);
730
+ }
731
+ $queryText += fragmentSql;
732
+ sourcemaps.push({
733
+ original: {
734
+ start: expression.range[0] - quasi.range[0] - 2,
735
+ end: expression.range[1] - quasi.range[0],
736
+ text: sourceCode.text.slice(expression.range[0] - 2, expression.range[1] + 1)
737
+ },
738
+ generated: {
739
+ start: position,
740
+ end: position + fragmentSql.length,
741
+ text: fragmentSql
742
+ },
743
+ offset: 0
744
+ });
745
+ continue;
746
+ }
747
+ const pgType = function_js.pipe(
748
+ mapExpressionToTsTypeString({ expression, parser, checker }),
749
+ (params) => getPgTypeFromTsType({ ...params, checker, options })
750
+ );
751
+ if (E__namespace.isLeft(pgType)) {
752
+ return E__namespace.left(checkSql_utils.InvalidQueryError.of(pgType.left, expression));
753
+ }
754
+ const pgTypeValue = pgType.right;
755
+ if (pgTypeValue === null) {
756
+ const placeholder2 = `$${++$idx}`;
757
+ $queryText += placeholder2;
758
+ sourcemaps.push({
759
+ original: {
760
+ text: sourceCode.text.slice(expression.range[0] - 2, expression.range[1] + 1),
761
+ start: expression.range[0] - quasi.range[0] - 2,
762
+ end: expression.range[1] - quasi.range[0] + 1
763
+ },
764
+ generated: {
765
+ text: placeholder2,
766
+ start: position,
767
+ end: position + placeholder2.length
768
+ },
769
+ offset: 0
770
+ });
771
+ continue;
772
+ }
773
+ if (pgTypeValue.kind === "literal") {
774
+ const placeholder2 = pgTypeValue.value;
775
+ $queryText += placeholder2;
776
+ sourcemaps.push({
777
+ original: {
778
+ start: expression.range[0] - quasi.range[0] - 2,
779
+ end: expression.range[1] - quasi.range[0] + 1,
780
+ text: sourceCode.text.slice(expression.range[0] - 2, expression.range[1] + 1)
781
+ },
782
+ generated: {
783
+ start: position,
784
+ end: position + placeholder2.length,
785
+ text: placeholder2
786
+ },
787
+ offset: 0
788
+ });
789
+ continue;
790
+ }
791
+ const escapePgValue = (text) => text.replace(/'/g, "''");
792
+ if (pgTypeValue.kind === "one-of" && $queryText.trimEnd().endsWith("=") && isLastQueryContextOneOf($queryText, ["SELECT", "ON", "WHERE", "WHEN", "HAVING", "RETURNING"])) {
793
+ const textFromEquals = $queryText.slice($queryText.lastIndexOf("="));
794
+ const placeholder2 = `IN (${pgTypeValue.types.map((t) => `'${escapePgValue(t)}'`).join(", ")})`;
795
+ const expressionText = sourceCode.text.slice(
796
+ expression.range[0] - 2,
797
+ expression.range[1] + 1
798
+ );
799
+ $queryText = $queryText.replace(/(=)\s*$/, "");
800
+ $queryText += placeholder2;
801
+ sourcemaps.push({
802
+ original: {
803
+ start: expression.range[0] - quasi.range[0] - 2 - textFromEquals.length,
804
+ end: expression.range[1] - quasi.range[0] + 2 - textFromEquals.length,
805
+ text: `${textFromEquals}${expressionText}`
806
+ },
807
+ generated: {
808
+ start: position - textFromEquals.length + 1,
809
+ end: position + placeholder2.length - textFromEquals.length,
810
+ text: placeholder2
811
+ },
812
+ offset: textFromEquals.length
813
+ });
814
+ continue;
815
+ }
816
+ const placeholder = `$${++$idx}::${pgTypeValue.cast}`;
817
+ $queryText += placeholder;
818
+ sourcemaps.push({
819
+ original: {
820
+ start: expression.range[0] - quasi.range[0] - 2,
821
+ end: expression.range[1] - quasi.range[0],
822
+ text: sourceCode.text.slice(expression.range[0] - 2, expression.range[1] + 1)
823
+ },
824
+ generated: {
825
+ start: position,
826
+ end: position + placeholder.length,
827
+ text: placeholder
828
+ },
829
+ offset: 0
830
+ });
831
+ }
832
+ return E__namespace.right({ text: $queryText, sourcemaps });
833
+ }
834
+ function mapExpressionToTsTypeString(params) {
835
+ const tsNode = params.parser.esTreeNodeToTSNodeMap.get(params.expression);
836
+ const tsType = params.checker.getTypeAtLocation(tsNode);
837
+ return {
838
+ node: tsNode,
839
+ type: tsType
840
+ };
841
+ }
842
+ const tsTypeToPgTypeMap = {
843
+ number: "int",
844
+ string: "text",
845
+ boolean: "boolean",
846
+ bigint: "bigint",
847
+ any: "text",
848
+ unknown: "text"
849
+ };
850
+ const tsFlagToPgTypeMap = {
851
+ [ts__default.TypeFlags.String]: "text",
852
+ [ts__default.TypeFlags.Number]: "int",
853
+ [ts__default.TypeFlags.Boolean]: "boolean",
854
+ [ts__default.TypeFlags.BigInt]: "bigint",
855
+ [ts__default.TypeFlags.NumberLiteral]: "int",
856
+ [ts__default.TypeFlags.StringLiteral]: "text",
857
+ [ts__default.TypeFlags.BooleanLiteral]: "boolean",
858
+ [ts__default.TypeFlags.BigIntLiteral]: "bigint"
859
+ };
860
+ function getPgTypeFromTsTypeUnion(params) {
861
+ const { types, checker, options } = params;
862
+ const nonNullTypes = types.filter((t) => (t.flags & ts__default.TypeFlags.Null) === 0);
863
+ if (nonNullTypes.length === 0) {
864
+ return E__namespace.right(null);
865
+ }
866
+ const hasSlonikToken = nonNullTypes.some((t) => {
867
+ const typeStr = checker.typeToString(t);
868
+ return isSlonikSqlTokenType(typeStr);
869
+ });
870
+ if (hasSlonikToken) {
871
+ return E__namespace.right(null);
872
+ }
873
+ const isStringLiterals = nonNullTypes.every((t) => t.flags & ts__default.TypeFlags.StringLiteral);
874
+ if (isStringLiterals) {
875
+ return E__namespace.right({
876
+ kind: "one-of",
877
+ types: nonNullTypes.map((t) => t.value),
878
+ cast: "text"
879
+ });
880
+ }
881
+ const results = nonNullTypes.map((t) => checkType({ checker, type: t, options }));
882
+ const strategies = [];
883
+ for (const result of results) {
884
+ if (E__namespace.isLeft(result)) {
885
+ return result;
886
+ }
887
+ if (result.right !== null) {
888
+ strategies.push(result.right);
889
+ }
890
+ }
891
+ if (strategies.length === 0) {
892
+ const typesStr = nonNullTypes.map((t) => checker.typeToString(t)).join(", ");
893
+ return E__namespace.left(`No PostgreSQL type could be inferred for the union members: ${typesStr}`);
894
+ }
895
+ const firstStrategy = strategies[0];
896
+ const mixedTypes = [firstStrategy.cast];
897
+ for (let i = 1; i < strategies.length; i++) {
898
+ const strategy = strategies[i];
899
+ if (strategy.cast !== firstStrategy.cast) {
900
+ mixedTypes.push(strategy.cast);
901
+ }
902
+ }
903
+ if (mixedTypes.length > 1) {
904
+ return E__namespace.left(
905
+ `Union types must result in the same PostgreSQL type (found ${mixedTypes.join(", ")})`
906
+ );
907
+ }
908
+ return E__namespace.right(firstStrategy);
909
+ }
910
+ function getPgTypeFromTsType(params) {
911
+ const { checker, node, type, options } = params;
912
+ const typeStr = checker.typeToString(type);
913
+ if (isSlonikSqlTokenType(typeStr)) {
914
+ return E__namespace.right(null);
915
+ }
916
+ if (node.kind === ts__default.SyntaxKind.ConditionalExpression) {
917
+ const trueType = checker.getTypeAtLocation(node.whenTrue);
918
+ const falseType = checker.getTypeAtLocation(node.whenFalse);
919
+ const trueTypeStr = checker.typeToString(trueType);
920
+ const falseTypeStr = checker.typeToString(falseType);
921
+ if (isSlonikSqlTokenType(trueTypeStr) || isSlonikSqlTokenType(falseTypeStr)) {
922
+ return E__namespace.right(null);
923
+ }
924
+ const whenTrue = checkType({
925
+ checker,
926
+ type: trueType,
927
+ options
928
+ });
929
+ const whenFalse = checkType({
930
+ checker,
931
+ type: falseType,
932
+ options
933
+ });
934
+ if (E__namespace.isLeft(whenTrue)) {
935
+ return whenTrue;
936
+ }
937
+ if (E__namespace.isLeft(whenFalse)) {
938
+ return whenFalse;
939
+ }
940
+ const trueStrategy = whenTrue.right;
941
+ const falseStrategy = whenFalse.right;
942
+ if (trueStrategy === null && falseStrategy === null) {
943
+ return E__namespace.right(null);
944
+ }
945
+ if (trueStrategy !== null && falseStrategy !== null && trueStrategy.cast !== falseStrategy.cast) {
946
+ return E__namespace.left(
947
+ `Conditional expression must have the same type (true = ${trueStrategy.cast}, false = ${falseStrategy.cast})`
948
+ );
949
+ }
950
+ const strategy = trueStrategy ?? falseStrategy;
951
+ if (strategy === null) {
952
+ return E__namespace.right(null);
953
+ }
954
+ return E__namespace.right({ kind: "cast", cast: strategy.cast });
955
+ }
956
+ return checkType({ checker, type, options });
957
+ }
958
+ function checkType(params) {
959
+ const { checker, type, options } = params;
960
+ if (type.flags & ts__default.TypeFlags.Null) {
961
+ return E__namespace.right(null);
962
+ }
963
+ const typeStr = checker.typeToString(type);
964
+ if (isSlonikSqlTokenType(typeStr)) {
965
+ return E__namespace.right(null);
966
+ }
967
+ const singularType = typeStr.replace(/\[\]$/, "");
968
+ const isArray = typeStr !== singularType;
969
+ const singularPgType = tsTypeToPgTypeMap[singularType];
970
+ if (singularPgType) {
971
+ return E__namespace.right({ kind: "cast", cast: isArray ? `${singularPgType}[]` : singularPgType });
972
+ }
973
+ const typesWithOverrides = { ...checkSql_utils.defaultTypeMapping, ...options.overrides?.types };
974
+ const override = Object.entries(typesWithOverrides).find(
975
+ ([, tsType]) => checkSql_utils.doesMatchPattern({
976
+ pattern: typeof tsType === "string" ? tsType : tsType.parameter,
977
+ text: singularType
978
+ })
979
+ );
980
+ if (override) {
981
+ const [pgType] = override;
982
+ return E__namespace.right({ kind: "cast", cast: isArray ? `${pgType}[]` : pgType });
983
+ }
984
+ const enumType = TSUtils.getEnumKind(type);
985
+ if (enumType) {
986
+ switch (enumType.kind) {
987
+ case "Const":
988
+ case "Numeric":
989
+ return E__namespace.right({ kind: "cast", cast: "int" });
990
+ case "String":
991
+ return E__namespace.right({ kind: "one-of", types: enumType.values, cast: "text" });
992
+ case "Heterogeneous":
993
+ return E__namespace.left("Heterogeneous enums are not supported");
994
+ }
995
+ }
996
+ if (checker.isArrayType(type)) {
997
+ const elementType = type.typeArguments?.[0];
998
+ if (elementType) {
999
+ return function_js.pipe(
1000
+ checkType({ checker, type: elementType, options }),
1001
+ E__namespace.map(
1002
+ (pgType) => pgType === null ? null : { kind: "cast", cast: `${pgType.cast}[]` }
1003
+ )
1004
+ );
1005
+ }
1006
+ }
1007
+ if (type.isStringLiteral()) {
1008
+ return E__namespace.right({ kind: "literal", value: `'${type.value}'`, cast: "text" });
1009
+ }
1010
+ if (type.isNumberLiteral()) {
1011
+ return E__namespace.right({ kind: "literal", value: `${type.value}`, cast: "int" });
1012
+ }
1013
+ if (type.isUnion()) {
1014
+ return function_js.pipe(
1015
+ getPgTypeFromTsTypeUnion({ types: type.types, checker, options }),
1016
+ E__namespace.chain(
1017
+ (pgType) => pgType === null ? E__namespace.left("Unsupported union type (only null)") : E__namespace.right(pgType)
1018
+ )
1019
+ );
1020
+ }
1021
+ if (type.flags in tsFlagToPgTypeMap) {
1022
+ const pgType = tsFlagToPgTypeMap[type.flags];
1023
+ return E__namespace.right({ kind: "cast", cast: isArray ? `${pgType}[]` : pgType });
1024
+ }
1025
+ return E__namespace.left(checkSql_utils.normalizeIndent`
1026
+ The type "${typeStr}" has no corresponding PostgreSQL type.
1027
+ Please add it manually using the "overrides.types" option:
1028
+
1029
+ \`\`\`ts
1030
+ {
1031
+ "connections": {
1032
+ ...,
1033
+ "overrides": {
1034
+ "types": {
1035
+ "PG TYPE (e.g. 'date')": "${typeStr}"
1036
+ }
1037
+ }
1038
+ }
1039
+ }
1040
+ \`\`\`
1041
+
1042
+ Read docs - https://github.com/gajus/eslint-plugin-slonik#type-override-reference
1043
+ `);
1044
+ }
1045
+
1046
+ const distDir = node_url.fileURLToPath(new URL("../../dist", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/eslint-plugin-slonik.BxexVlk1.cjs', document.baseURI).href))));
1047
+ function defineWorker(params) {
1048
+ return synckit.createSyncFn(path__default.join(distDir, `./workers/${params.name}.worker.mjs`), {
1049
+ tsRunner: "tsx",
1050
+ timeout: params.timeout
1051
+ });
1052
+ }
1053
+ const workers = {
1054
+ generateSync: defineWorker({ name: "check-sql", timeout: 1e3 * 60 * 1 })
1055
+ };
1056
+
1057
+ const zStringOrRegex = z__default.union([z__default.string(), z__default.object({ regex: z__default.string() })]);
1058
+ const zBaseTarget = z__default.object({
1059
+ /**
1060
+ * Transform the end result of the type.
1061
+ *
1062
+ * For example:
1063
+ * - `"{type}[]"` will transform the type to an array
1064
+ * - `["colname", "x_colname"]` will replace `colname` with `x_colname` in the type.
1065
+ * - `["{type}[]", ["colname", x_colname"]]` will do both
1066
+ */
1067
+ transform: z__default.union([z__default.string(), z__default.array(z__default.union([z__default.string(), z__default.tuple([z__default.string(), z__default.string()])]))]).optional(),
1068
+ /**
1069
+ * Transform the (column) field key. Can be one of the following:
1070
+ * - `"snake"` - `userId` → `user_id`
1071
+ * - `"camel"` - `user_id` → `userId`
1072
+ * - `"pascal"` - `user_id` → `UserId`
1073
+ * - `"screaming snake"` - `user_id` → `USER_ID`
1074
+ */
1075
+ fieldTransform: z__default.enum(["snake", "pascal", "camel", "screaming snake"]).optional(),
1076
+ /**
1077
+ * Whether or not to skip type annotation.
1078
+ */
1079
+ skipTypeAnnotations: z__default.boolean().optional()
1080
+ });
1081
+ const zWrapperTarget = z__default.object({ wrapper: zStringOrRegex, maxDepth: z__default.number().optional() }).merge(zBaseTarget);
1082
+ const zTagTarget = z__default.object({ tag: zStringOrRegex }).merge(zBaseTarget);
1083
+ const zOverrideTypeResolver = z__default.union([
1084
+ z__default.string(),
1085
+ z__default.object({ parameter: zStringOrRegex, return: z__default.string() })
1086
+ ]);
1087
+ const zBaseSchema = z__default.object({
1088
+ targets: z__default.union([zWrapperTarget, zTagTarget]).array(),
1089
+ /**
1090
+ * Whether or not keep the connection alive. Change it only if you know what you're doing.
1091
+ */
1092
+ keepAlive: z__default.boolean().optional(),
1093
+ /**
1094
+ * Override defaults
1095
+ */
1096
+ overrides: z__default.object({
1097
+ types: z__default.union([
1098
+ z__default.record(z__default.enum(checkSql_utils.objectKeysNonEmpty(checkSql_utils.defaultTypeMapping)), zOverrideTypeResolver),
1099
+ z__default.record(z__default.string(), zOverrideTypeResolver)
1100
+ ]),
1101
+ columns: z__default.record(z__default.string(), z__default.string())
1102
+ }).partial().optional(),
1103
+ /**
1104
+ * Use `undefined` instead of `null` when the value is nullable.
1105
+ */
1106
+ nullAsUndefined: z__default.boolean().optional(),
1107
+ /**
1108
+ * Mark the property as optional when the value is nullable.
1109
+ */
1110
+ nullAsOptional: z__default.boolean().optional(),
1111
+ /**
1112
+ * Specifies whether to infer literals and their types.
1113
+ * Can be a boolean or an array of specific types to infer.
1114
+ *
1115
+ * By default, it will infer all literals.
1116
+ */
1117
+ inferLiterals: z__default.union([z__default.boolean(), z__default.enum(["number", "string", "boolean"]).array()]).optional()
1118
+ });
1119
+ const zConnectionMigration = z__default.object({
1120
+ /**
1121
+ * The path where the migration files are located.
1122
+ */
1123
+ migrationsDir: z__default.string(),
1124
+ /**
1125
+ * THIS IS NOT THE PRODUCTION DATABASE.
1126
+ *
1127
+ * A connection url to the database.
1128
+ * This is required since in order to run the migrations, a connection to postgres is required.
1129
+ * Will be used only to create and drop the shadow database (see `databaseName`).
1130
+ */
1131
+ connectionUrl: z__default.string().optional(),
1132
+ /**
1133
+ * The name of the shadow database that will be created from the migration files.
1134
+ */
1135
+ databaseName: z__default.string().optional(),
1136
+ /**
1137
+ * Whether or not should refresh the shadow database when the migration files change.
1138
+ */
1139
+ watchMode: z__default.boolean().optional()
1140
+ });
1141
+ const zConnectionUrl = z__default.object({
1142
+ /**
1143
+ * The connection url to the database
1144
+ */
1145
+ databaseUrl: z__default.string()
1146
+ });
1147
+ const zRuleOptionConnection = z__default.union([
1148
+ zBaseSchema.merge(zConnectionMigration),
1149
+ zBaseSchema.merge(zConnectionUrl)
1150
+ ]);
1151
+ const zConfig = z__default.object({
1152
+ connections: z__default.union([z__default.array(zRuleOptionConnection), zRuleOptionConnection])
1153
+ });
1154
+ const UserConfigFile = z__default.object({
1155
+ useConfigFile: z__default.boolean()
1156
+ });
1157
+ const Options = z__default.union([zConfig, UserConfigFile]);
1158
+ const RuleOptions = z__default.array(Options).min(1).max(1);
1159
+ const defaultInferLiteralOptions = ["string"];
1160
+
1161
+ function getConfigFromFileWithContext(params) {
1162
+ const options = params.context.options[0];
1163
+ if (!isConfigFileRuleOptions(options)) {
1164
+ return options;
1165
+ }
1166
+ return function_js.pipe(
1167
+ getConfigFromFile(params.projectDir),
1168
+ E__namespace.getOrElseW((message) => {
1169
+ throw new Error(`eslint-plugin-slonik: ${message}`);
1170
+ })
1171
+ );
1172
+ }
1173
+ function getConfigFromFile(projectDir) {
1174
+ try {
1175
+ const configFilePath = path__default.join(projectDir, "slonik.config.ts");
1176
+ const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/eslint-plugin-slonik.BxexVlk1.cjs', document.baseURI).href)));
1177
+ const rawConfig = require$1(`tsx/cjs/api`).require(configFilePath, configFilePath).default;
1178
+ if (rawConfig === void 0) {
1179
+ throw new checkSql_utils.InvalidConfigError(`slonik.config.ts must export a default value`);
1180
+ }
1181
+ const config = zConfig.safeParse(rawConfig);
1182
+ if (!config.success) {
1183
+ throw new checkSql_utils.InvalidConfigError(`slonik.config.ts is invalid: ${config.error.message}`);
1184
+ }
1185
+ return E__namespace.right(config.data);
1186
+ } catch (error) {
1187
+ return E__namespace.left(`${error}`);
1188
+ }
1189
+ }
1190
+ function isConfigFileRuleOptions(options) {
1191
+ return "useConfigFile" in options;
1192
+ }
1193
+ function defineConfig(config) {
1194
+ return config;
1195
+ }
1196
+
1197
+ const messages = {
1198
+ typeInferenceFailed: "Type inference failed {{error}}",
1199
+ error: "{{error}}",
1200
+ invalidQuery: "Invalid Query: {{error}}",
1201
+ missingTypeAnnotations: "Query is missing type annotation\n Fix with: {{fix}}",
1202
+ incorrectTypeAnnotations: `Query has incorrect type annotation.
1203
+ Expected: {{expected}}
1204
+ Actual: {{actual}}`,
1205
+ invalidTypeAnnotations: `Query has invalid type annotation (SafeQL does not support it. If you think it should, please open an issue)`
1206
+ };
1207
+ function check(params) {
1208
+ const connections = Array.isArray(params.config.connections) ? params.config.connections : [params.config.connections];
1209
+ for (const connection of connections) {
1210
+ for (const target of connection.targets) {
1211
+ checkConnection({ ...params, connection, target });
1212
+ }
1213
+ }
1214
+ }
1215
+ function isTagMemberValid(expr) {
1216
+ if (checkSql_utils.isIdentifier(expr.tag)) {
1217
+ return true;
1218
+ }
1219
+ if (checkSql_utils.isMemberExpression(expr.tag) && checkSql_utils.isIdentifier(expr.tag.property)) {
1220
+ return true;
1221
+ }
1222
+ return false;
1223
+ }
1224
+ function checkConnection(params) {
1225
+ if ("tag" in params.target) {
1226
+ return checkConnectionByTagExpression({ ...params, target: params.target });
1227
+ }
1228
+ if ("wrapper" in params.target) {
1229
+ return checkConnectionByWrapperExpression({ ...params, target: params.target });
1230
+ }
1231
+ return tsPattern.match(params.target).exhaustive();
1232
+ }
1233
+ const generateSyncE = function_js.flow(
1234
+ workers.generateSync,
1235
+ E__namespace.chain(J__namespace.parse),
1236
+ E__namespace.chainW((parsed) => parsed),
1237
+ E__namespace.mapLeft((error) => error)
1238
+ );
1239
+ let fatalError;
1240
+ function reportCheck(params) {
1241
+ const { context, tag, connection, target, projectDir, typeParameter, baseNode } = params;
1242
+ if (fatalError !== void 0) {
1243
+ const hint = isInEditorEnv() ? "If you think this is a bug, please open an issue. If not, please try to fix the error and restart ESLint." : "If you think this is a bug, please open an issue.";
1244
+ return checkSql_utils.reportBaseError({ context, error: fatalError, tag, hint });
1245
+ }
1246
+ const nullAsOptional = connection.nullAsOptional ?? false;
1247
+ const nullAsUndefined = connection.nullAsUndefined ?? false;
1248
+ return function_js.pipe(
1249
+ E__namespace.Do,
1250
+ E__namespace.bind("parser", () => {
1251
+ return hasParserServicesWithTypeInformation(context.sourceCode.parserServices) ? E__namespace.right(context.sourceCode.parserServices) : E__namespace.left(new checkSql_utils.InvalidConfigError("Parser services are not available"));
1252
+ }),
1253
+ E__namespace.bind("checker", ({ parser }) => {
1254
+ return !parser.program ? E__namespace.left(new checkSql_utils.InvalidConfigError("Type checker is not available")) : E__namespace.right(parser.program.getTypeChecker());
1255
+ }),
1256
+ E__namespace.bindW(
1257
+ "query",
1258
+ ({ parser, checker }) => mapTemplateLiteralToQueryText(
1259
+ tag.quasi,
1260
+ parser,
1261
+ checker,
1262
+ params.connection,
1263
+ params.context.sourceCode
1264
+ )
1265
+ ),
1266
+ E__namespace.bindW("result", ({ query }) => {
1267
+ return generateSyncE({ query, connection, target, projectDir });
1268
+ }),
1269
+ E__namespace.fold(
1270
+ (error) => {
1271
+ return tsPattern.match(error).with({ _tag: "InvalidConfigError" }, (error2) => {
1272
+ return checkSql_utils.reportInvalidConfig({ context, error: error2, tag });
1273
+ }).with({ _tag: "DuplicateColumnsError" }, (error2) => {
1274
+ return checkSql_utils.reportDuplicateColumns({ context, error: error2, tag });
1275
+ }).with({ _tag: "PostgresError" }, (error2) => {
1276
+ return checkSql_utils.reportPostgresError({ context, error: error2, tag });
1277
+ }).with({ _tag: "InvalidQueryError" }, (error2) => {
1278
+ return checkSql_utils.reportInvalidQueryError({ context, error: error2 });
1279
+ }).with(
1280
+ { _tag: "InvalidMigrationError" },
1281
+ { _tag: "InvalidMigrationsPathError" },
1282
+ { _tag: "DatabaseInitializationError" },
1283
+ { _tag: "InternalError" },
1284
+ (error2) => {
1285
+ if (params.connection.keepAlive === true) {
1286
+ fatalError = error2;
1287
+ }
1288
+ return checkSql_utils.reportBaseError({ context, error: error2, tag });
1289
+ }
1290
+ ).exhaustive();
1291
+ },
1292
+ ({ result, checker, parser }) => {
1293
+ const shouldSkipTypeAnnotations = target.skipTypeAnnotations === true;
1294
+ if (shouldSkipTypeAnnotations) {
1295
+ return;
1296
+ }
1297
+ const isMissingTypeAnnotations = typeParameter === void 0;
1298
+ if (isMissingTypeAnnotations) {
1299
+ if (result.output === null) {
1300
+ return;
1301
+ }
1302
+ return checkSql_utils.reportMissingTypeAnnotations({
1303
+ tag,
1304
+ context,
1305
+ baseNode,
1306
+ actual: checkSql_utils.getFinalResolvedTargetString({
1307
+ target: result.output,
1308
+ nullAsOptional: nullAsOptional ?? false,
1309
+ nullAsUndefined: nullAsUndefined ?? false,
1310
+ transform: target.transform,
1311
+ inferLiterals: connection.inferLiterals ?? defaultInferLiteralOptions
1312
+ })
1313
+ });
1314
+ }
1315
+ const reservedTypes = memoize({
1316
+ key: `reserved-types:${JSON.stringify(connection.overrides)}`,
1317
+ value: () => {
1318
+ const types = /* @__PURE__ */ new Set();
1319
+ for (const value of Object.values(connection.overrides?.types ?? {})) {
1320
+ types.add(typeof value === "string" ? value : value.return);
1321
+ }
1322
+ for (const columnType of Object.values(connection.overrides?.columns ?? {})) {
1323
+ types.add(columnType);
1324
+ }
1325
+ return types;
1326
+ }
1327
+ });
1328
+ const typeAnnotationState = getTypeAnnotationState({
1329
+ generated: result.output,
1330
+ typeParameter,
1331
+ transform: target.transform,
1332
+ checker,
1333
+ parser,
1334
+ reservedTypes,
1335
+ nullAsOptional,
1336
+ nullAsUndefined,
1337
+ inferLiterals: connection.inferLiterals ?? defaultInferLiteralOptions
1338
+ });
1339
+ if (typeAnnotationState === "INVALID") {
1340
+ return checkSql_utils.reportInvalidTypeAnnotations({
1341
+ context,
1342
+ typeParameter
1343
+ });
1344
+ }
1345
+ if (!typeAnnotationState.isEqual) {
1346
+ return checkSql_utils.reportIncorrectTypeAnnotations({
1347
+ context,
1348
+ typeParameter,
1349
+ expected: checkSql_utils.fmap(
1350
+ typeAnnotationState.expected,
1351
+ (expected) => checkSql_utils.getResolvedTargetString({
1352
+ target: expected,
1353
+ nullAsOptional: false,
1354
+ nullAsUndefined: false,
1355
+ inferLiterals: params.connection.inferLiterals ?? defaultInferLiteralOptions
1356
+ })
1357
+ ),
1358
+ actual: checkSql_utils.fmap(
1359
+ result.output,
1360
+ (output) => checkSql_utils.getFinalResolvedTargetString({
1361
+ target: output,
1362
+ nullAsOptional: connection.nullAsOptional ?? false,
1363
+ nullAsUndefined: connection.nullAsUndefined ?? false,
1364
+ transform: target.transform,
1365
+ inferLiterals: connection.inferLiterals ?? defaultInferLiteralOptions
1366
+ })
1367
+ )
1368
+ });
1369
+ }
1370
+ }
1371
+ )
1372
+ );
1373
+ }
1374
+ function hasParserServicesWithTypeInformation(parser) {
1375
+ return parser !== void 0 && parser.program !== null;
1376
+ }
1377
+ function checkConnectionByTagExpression(params) {
1378
+ const { context, tag, projectDir, connection, target } = params;
1379
+ const tagAsText = context.sourceCode.getText(tag.tag).replace(/^this\./, "");
1380
+ if (checkSql_utils.doesMatchPattern({ pattern: target.tag, text: tagAsText })) {
1381
+ return reportCheck({
1382
+ context,
1383
+ tag,
1384
+ connection,
1385
+ target,
1386
+ projectDir,
1387
+ baseNode: tag.tag,
1388
+ typeParameter: tag.typeArguments
1389
+ });
1390
+ }
1391
+ }
1392
+ function getValidParentUntilDepth(node, depth) {
1393
+ if (node.type === "CallExpression" && node.callee.type === "MemberExpression") {
1394
+ return node;
1395
+ }
1396
+ if (depth > 0 && node.parent) {
1397
+ return getValidParentUntilDepth(node.parent, depth - 1);
1398
+ }
1399
+ return null;
1400
+ }
1401
+ function checkConnectionByWrapperExpression(params) {
1402
+ const { context, tag, projectDir, connection, target } = params;
1403
+ if (!isTagMemberValid(tag)) {
1404
+ return;
1405
+ }
1406
+ const wrapperNode = getValidParentUntilDepth(tag.parent, target.maxDepth ?? 0);
1407
+ if (wrapperNode === null) {
1408
+ return;
1409
+ }
1410
+ const calleeAsText = context.sourceCode.getText(wrapperNode.callee).replace(/^this\./, "");
1411
+ if (checkSql_utils.doesMatchPattern({ pattern: target.wrapper, text: calleeAsText })) {
1412
+ return reportCheck({
1413
+ context,
1414
+ tag,
1415
+ connection,
1416
+ target,
1417
+ projectDir,
1418
+ baseNode: wrapperNode.callee,
1419
+ typeParameter: wrapperNode.typeArguments
1420
+ });
1421
+ }
1422
+ }
1423
+ function getTypeAnnotationState({
1424
+ generated,
1425
+ typeParameter,
1426
+ transform,
1427
+ parser,
1428
+ checker,
1429
+ reservedTypes,
1430
+ nullAsOptional,
1431
+ nullAsUndefined,
1432
+ inferLiterals
1433
+ }) {
1434
+ if (typeParameter.params.length !== 1) {
1435
+ return "INVALID";
1436
+ }
1437
+ const typeNode = typeParameter.params[0];
1438
+ const expected = getResolvedTargetByTypeNode({
1439
+ checker,
1440
+ parser,
1441
+ typeNode,
1442
+ reservedTypes
1443
+ });
1444
+ return getResolvedTargetsEquality({
1445
+ expected,
1446
+ generated,
1447
+ nullAsOptional,
1448
+ nullAsUndefined,
1449
+ inferLiterals,
1450
+ transform
1451
+ });
1452
+ }
1453
+ function getResolvedTargetsEquality(params) {
1454
+ if (params.expected === null && params.generated === null) {
1455
+ return {
1456
+ isEqual: true,
1457
+ expected: params.expected,
1458
+ generated: params.generated
1459
+ };
1460
+ }
1461
+ if (params.expected === null || params.generated === null) {
1462
+ return {
1463
+ isEqual: false,
1464
+ expected: params.expected,
1465
+ generated: params.generated
1466
+ };
1467
+ }
1468
+ let expectedString = checkSql_utils.getResolvedTargetComparableString({
1469
+ target: params.expected,
1470
+ nullAsOptional: false,
1471
+ nullAsUndefined: false,
1472
+ inferLiterals: params.inferLiterals
1473
+ });
1474
+ let generatedString = checkSql_utils.getResolvedTargetComparableString({
1475
+ target: params.generated,
1476
+ nullAsOptional: params.nullAsOptional,
1477
+ nullAsUndefined: params.nullAsUndefined,
1478
+ inferLiterals: params.inferLiterals
1479
+ });
1480
+ if (expectedString === null || generatedString === null) {
1481
+ return {
1482
+ isEqual: false,
1483
+ expected: params.expected,
1484
+ generated: params.generated
1485
+ };
1486
+ }
1487
+ expectedString = expectedString.replace(/'/g, '"');
1488
+ generatedString = generatedString.replace(/'/g, '"');
1489
+ expectedString = expectedString.split(", ").sort().join(", ");
1490
+ generatedString = generatedString.split(", ").sort().join(", ");
1491
+ if (params.transform !== void 0) {
1492
+ generatedString = checkSql_utils.transformTypes(generatedString, params.transform);
1493
+ }
1494
+ return {
1495
+ isEqual: expectedString === generatedString,
1496
+ expected: params.expected,
1497
+ generated: params.generated
1498
+ };
1499
+ }
1500
+ const createRule = utils.ESLintUtils.RuleCreator(() => `https://github.com/gajus/eslint-plugin-slonik`);
1501
+ const checkSql = createRule({
1502
+ name: "check-sql",
1503
+ meta: {
1504
+ fixable: "code",
1505
+ docs: {
1506
+ description: "Ensure that sql queries have type annotations"
1507
+ },
1508
+ messages,
1509
+ type: "problem",
1510
+ schema: z__default.toJSONSchema(RuleOptions, { target: "draft-4" })
1511
+ },
1512
+ defaultOptions: [],
1513
+ create(context) {
1514
+ if (!checkSql_utils.shouldLintFile(context)) {
1515
+ return {};
1516
+ }
1517
+ const projectDir = memoize({
1518
+ key: context.filename,
1519
+ value: () => locateNearestPackageJsonDir(context.filename)
1520
+ });
1521
+ const config = memoize({
1522
+ key: JSON.stringify({ key: "config", options: context.options, projectDir }),
1523
+ value: () => getConfigFromFileWithContext({ context, projectDir })
1524
+ });
1525
+ return {
1526
+ TaggedTemplateExpression(tag) {
1527
+ check({ context, tag, config, projectDir });
1528
+ }
1529
+ };
1530
+ }
1531
+ });
1532
+
1533
+ const rules = {
1534
+ "check-sql": checkSql
1535
+ };
1536
+
1537
+ exports.defineConfig = defineConfig;
1538
+ exports.rules = rules;
1539
+ //# sourceMappingURL=eslint-plugin-slonik.BxexVlk1.cjs.map