@codacy/tools-sqlfluff-4 0.6.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Codacy
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 all
13
+ 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 THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # @codacy/tools-sqlfluff-4
2
+
3
+ ## Table of Contents
4
+
5
+ - [Overview](#overview)
6
+ - [Updating patterns](#updating-patterns)
7
+ - [Updating the SQLFluff version](#updating-the-sqlfluff-version)
8
+ - [Development](#development)
9
+ - [Notes for maintainers](#notes-for-maintainers)
10
+
11
+ ---
12
+
13
+ ## Overview
14
+
15
+ Multi-dialect SQL linter using [SQLFluff](https://sqlfluff.com/). Uses the CLI execution strategy -- spawns `sqlfluff lint --format json` from a managed Python venv via `spawnTool()` and parses its JSON output.
16
+
17
+ | Property | Value |
18
+ | ------------- | -------------------------------------- |
19
+ | Tool ID | `SQLFluff` |
20
+ | Codacy UUID | `eebd5ab6-3bef-4192-843c-f52bc4dce861` |
21
+ | Strategy | CLI |
22
+ | Languages | SQL |
23
+ | Binary | `sqlfluff` (pip-installed in venv) |
24
+ | File patterns | `**/*.sql` |
25
+
26
+ ## Updating patterns
27
+
28
+ ```bash
29
+ # Re-fetch pattern metadata from the Codacy API
30
+ pnpm prefetch
31
+
32
+ # Commit the result
33
+ git add src/patterns.json
34
+ ```
35
+
36
+ The `prefetch` script calls `packages/tools/scripts/fetch-patterns.mjs` with the tool UUID to download pattern metadata from the Codacy API.
37
+
38
+ Pattern IDs follow the format `SQLFluff_AL01_aliasing.table`, `SQLFluff_LT01_layout.spacing`, etc. -- they include both the short code and the rule name.
39
+
40
+ ## Updating the SQLFluff version
41
+
42
+ 1. Update `preferredVersion` in `src/adapter.ts`
43
+ 2. Update the `PIP_PACKAGES` array with the new pinned version
44
+ 3. Run `pnpm prefetch` to check for new/removed rules
45
+ 4. Run `pnpm test` to verify compatibility
46
+ 5. If the major version changes, create a new adapter package (`sqlfluff-4/`)
47
+
48
+ ## Development
49
+
50
+ ```bash
51
+ pnpm build # Build with tsup
52
+ pnpm test # Run tests (requires sqlfluff in PATH or venv)
53
+ ```
54
+
55
+ To install sqlfluff locally for testing:
56
+
57
+ ```bash
58
+ pip install sqlfluff==4.2.2
59
+ ```
60
+
61
+ ## Notes for maintainers
62
+
63
+ - **Multi-dialect support**: SQLFluff supports ANSI, PostgreSQL, MySQL, BigQuery, Snowflake, and many more SQL dialects. The generated config defaults to `dialect = ansi`. Users can override this via a local `.sqlfluff` config file.
64
+ - **Python pip dependency**: SQLFluff requires Python 3 as a runtime. The adapter uses an isolated venv at `~/.codacy/runtimes/SQLFluff/venv/` (keyed on the
65
+ stable tool ID, not the package folder name, so a major bump keeps the venv and can
66
+ upgrade it in place instead of orphaning it).
67
+ - **Pattern ID mapping**: SQLFluff's JSON output reports `code` (e.g. `AL01`) but Codacy pattern IDs include both code and name (e.g. `SQLFluff_AL01_aliasing.table`). The adapter builds a `CODE_TO_PATTERN` reverse lookup map from `patterns.json` at module initialization.
68
+ - **Config generation**: When patterns are enabled but no local config exists, the adapter generates a `.sqlfluff` INI file in `.codacy/generated/` with `dialect = ansi`, `templater = raw`, and a `rules` list derived from the enabled pattern codes.
69
+ - Exit code 0 = no violations, 1 = violations found (normal), 2 = error.
70
+ - `start_line_no` and `start_line_pos` in sqlfluff's JSON output are 1-based, matching Codacy's convention.
71
+ - Config file detection only checks for `.sqlfluff` in the repository root.
72
+ - Pattern filtering is both config-level (generated config only enables the requested rules) and post-hoc (results are filtered by enabled pattern IDs as a safety net).
@@ -0,0 +1,5 @@
1
+ import * as _codacy_tooling from '@codacy/tooling';
2
+
3
+ declare const _default: Readonly<_codacy_tooling.ToolAdapter>;
4
+
5
+ export { _default as default };
package/dist/index.js ADDED
@@ -0,0 +1,1181 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ default: () => index_default
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+ var import_tooling2 = require("@codacy/tooling");
37
+
38
+ // src/adapter.ts
39
+ var import_tooling = require("@codacy/tooling");
40
+ var import_path = __toESM(require("path"));
41
+ var import_promises = __toESM(require("fs/promises"));
42
+
43
+ // src/patterns.json
44
+ var patterns_default = [
45
+ {
46
+ id: "SQLFluff_AL01_aliasing.table",
47
+ category: "CodeStyle",
48
+ severityLevel: "Info",
49
+ title: "Enforce explicit aliasing of tables",
50
+ enabled: true,
51
+ languages: ["SQL"],
52
+ parameters: []
53
+ },
54
+ {
55
+ id: "SQLFluff_AL02_aliasing.column",
56
+ category: "CodeStyle",
57
+ severityLevel: "Info",
58
+ title: "Enforce explicit aliasing of columns using AS",
59
+ enabled: true,
60
+ languages: ["SQL"],
61
+ parameters: []
62
+ },
63
+ {
64
+ id: "SQLFluff_AL03_aliasing.expression",
65
+ category: "BestPractice",
66
+ severityLevel: "Info",
67
+ title: "Enforce explicit aliasing of column expressions",
68
+ enabled: false,
69
+ languages: ["SQL"],
70
+ parameters: []
71
+ },
72
+ {
73
+ id: "SQLFluff_AL04_aliasing.unique.table",
74
+ category: "ErrorProne",
75
+ severityLevel: "High",
76
+ title: "Enforce Unique Table Aliases",
77
+ enabled: false,
78
+ languages: ["SQL"],
79
+ parameters: []
80
+ },
81
+ {
82
+ id: "SQLFluff_AL05_aliasing.unused",
83
+ category: "CodeStyle",
84
+ severityLevel: "Info",
85
+ title: "Avoid unused table aliases",
86
+ enabled: false,
87
+ languages: ["SQL"],
88
+ parameters: []
89
+ },
90
+ {
91
+ id: "SQLFluff_AL06_aliasing.length",
92
+ category: "BestPractice",
93
+ severityLevel: "Info",
94
+ title: "Enforce table alias lengths",
95
+ enabled: false,
96
+ languages: ["SQL"],
97
+ parameters: []
98
+ },
99
+ {
100
+ id: "SQLFluff_AL07_aliasing.forbid",
101
+ category: "BestPractice",
102
+ severityLevel: "Warning",
103
+ title: "Avoid table aliases in FROM clauses and JOIN conditions",
104
+ enabled: false,
105
+ languages: ["SQL"],
106
+ parameters: []
107
+ },
108
+ {
109
+ id: "SQLFluff_AL08_aliasing.unique.column",
110
+ category: "ErrorProne",
111
+ severityLevel: "High",
112
+ title: "Enforce Unique Column Aliases",
113
+ enabled: false,
114
+ languages: ["SQL"],
115
+ parameters: []
116
+ },
117
+ {
118
+ id: "SQLFluff_AL09_aliasing.self_alias.column",
119
+ category: "CodeStyle",
120
+ severityLevel: "Info",
121
+ title: "Avoid Self-Aliasing of Columns",
122
+ enabled: false,
123
+ languages: ["SQL"],
124
+ parameters: []
125
+ },
126
+ {
127
+ id: "SQLFluff_AL10_aliasing.required",
128
+ category: "ErrorProne",
129
+ severityLevel: "High",
130
+ title: "Require alias for derived tables",
131
+ enabled: false,
132
+ languages: ["SQL"],
133
+ parameters: []
134
+ },
135
+ {
136
+ id: "SQLFluff_AM01_ambiguous.distinct",
137
+ category: "BestPractice",
138
+ severityLevel: "Info",
139
+ title: "Avoid ambiguous use of DISTINCT with GROUP BY",
140
+ enabled: true,
141
+ languages: ["SQL"],
142
+ parameters: []
143
+ },
144
+ {
145
+ id: "SQLFluff_AM02_ambiguous.union",
146
+ category: "BestPractice",
147
+ severityLevel: "Info",
148
+ title: "Enforce explicit UNION modifier",
149
+ enabled: false,
150
+ languages: ["SQL"],
151
+ parameters: []
152
+ },
153
+ {
154
+ id: "SQLFluff_AM03_ambiguous.order_by",
155
+ category: "BestPractice",
156
+ severityLevel: "Info",
157
+ title: "Enforce Consistent Ordering Directions in ORDER BY Clause",
158
+ enabled: false,
159
+ languages: ["SQL"],
160
+ parameters: []
161
+ },
162
+ {
163
+ id: "SQLFluff_AM04_ambiguous.column_count",
164
+ category: "BestPractice",
165
+ severityLevel: "Warning",
166
+ title: "Avoid querying with ambiguous column count",
167
+ enabled: false,
168
+ languages: ["SQL"],
169
+ parameters: []
170
+ },
171
+ {
172
+ id: "SQLFluff_AM05_ambiguous.join",
173
+ category: "BestPractice",
174
+ severityLevel: "Info",
175
+ title: "Enforce Fully Qualified Join Clauses",
176
+ enabled: false,
177
+ languages: ["SQL"],
178
+ parameters: []
179
+ },
180
+ {
181
+ id: "SQLFluff_AM06_ambiguous.column_references",
182
+ category: "CodeStyle",
183
+ severityLevel: "Info",
184
+ title: "Avoid inconsistent column references in GROUP BY and ORDER BY clauses",
185
+ enabled: false,
186
+ languages: ["SQL"],
187
+ parameters: []
188
+ },
189
+ {
190
+ id: "SQLFluff_AM07_ambiguous.set_columns",
191
+ category: "ErrorProne",
192
+ severityLevel: "High",
193
+ title: "Enforce consistent number of columns in set queries",
194
+ enabled: false,
195
+ languages: ["SQL"],
196
+ parameters: []
197
+ },
198
+ {
199
+ id: "SQLFluff_AM08_ambiguous.join_condition",
200
+ category: "BestPractice",
201
+ severityLevel: "Warning",
202
+ title: "Avoid Implicit Cross Join",
203
+ enabled: false,
204
+ languages: ["SQL"],
205
+ parameters: []
206
+ },
207
+ {
208
+ id: "SQLFluff_AM09_ambiguous.order_by_limit",
209
+ category: "BestPractice",
210
+ severityLevel: "Warning",
211
+ title: "Require ORDER BY when using LIMIT/OFFSET",
212
+ enabled: false,
213
+ languages: ["SQL"],
214
+ parameters: []
215
+ },
216
+ {
217
+ id: "SQLFluff_CP01_capitalisation.keywords",
218
+ category: "CodeStyle",
219
+ severityLevel: "Info",
220
+ title: "Enforce consistent capitalisation of SQL keywords",
221
+ enabled: true,
222
+ languages: ["SQL"],
223
+ parameters: []
224
+ },
225
+ {
226
+ id: "SQLFluff_CP02_capitalisation.identifiers",
227
+ category: "CodeStyle",
228
+ severityLevel: "Info",
229
+ title: "Enforce consistent capitalisation of unquoted identifiers",
230
+ enabled: true,
231
+ languages: ["SQL"],
232
+ parameters: []
233
+ },
234
+ {
235
+ id: "SQLFluff_CP03_capitalisation.functions",
236
+ category: "CodeStyle",
237
+ severityLevel: "Info",
238
+ title: "Enforce Consistent Capitalisation of SQL Function Names",
239
+ enabled: false,
240
+ languages: ["SQL"],
241
+ parameters: []
242
+ },
243
+ {
244
+ id: "SQLFluff_CP04_capitalisation.literals",
245
+ category: "CodeStyle",
246
+ severityLevel: "Info",
247
+ title: "Enforce consistent capitalisation of boolean and null literals",
248
+ enabled: false,
249
+ languages: ["SQL"],
250
+ parameters: []
251
+ },
252
+ {
253
+ id: "SQLFluff_CP05_capitalisation.types",
254
+ category: "CodeStyle",
255
+ severityLevel: "Info",
256
+ title: "Enforce consistent capitalisation of datatypes",
257
+ enabled: false,
258
+ languages: ["SQL"],
259
+ parameters: []
260
+ },
261
+ {
262
+ id: "SQLFluff_CV01_convention.not_equal",
263
+ category: "CodeStyle",
264
+ severityLevel: "Info",
265
+ title: "Enforce Consistent Usage of Not Equal Operators",
266
+ enabled: false,
267
+ languages: ["SQL"],
268
+ parameters: []
269
+ },
270
+ {
271
+ id: "SQLFluff_CV02_convention.coalesce",
272
+ category: "BestPractice",
273
+ severityLevel: "Info",
274
+ title: "Use COALESCE Instead of IFNULL or NVL",
275
+ enabled: false,
276
+ languages: ["SQL"],
277
+ parameters: []
278
+ },
279
+ {
280
+ id: "SQLFluff_CV03_convention.select_trailing_comma",
281
+ category: "Compatibility",
282
+ severityLevel: "Warning",
283
+ title: "Disallow Trailing Commas in SELECT Clause",
284
+ enabled: false,
285
+ languages: ["SQL"],
286
+ parameters: []
287
+ },
288
+ {
289
+ id: "SQLFluff_CV04_convention.count_rows",
290
+ category: "CodeStyle",
291
+ severityLevel: "Info",
292
+ title: "Enforce consistent COUNT syntax for row counting",
293
+ enabled: false,
294
+ languages: ["SQL"],
295
+ parameters: []
296
+ },
297
+ {
298
+ id: "SQLFluff_CV05_convention.is_null",
299
+ category: "ErrorProne",
300
+ severityLevel: "High",
301
+ title: "Enforce Use of IS or IS NOT for NULL Comparisons",
302
+ enabled: false,
303
+ languages: ["SQL"],
304
+ parameters: []
305
+ },
306
+ {
307
+ id: "SQLFluff_CV06_convention.terminator",
308
+ category: "CodeStyle",
309
+ severityLevel: "Info",
310
+ title: "Enforce statement termination with a semi-colon",
311
+ enabled: false,
312
+ languages: ["SQL"],
313
+ parameters: []
314
+ },
315
+ {
316
+ id: "SQLFluff_CV07_convention.statement_brackets",
317
+ category: "CodeStyle",
318
+ severityLevel: "Info",
319
+ title: "Avoid Wrapping Top-Level SQL Statements in Brackets",
320
+ enabled: false,
321
+ languages: ["SQL"],
322
+ parameters: []
323
+ },
324
+ {
325
+ id: "SQLFluff_CV08_convention.left_join",
326
+ category: "BestPractice",
327
+ severityLevel: "Info",
328
+ title: "Enforce use of LEFT JOIN instead of RIGHT JOIN",
329
+ enabled: false,
330
+ languages: ["SQL"],
331
+ parameters: []
332
+ },
333
+ {
334
+ id: "SQLFluff_CV09_convention.blocked_words",
335
+ category: "BestPractice",
336
+ severityLevel: "Warning",
337
+ title: "Block Configurable Words Usage",
338
+ enabled: false,
339
+ languages: ["SQL"],
340
+ parameters: []
341
+ },
342
+ {
343
+ id: "SQLFluff_CV10_convention.quoted_literals",
344
+ category: "CodeStyle",
345
+ severityLevel: "Info",
346
+ title: "Enforce Consistent Usage of Preferred Quotes for Quoted Literals",
347
+ enabled: false,
348
+ languages: ["SQL"],
349
+ parameters: []
350
+ },
351
+ {
352
+ id: "SQLFluff_CV11_convention.casting_style",
353
+ category: "CodeStyle",
354
+ severityLevel: "Info",
355
+ title: "Enforce consistent type casting style",
356
+ enabled: false,
357
+ languages: ["SQL"],
358
+ parameters: []
359
+ },
360
+ {
361
+ id: "SQLFluff_CV12_convention.join_condition",
362
+ category: "BestPractice",
363
+ severityLevel: "Info",
364
+ title: "Use JOIN ON for join conditions",
365
+ enabled: false,
366
+ languages: ["SQL"],
367
+ parameters: []
368
+ },
369
+ {
370
+ id: "SQLFluff_JJ01_jinja.padding",
371
+ category: "CodeStyle",
372
+ severityLevel: "Info",
373
+ title: "Enforce single whitespace padding around Jinja tags",
374
+ enabled: false,
375
+ languages: ["SQL"],
376
+ parameters: []
377
+ },
378
+ {
379
+ id: "SQLFluff_LT01_layout.spacing",
380
+ category: "CodeStyle",
381
+ severityLevel: "Info",
382
+ title: "Enforce Appropriate Spacing in SQL",
383
+ enabled: true,
384
+ languages: ["SQL"],
385
+ parameters: []
386
+ },
387
+ {
388
+ id: "SQLFluff_LT02_layout.indent",
389
+ category: "CodeStyle",
390
+ severityLevel: "Info",
391
+ title: "Enforce Correct Indentation",
392
+ enabled: true,
393
+ languages: ["SQL"],
394
+ parameters: []
395
+ },
396
+ {
397
+ id: "SQLFluff_LT03_layout.operators",
398
+ category: "CodeStyle",
399
+ severityLevel: "Info",
400
+ title: "Enforce Standard Operator Positioning in SQL",
401
+ enabled: false,
402
+ languages: ["SQL"],
403
+ parameters: []
404
+ },
405
+ {
406
+ id: "SQLFluff_LT04_layout.commas",
407
+ category: "CodeStyle",
408
+ severityLevel: "Info",
409
+ title: "Enforce consistent leading or trailing commas",
410
+ enabled: true,
411
+ languages: ["SQL"],
412
+ parameters: []
413
+ },
414
+ {
415
+ id: "SQLFluff_LT05_layout.long_lines",
416
+ category: "CodeStyle",
417
+ severityLevel: "Info",
418
+ title: "Enforce line length limit",
419
+ enabled: false,
420
+ languages: ["SQL"],
421
+ parameters: []
422
+ },
423
+ {
424
+ id: "SQLFluff_LT06_layout.functions",
425
+ category: "CodeStyle",
426
+ severityLevel: "Info",
427
+ title: "Enforce function name immediately followed by parenthesis",
428
+ enabled: false,
429
+ languages: ["SQL"],
430
+ parameters: []
431
+ },
432
+ {
433
+ id: "SQLFluff_LT07_layout.cte_bracket",
434
+ category: "CodeStyle",
435
+ severityLevel: "Info",
436
+ title: "Enforce WITH Clause Closing Bracket on New Line",
437
+ enabled: false,
438
+ languages: ["SQL"],
439
+ parameters: []
440
+ },
441
+ {
442
+ id: "SQLFluff_LT08_layout.cte_newline",
443
+ category: "CodeStyle",
444
+ severityLevel: "Info",
445
+ title: "Enforce blank line after CTE closing bracket",
446
+ enabled: false,
447
+ languages: ["SQL"],
448
+ parameters: []
449
+ },
450
+ {
451
+ id: "SQLFluff_LT09_layout.select_targets",
452
+ category: "CodeStyle",
453
+ severityLevel: "Info",
454
+ title: "Enforce select targets on new lines",
455
+ enabled: false,
456
+ languages: ["SQL"],
457
+ parameters: []
458
+ },
459
+ {
460
+ id: "SQLFluff_LT10_layout.select_modifiers",
461
+ category: "CodeStyle",
462
+ severityLevel: "Info",
463
+ title: "Enforce SELECT Modifiers on Same Line as SELECT",
464
+ enabled: false,
465
+ languages: ["SQL"],
466
+ parameters: []
467
+ },
468
+ {
469
+ id: "SQLFluff_LT11_layout.set_operators",
470
+ category: "CodeStyle",
471
+ severityLevel: "Info",
472
+ title: "Enforce set operators to be surrounded by newlines",
473
+ enabled: false,
474
+ languages: ["SQL"],
475
+ parameters: []
476
+ },
477
+ {
478
+ id: "SQLFluff_LT12_layout.end_of_file",
479
+ category: "CodeStyle",
480
+ severityLevel: "Info",
481
+ title: "Enforce files end with a single trailing newline",
482
+ enabled: false,
483
+ languages: ["SQL"],
484
+ parameters: []
485
+ },
486
+ {
487
+ id: "SQLFluff_LT13_layout.start_of_file",
488
+ category: "CodeStyle",
489
+ severityLevel: "Info",
490
+ title: "Disallow files to begin with newlines or whitespace",
491
+ enabled: false,
492
+ languages: ["SQL"],
493
+ parameters: []
494
+ },
495
+ {
496
+ id: "SQLFluff_LT14_layout.keyword_newline",
497
+ category: "CodeStyle",
498
+ severityLevel: "Info",
499
+ title: "Enforce Keyword Clause Newline Layout",
500
+ enabled: false,
501
+ languages: ["SQL"],
502
+ parameters: []
503
+ },
504
+ {
505
+ id: "SQLFluff_LT15_layout.newlines",
506
+ category: "CodeStyle",
507
+ severityLevel: "Info",
508
+ title: "Avoid Too Many Consecutive Blank Lines",
509
+ enabled: false,
510
+ languages: ["SQL"],
511
+ parameters: []
512
+ },
513
+ {
514
+ id: "SQLFluff_OR01_oracle.empty_batch",
515
+ category: "CodeStyle",
516
+ severityLevel: "Info",
517
+ title: "Remove empty batches",
518
+ enabled: false,
519
+ languages: ["SQL"],
520
+ parameters: [],
521
+ tags: ["oracle", "sqlfluff"]
522
+ },
523
+ {
524
+ id: "SQLFluff_PG01_postgres.excessive_locks",
525
+ category: "BestPractice",
526
+ severityLevel: "Warning",
527
+ title: "Avoid excessive locks in PostgreSQL DDL",
528
+ enabled: false,
529
+ languages: ["SQL"],
530
+ parameters: [],
531
+ tags: ["postgresql", "database", "ddl"]
532
+ },
533
+ {
534
+ id: "SQLFluff_PG02_postgres.not_valid_foreign_key",
535
+ category: "BestPractice",
536
+ severityLevel: "Warning",
537
+ title: "Create PostgreSQL foreign keys as NOT VALID",
538
+ enabled: false,
539
+ languages: ["SQL"],
540
+ parameters: [],
541
+ tags: ["postgres"]
542
+ },
543
+ {
544
+ id: "SQLFluff_RF01_references.from",
545
+ category: "ErrorProne",
546
+ severityLevel: "High",
547
+ title: "Disallow references to objects not in FROM clause",
548
+ enabled: true,
549
+ languages: ["SQL"],
550
+ parameters: []
551
+ },
552
+ {
553
+ id: "SQLFluff_RF02_references.qualification",
554
+ category: "ErrorProne",
555
+ severityLevel: "Warning",
556
+ title: "Enforce Qualification of References in Multi-Table SELECT",
557
+ enabled: true,
558
+ languages: ["SQL"],
559
+ parameters: []
560
+ },
561
+ {
562
+ id: "SQLFluff_RF03_references.consistent",
563
+ category: "CodeStyle",
564
+ severityLevel: "Info",
565
+ title: "Enforce Consistent Qualification of Column References",
566
+ enabled: false,
567
+ languages: ["SQL"],
568
+ parameters: []
569
+ },
570
+ {
571
+ id: "SQLFluff_RF04_references.keywords",
572
+ category: "BestPractice",
573
+ severityLevel: "Warning",
574
+ title: "Avoid Using Keywords as Identifiers",
575
+ enabled: false,
576
+ languages: ["SQL"],
577
+ parameters: []
578
+ },
579
+ {
580
+ id: "SQLFluff_RF05_references.special_chars",
581
+ category: "BestPractice",
582
+ severityLevel: "Info",
583
+ title: "Avoid Using Special Characters in Identifiers",
584
+ enabled: false,
585
+ languages: ["SQL"],
586
+ parameters: []
587
+ },
588
+ {
589
+ id: "SQLFluff_RF06_references.quoting",
590
+ category: "CodeStyle",
591
+ severityLevel: "Info",
592
+ title: "Avoid Unnecessary Quoted Identifiers",
593
+ enabled: false,
594
+ languages: ["SQL"],
595
+ parameters: []
596
+ },
597
+ {
598
+ id: "SQLFluff_RF07_references.window_alias",
599
+ category: "ErrorProne",
600
+ severityLevel: "High",
601
+ title: "Avoid referencing SELECT aliases inside their own OVER clause",
602
+ enabled: false,
603
+ languages: ["SQL"],
604
+ parameters: []
605
+ },
606
+ {
607
+ id: "SQLFluff_ST01_structure.else_null",
608
+ category: "CodeStyle",
609
+ severityLevel: "Info",
610
+ title: "Avoid specifying else null in CASE WHEN statements",
611
+ enabled: true,
612
+ languages: ["SQL"],
613
+ parameters: []
614
+ },
615
+ {
616
+ id: "SQLFluff_ST02_structure.simple_case",
617
+ category: "BestPractice",
618
+ severityLevel: "Info",
619
+ title: "Avoid Unnecessary CASE Statement",
620
+ enabled: false,
621
+ languages: ["SQL"],
622
+ parameters: []
623
+ },
624
+ {
625
+ id: "SQLFluff_ST03_structure.unused_cte",
626
+ category: "UnusedCode",
627
+ severityLevel: "Warning",
628
+ title: "Avoid Unused Common Table Expressions (CTEs)",
629
+ enabled: true,
630
+ languages: ["SQL"],
631
+ parameters: []
632
+ },
633
+ {
634
+ id: "SQLFluff_ST04_structure.nested_case",
635
+ category: "CodeStyle",
636
+ severityLevel: "Info",
637
+ title: "Avoid Nested CASE Statements in ELSE Clause",
638
+ enabled: false,
639
+ languages: ["SQL"],
640
+ parameters: []
641
+ },
642
+ {
643
+ id: "SQLFluff_ST05_structure.subquery",
644
+ category: "BestPractice",
645
+ severityLevel: "Warning",
646
+ title: "Avoid Subqueries in Join/From Clauses",
647
+ enabled: false,
648
+ languages: ["SQL"],
649
+ parameters: []
650
+ },
651
+ {
652
+ id: "SQLFluff_ST06_structure.column_order",
653
+ category: "CodeStyle",
654
+ severityLevel: "Info",
655
+ title: "Enforce select targets order by complexity",
656
+ enabled: true,
657
+ languages: ["SQL"],
658
+ parameters: []
659
+ },
660
+ {
661
+ id: "SQLFluff_ST07_structure.using",
662
+ category: "BestPractice",
663
+ severityLevel: "Info",
664
+ title: "Prefer specifying join keys instead of USING",
665
+ enabled: true,
666
+ languages: ["SQL"],
667
+ parameters: []
668
+ },
669
+ {
670
+ id: "SQLFluff_ST08_structure.distinct",
671
+ category: "BestPractice",
672
+ severityLevel: "Info",
673
+ title: "Avoid using DISTINCT with parentheses",
674
+ enabled: false,
675
+ languages: ["SQL"],
676
+ parameters: []
677
+ },
678
+ {
679
+ id: "SQLFluff_ST09_structure.join_condition_order",
680
+ category: "CodeStyle",
681
+ severityLevel: "Info",
682
+ title: "Enforce Join Condition Table Order",
683
+ enabled: false,
684
+ languages: ["SQL"],
685
+ parameters: []
686
+ },
687
+ {
688
+ id: "SQLFluff_ST10_structure.constant_expression",
689
+ category: "BestPractice",
690
+ severityLevel: "Warning",
691
+ title: "Avoid Redundant Constant Expressions",
692
+ enabled: false,
693
+ languages: ["SQL"],
694
+ parameters: []
695
+ },
696
+ {
697
+ id: "SQLFluff_ST11_structure.unused_join",
698
+ category: "ErrorProne",
699
+ severityLevel: "Warning",
700
+ title: "Avoid Unused Outer Joins",
701
+ enabled: false,
702
+ languages: ["SQL"],
703
+ parameters: []
704
+ },
705
+ {
706
+ id: "SQLFluff_ST12_structure.consecutive_semicolons",
707
+ category: "BestPractice",
708
+ severityLevel: "Info",
709
+ title: "Avoid consecutive semicolons",
710
+ enabled: false,
711
+ languages: ["SQL"],
712
+ parameters: []
713
+ },
714
+ {
715
+ id: "SQLFluff_TQ01_tsql.sp_prefix",
716
+ category: "BestPractice",
717
+ severityLevel: "Warning",
718
+ title: "Avoid using the 'sp_' prefix for user-defined stored procedures",
719
+ enabled: false,
720
+ languages: ["SQL"],
721
+ parameters: []
722
+ },
723
+ {
724
+ id: "SQLFluff_TQ02_tsql.procedure_begin_end",
725
+ category: "BestPractice",
726
+ severityLevel: "Warning",
727
+ title: "Require BEGIN/END for procedure bodies with multiple statements",
728
+ enabled: false,
729
+ languages: ["SQL"],
730
+ parameters: []
731
+ },
732
+ {
733
+ id: "SQLFluff_TQ03_tsql.empty_batch",
734
+ category: "BestPractice",
735
+ severityLevel: "Info",
736
+ title: "Remove empty batches",
737
+ enabled: false,
738
+ languages: ["SQL"],
739
+ parameters: []
740
+ },
741
+ {
742
+ id: "SQLFluff_TQ04_tsql.prefer_as_alias",
743
+ category: "Compatibility",
744
+ severityLevel: "Info",
745
+ title: "Prefer AS-style aliasing",
746
+ enabled: false,
747
+ languages: ["SQL"],
748
+ parameters: []
749
+ }
750
+ ];
751
+
752
+ // src/metadata.ts
753
+ var descriptor = {
754
+ id: "SQLFluff",
755
+ displayName: "SQLFluff",
756
+ preferredVersion: "4.2.2",
757
+ languages: ["SQL"],
758
+ filePatterns: ["**/*.sql"],
759
+ supportedOS: ["linux", "darwin", "win32"],
760
+ supportedArch: ["x64", "arm64"],
761
+ supportedRunners: ["local", "container"]
762
+ };
763
+
764
+ // src/adapter.ts
765
+ var TOOL_ID = "SQLFluff";
766
+ var VENV_ID = TOOL_ID;
767
+ var LEGACY_VENV_IDS = ["sqlfluff-3", "sqlfluff-4"];
768
+ async function hasLegacyVenv(globalDir) {
769
+ for (const legacyId of LEGACY_VENV_IDS) {
770
+ if (await (0, import_tooling.hasManagedInstall)(import_path.default.join(globalDir, "runtimes", legacyId))) return true;
771
+ }
772
+ return false;
773
+ }
774
+ var PIP_PACKAGES = ["sqlfluff==4.2.2"];
775
+ var PYTHON_VERSION_RANGE = ">=3.9.0";
776
+ var PATTERN_META = new Map(
777
+ patterns_default.map((p) => [
778
+ p.id,
779
+ {
780
+ category: p.category,
781
+ severity: p.severityLevel ?? "Info"
782
+ }
783
+ ])
784
+ );
785
+ var CODE_TO_PATTERN = new Map(
786
+ patterns_default.map((p) => {
787
+ const withoutPrefix = p.id.replace(`${TOOL_ID}_`, "");
788
+ const code = withoutPrefix.split("_")[0];
789
+ return [code, p.id];
790
+ })
791
+ );
792
+ function ruleMetadata(patternId) {
793
+ return PATTERN_META.get(patternId) ?? { category: "CodeStyle", severity: "Info" };
794
+ }
795
+ var CONFIG_FILE_CANDIDATE = ".sqlfluff";
796
+ async function resolveBinaryPath(ctx) {
797
+ const venvDir = (0, import_tooling.getVenvDir)(ctx.globalDir, VENV_ID);
798
+ const venvBin = (0, import_tooling.resolveVenvBinary)((0, import_tooling.getVenvPaths)(venvDir), "sqlfluff");
799
+ try {
800
+ await import_promises.default.access(venvBin);
801
+ return venvBin;
802
+ } catch {
803
+ return "sqlfluff";
804
+ }
805
+ }
806
+ function extractRuleCode(patternId) {
807
+ const withoutPrefix = patternId.replace(`${TOOL_ID}_`, "");
808
+ return withoutPrefix.split("_")[0];
809
+ }
810
+ function generateConfigContent(patterns) {
811
+ const codes = patterns.map((p) => extractRuleCode(p.patternId));
812
+ const uniqueCodes = [...new Set(codes)];
813
+ const needsJinja = patterns.some((p) => new RegExp(`^${TOOL_ID}_JJ\\d+`).test(p.patternId));
814
+ const templater = needsJinja ? "jinja" : "raw";
815
+ return `[sqlfluff]
816
+ dialect = ansi
817
+ templater = ${templater}
818
+ rules = ${uniqueCodes.join(",")}
819
+ `;
820
+ }
821
+ var adapter = {
822
+ ...descriptor,
823
+ patternsMetadata: patterns_default,
824
+ compatibleVersions: ">=4.0.0",
825
+ website: "https://sqlfluff.com/",
826
+ prerequisites: [
827
+ {
828
+ name: "Python",
829
+ versionRange: PYTHON_VERSION_RANGE,
830
+ preferredVersion: "3.12.0",
831
+ checkCommand: "python3 --version"
832
+ }
833
+ ],
834
+ /**
835
+ * Checks whether sqlfluff is available in a venv or on the global PATH.
836
+ *
837
+ * Checks in order:
838
+ * 1. Codacy-managed venv (`~/.codacy/runtimes/SQLFluff/venv/bin/sqlfluff`)
839
+ * 2. Global PATH (`sqlfluff`)
840
+ *
841
+ * Parses the version from `sqlfluff version` output like `3.3.0`.
842
+ */
843
+ async checkAvailability(ctx) {
844
+ ctx.logger.debug("Checking availability", { toolId: TOOL_ID });
845
+ const pythonInfo = await (0, import_tooling.findPython)(PYTHON_VERSION_RANGE, ctx.logger).catch(() => null);
846
+ const dependencies = pythonInfo ? [
847
+ {
848
+ name: "Python",
849
+ available: true,
850
+ version: pythonInfo.version,
851
+ installation: "global"
852
+ }
853
+ ] : [
854
+ {
855
+ name: "Python",
856
+ available: false,
857
+ reason: `Python 3 (${PYTHON_VERSION_RANGE}) not found`
858
+ }
859
+ ];
860
+ const venvDir = (0, import_tooling.getVenvDir)(ctx.globalDir, VENV_ID);
861
+ try {
862
+ const venv = (0, import_tooling.getVenvPaths)(venvDir);
863
+ await import_promises.default.access(venv.python);
864
+ const version = await (0, import_tooling.checkVenvTool)(
865
+ venv,
866
+ "sqlfluff",
867
+ "version",
868
+ /(\d+\.\d+\.\d+)/,
869
+ ctx.logger
870
+ );
871
+ if (version) {
872
+ ctx.logger.debug("Found sqlfluff in codacy venv", { toolId: TOOL_ID, version });
873
+ return {
874
+ available: true,
875
+ version,
876
+ path: (0, import_tooling.resolveVenvBinary)(venv, "sqlfluff"),
877
+ installation: "codacy",
878
+ dependencies
879
+ };
880
+ }
881
+ } catch {
882
+ }
883
+ try {
884
+ const { stdout, exitCode } = await (0, import_tooling.spawnTool)("sqlfluff", ["version"], {
885
+ cwd: process.cwd()
886
+ });
887
+ if (exitCode === 0) {
888
+ const match = stdout.match(/(\d+\.\d+\.\d+)/);
889
+ if (match) {
890
+ ctx.logger.debug("Found sqlfluff on global PATH", {
891
+ toolId: TOOL_ID,
892
+ version: match[1]
893
+ });
894
+ return {
895
+ available: true,
896
+ version: match[1],
897
+ installation: "global",
898
+ dependencies
899
+ };
900
+ }
901
+ }
902
+ } catch {
903
+ }
904
+ ctx.logger.debug("sqlfluff not found", { toolId: TOOL_ID });
905
+ return {
906
+ available: false,
907
+ reason: "sqlfluff not found in venv or PATH",
908
+ installHint: "pip install sqlfluff # or\ncodacy-analysis analyze . --install-dependencies # auto-install",
909
+ dependencies,
910
+ // A venv from an earlier CLI version means this install is ours to repair,
911
+ // not a tool the user never had. The runner cannot infer this: it looks for
912
+ // a non-empty `tools/<id>/`, and SQLFluff keeps nothing there.
913
+ ...await hasLegacyVenv(ctx.globalDir) ? { staleManagedInstall: true } : {}
914
+ };
915
+ },
916
+ /**
917
+ * Installs SQLFluff into an isolated Python virtual environment.
918
+ *
919
+ * Uses findPython -> ensureVenv -> pipInstall to create a dedicated venv
920
+ * at `~/.codacy/runtimes/SQLFluff/venv/` and install `sqlfluff==4.2.2`.
921
+ */
922
+ async install(ctx) {
923
+ ctx.logger.info("Starting install", { toolId: TOOL_ID });
924
+ const python = await (0, import_tooling.ensurePython)(ctx.globalDir, PYTHON_VERSION_RANGE, ctx.logger);
925
+ if (!python) {
926
+ return {
927
+ success: false,
928
+ error: {
929
+ toolId: TOOL_ID,
930
+ phase: "requirementCheck",
931
+ kind: "MissingPrerequisite",
932
+ message: `Python (${PYTHON_VERSION_RANGE}) could not be found or downloaded. SQLFluff requires a Python runtime.`,
933
+ level: "error"
934
+ }
935
+ };
936
+ }
937
+ const venvDir = (0, import_tooling.getVenvDir)(ctx.globalDir, VENV_ID);
938
+ try {
939
+ ctx.logger.info(`Creating venv for sqlfluff at ${venvDir}...`);
940
+ const venv = await (0, import_tooling.ensureVenv)(python.path, venvDir, ctx.logger);
941
+ ctx.logger.info(`Installing ${PIP_PACKAGES.join(", ")} into venv...`);
942
+ await (0, import_tooling.pipInstall)(venv, PIP_PACKAGES, ctx.logger);
943
+ const sqlfluffPath = (0, import_tooling.resolveVenvBinary)(venv, "sqlfluff");
944
+ ctx.logger.info(`Installed sqlfluff to ${sqlfluffPath}`);
945
+ await (0, import_tooling.pruneSupersededArtifacts)(
946
+ import_path.default.join(ctx.globalDir, "runtimes"),
947
+ VENV_ID,
948
+ (name) => LEGACY_VENV_IDS.includes(name),
949
+ ctx.logger
950
+ );
951
+ return {
952
+ success: true,
953
+ installedPath: sqlfluffPath,
954
+ installedVersion: adapter.preferredVersion
955
+ };
956
+ } catch (err) {
957
+ return {
958
+ success: false,
959
+ error: {
960
+ toolId: TOOL_ID,
961
+ phase: "toolInstall",
962
+ kind: "InstallError",
963
+ message: `Failed to install sqlfluff: ${err instanceof Error ? err.message : String(err)}`,
964
+ level: "error"
965
+ }
966
+ };
967
+ }
968
+ },
969
+ /**
970
+ * Checks for `.sqlfluff` configuration file in the repository root.
971
+ */
972
+ async checkLocalConfigurationFile(ctx) {
973
+ ctx.logger.debug("Checking for local config", { toolId: TOOL_ID });
974
+ const candidatePath = import_path.default.join(ctx.repositoryRoot, CONFIG_FILE_CANDIDATE);
975
+ try {
976
+ await import_promises.default.access(candidatePath);
977
+ ctx.logger.debug("Local config found", { toolId: TOOL_ID, path: candidatePath });
978
+ return { found: true, path: candidatePath };
979
+ } catch {
980
+ return { found: false };
981
+ }
982
+ },
983
+ /**
984
+ * Runs `sqlfluff lint --format json` against the target SQL files and
985
+ * converts the JSON output into Codacy Issue objects.
986
+ *
987
+ * Config resolution:
988
+ * - If `useLocalConfigurationFile` is true and a local `.sqlfluff` is found,
989
+ * lets sqlfluff discover it naturally (no --config flag needed).
990
+ * - If patterns are specified and no local config is in use, generates a
991
+ * `.sqlfluff` config in `.codacy/generated/` with the enabled rule codes.
992
+ * - If no patterns and no local config, skips execution.
993
+ *
994
+ * Key details:
995
+ * - `--format json` produces a JSON array of file results, each with `filepath`
996
+ * and `violations[]`.
997
+ * - `violations[].code` is the short rule code (e.g. "AL01"). The adapter maps
998
+ * this to the full Codacy pattern ID (e.g. "SQLFluff_AL01_aliasing.table")
999
+ * via the CODE_TO_PATTERN lookup built from patterns.json.
1000
+ * - Exit code 0 = no violations, 1 = violations found (normal), 2 = error.
1001
+ *
1002
+ * Never throws -- all errors are captured in the returned `errors` array.
1003
+ */
1004
+ async analyze(ctx, codacyConfig) {
1005
+ const startMs = Date.now();
1006
+ ctx.logger.info("Starting analysis", { toolId: TOOL_ID, fileCount: ctx.targetFiles.length });
1007
+ const startedAt = /* @__PURE__ */ new Date();
1008
+ const issues = [];
1009
+ const errors = [];
1010
+ if (ctx.targetFiles.length === 0) {
1011
+ return (0, import_tooling.buildResult)(TOOL_ID, startedAt, /* @__PURE__ */ new Date(), issues, errors, 0);
1012
+ }
1013
+ const binary = await resolveBinaryPath(ctx);
1014
+ const absoluteFiles = ctx.targetFiles.map((f) => import_path.default.resolve(ctx.repositoryRoot, f));
1015
+ const args = ["lint", "--format", "json", "--nocolor"];
1016
+ const useLocal = codacyConfig.useLocalConfigurationFile && codacyConfig.localConfigurationFile;
1017
+ if (useLocal) {
1018
+ } else if (codacyConfig.patterns.length > 0) {
1019
+ try {
1020
+ await import_promises.default.mkdir(ctx.generatedConfigDir, { recursive: true });
1021
+ const configPath = import_path.default.join(ctx.generatedConfigDir, ".sqlfluff");
1022
+ const configContent = generateConfigContent(codacyConfig.patterns);
1023
+ await import_promises.default.writeFile(configPath, configContent, "utf-8");
1024
+ args.push("--config", configPath);
1025
+ ctx.logger.debug("Generated sqlfluff config", { path: configPath });
1026
+ } catch (err) {
1027
+ errors.push({
1028
+ toolId: TOOL_ID,
1029
+ phase: "toolConfig",
1030
+ kind: "ConfigError",
1031
+ message: `Failed to generate sqlfluff config: ${err instanceof Error ? err.message : String(err)}`,
1032
+ level: "error"
1033
+ });
1034
+ return (0, import_tooling.buildResult)(TOOL_ID, startedAt, /* @__PURE__ */ new Date(), issues, errors, ctx.targetFiles.length);
1035
+ }
1036
+ }
1037
+ const fileChunks = (0, import_tooling.chunkFilesForArgv)(absoluteFiles);
1038
+ try {
1039
+ const fileResults = [];
1040
+ for (const chunk of fileChunks) {
1041
+ const { stdout, stderr, exitCode } = await (0, import_tooling.spawnTool)(binary, [...args, ...chunk], {
1042
+ cwd: ctx.repositoryRoot,
1043
+ logger: ctx.logger
1044
+ });
1045
+ if (exitCode >= 2) {
1046
+ errors.push({
1047
+ toolId: TOOL_ID,
1048
+ phase: "toolInvoke",
1049
+ kind: "NonZeroExit",
1050
+ message: `sqlfluff exited with code ${exitCode}${stderr ? `: ${stderr.trim()}` : ""}`,
1051
+ level: "error"
1052
+ });
1053
+ return (0, import_tooling.buildResult)(
1054
+ TOOL_ID,
1055
+ startedAt,
1056
+ /* @__PURE__ */ new Date(),
1057
+ issues,
1058
+ errors,
1059
+ ctx.targetFiles.length
1060
+ );
1061
+ }
1062
+ const stderrFiltered = stderr.split("\n").filter(
1063
+ (l) => l.trim() && !l.includes("== [") && !l.includes("All Finished") && !l.startsWith("PASS") && !l.startsWith("FAIL") && !l.includes("Tried to allowlist unknown rule references")
1064
+ ).join("\n").trim();
1065
+ if (stderrFiltered) {
1066
+ errors.push({
1067
+ toolId: TOOL_ID,
1068
+ phase: "outputParse",
1069
+ kind: "ParseWarning",
1070
+ message: `sqlfluff stderr: ${stderrFiltered}`,
1071
+ level: "warning"
1072
+ });
1073
+ }
1074
+ if (!stdout.trim()) continue;
1075
+ let chunkResults;
1076
+ try {
1077
+ chunkResults = JSON.parse(stdout);
1078
+ } catch (err) {
1079
+ errors.push({
1080
+ toolId: TOOL_ID,
1081
+ phase: "outputParse",
1082
+ kind: "MalformedOutput",
1083
+ message: `Failed to parse sqlfluff JSON output: ${err instanceof Error ? err.message : String(err)}`,
1084
+ level: "error"
1085
+ });
1086
+ return (0, import_tooling.buildResult)(
1087
+ TOOL_ID,
1088
+ startedAt,
1089
+ /* @__PURE__ */ new Date(),
1090
+ issues,
1091
+ errors,
1092
+ ctx.targetFiles.length
1093
+ );
1094
+ }
1095
+ if (!Array.isArray(chunkResults)) {
1096
+ errors.push({
1097
+ toolId: TOOL_ID,
1098
+ phase: "outputParse",
1099
+ kind: "MalformedOutput",
1100
+ message: "sqlfluff output is not a JSON array",
1101
+ level: "error"
1102
+ });
1103
+ return (0, import_tooling.buildResult)(
1104
+ TOOL_ID,
1105
+ startedAt,
1106
+ /* @__PURE__ */ new Date(),
1107
+ issues,
1108
+ errors,
1109
+ ctx.targetFiles.length
1110
+ );
1111
+ }
1112
+ fileResults.push(...chunkResults);
1113
+ }
1114
+ const enabledPatterns = new Set(codacyConfig.patterns.map((p) => p.patternId));
1115
+ const fileLineCache = /* @__PURE__ */ new Map();
1116
+ for (const fileResult of fileResults) {
1117
+ if (!fileResult.violations || fileResult.violations.length === 0) continue;
1118
+ let filePath = fileResult.filepath;
1119
+ if (import_path.default.isAbsolute(filePath)) {
1120
+ filePath = import_path.default.relative(ctx.repositoryRoot, filePath);
1121
+ }
1122
+ const absPath = import_path.default.resolve(ctx.repositoryRoot, filePath);
1123
+ if (!fileLineCache.has(absPath)) {
1124
+ fileLineCache.set(absPath, await (0, import_tooling.readFileLines)(absPath));
1125
+ }
1126
+ const fileLines = fileLineCache.get(absPath);
1127
+ for (const violation of fileResult.violations) {
1128
+ const patternId = CODE_TO_PATTERN.get(violation.code);
1129
+ if (!patternId) {
1130
+ ctx.logger.debug("Skipping unknown rule code", { code: violation.code });
1131
+ continue;
1132
+ }
1133
+ if (enabledPatterns.size > 0 && !enabledPatterns.has(patternId)) continue;
1134
+ const meta = ruleMetadata(patternId);
1135
+ const line = violation.start_line_no;
1136
+ const endLine = violation.end_line_no;
1137
+ issues.push({
1138
+ filePath,
1139
+ patternId,
1140
+ toolId: TOOL_ID,
1141
+ line,
1142
+ column: violation.start_line_pos,
1143
+ endLine,
1144
+ endColumn: violation.end_line_pos,
1145
+ message: violation.description,
1146
+ lineContent: (0, import_tooling.getLineContent)(fileLines, line),
1147
+ multilineContent: (0, import_tooling.getMultilineContent)(fileLines, line, endLine),
1148
+ category: meta.category,
1149
+ severity: meta.severity
1150
+ });
1151
+ }
1152
+ }
1153
+ } catch (err) {
1154
+ errors.push({
1155
+ toolId: TOOL_ID,
1156
+ phase: "toolInvoke",
1157
+ kind: "InvocationError",
1158
+ message: `Failed to run sqlfluff: ${err instanceof Error ? err.message : String(err)}`,
1159
+ level: "error"
1160
+ });
1161
+ }
1162
+ const result = (0, import_tooling.buildResult)(
1163
+ TOOL_ID,
1164
+ startedAt,
1165
+ /* @__PURE__ */ new Date(),
1166
+ issues,
1167
+ errors,
1168
+ ctx.targetFiles.length
1169
+ );
1170
+ ctx.logger.info("Analysis complete", {
1171
+ toolId: TOOL_ID,
1172
+ issueCount: result.summary.issueCount,
1173
+ errorCount: result.summary.errorCount,
1174
+ durationMs: Date.now() - startMs
1175
+ });
1176
+ return result;
1177
+ }
1178
+ };
1179
+
1180
+ // src/index.ts
1181
+ var index_default = (0, import_tooling2.defineToolAdapter)(adapter);
@@ -0,0 +1,13 @@
1
+ import { AdapterDescriptor } from '@codacy/tooling';
2
+
3
+ /**
4
+ * Lightweight adapter descriptor for lazy loading.
5
+ *
6
+ * This module contains only plain-data metadata fields and has zero heavy
7
+ * imports (no patterns.json, no runtime utilities). The CLI imports this
8
+ * at startup for adapter registration without loading the full adapter module.
9
+ */
10
+
11
+ declare const descriptor: AdapterDescriptor;
12
+
13
+ export { descriptor };
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/metadata.ts
21
+ var metadata_exports = {};
22
+ __export(metadata_exports, {
23
+ descriptor: () => descriptor
24
+ });
25
+ module.exports = __toCommonJS(metadata_exports);
26
+ var descriptor = {
27
+ id: "SQLFluff",
28
+ displayName: "SQLFluff",
29
+ preferredVersion: "4.2.2",
30
+ languages: ["SQL"],
31
+ filePatterns: ["**/*.sql"],
32
+ supportedOS: ["linux", "darwin", "win32"],
33
+ supportedArch: ["x64", "arm64"],
34
+ supportedRunners: ["local", "container"]
35
+ };
36
+ // Annotate the CommonJS export names for ESM import in node:
37
+ 0 && (module.exports = {
38
+ descriptor
39
+ });
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@codacy/tools-sqlfluff-4",
3
+ "version": "0.6.0",
4
+ "description": "SQLFluff adapter — CLI-mode SQL linter",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "dependencies": {
11
+ "@codacy/tooling": "0.22.0"
12
+ },
13
+ "license": "MIT",
14
+ "author": "Codacy <support@codacy.com> (https://www.codacy.com)",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/codacy/analysis-cli.git",
18
+ "directory": "packages/tools/sqlfluff-4"
19
+ },
20
+ "homepage": "https://github.com/codacy/analysis-cli",
21
+ "engines": {
22
+ "node": ">=20.0.0"
23
+ },
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "default": "./dist/index.js"
28
+ },
29
+ "./metadata": {
30
+ "types": "./dist/metadata.d.ts",
31
+ "default": "./dist/metadata.js"
32
+ }
33
+ },
34
+ "scripts": {
35
+ "build": "tsup src/index.ts src/metadata.ts --format cjs --dts --clean",
36
+ "test": "vitest run",
37
+ "lint": "eslint src/",
38
+ "clean": "rm -rf dist",
39
+ "prefetch": "node ../scripts/fetch-patterns.mjs eebd5ab6-3bef-4192-843c-f52bc4dce861 src/patterns.json"
40
+ }
41
+ }