Skip to main content

thread_language/
constants.rs

1// SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>
2// SPDX-FileContributor: Adam Poulemanos <adam@knit.li>
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later
5
6use crate::SupportLang;
7
8pub const ALL_SUPPORTED_LANGS: [&str; 26] = [
9    "bash",
10    "c",
11    "cpp",
12    "csharp",
13    "css",
14    "elixir",
15    "go",
16    "haskell",
17    "hcl",
18    "html",
19    "java",
20    "javascript",
21    "json",
22    "kotlin",
23    "lua",
24    "nix",
25    "php",
26    "python",
27    "rust",
28    "ruby",
29    "scala",
30    "solidity",
31    "swift",
32    "typescript",
33    "tsx",
34    "yaml",
35];
36
37#[cfg(any(feature = "bash", feature = "all-parsers"))]
38pub const BASH_EXTS: [&str; 18] = [
39    "bash",
40    "bats",
41    "sh",
42    ".bashrc",
43    "bash_aliases",
44    "cgi",
45    "command",
46    "env",
47    "fcgi",
48    "ksh",
49    "tmux",
50    "tool",
51    "zsh",
52    "bash_logout",
53    "bash_profile",
54    "profile",
55    "login",
56    "logout",
57];
58
59// C++ is more popular, at least according to GitHub's language stats,
60// so we prioritize it over C for the 'h' filetype when both are enabled.
61cfg_if::cfg_if! {
62    if #[cfg(all(feature = "c", not(feature = "cpp")))] {
63        pub const C_EXTS: [&'static str; 2] = ["c", "h"];
64    } else if #[cfg(any(feature = "c", feature = "all-parsers"))] {
65        pub const C_EXTS: [&str; 1] = ["c"];
66    }
67}
68
69/// C++ specific extensions; we consider cuda c++ for our purposes
70#[cfg(any(feature = "cpp", feature = "all-parsers"))]
71pub const CPP_EXTS: [&str; 10] = [
72    "cpp", "cc", "cxx", "hpp", "hxx", "c++", "hh", "cu", "ino", "h",
73];
74
75#[cfg(any(feature = "csharp", feature = "all-parsers"))]
76pub const CSHARP_EXTS: [&str; 2] = ["cs", "csx"];
77
78#[cfg(any(
79    feature = "css",
80    feature = "all-parsers",
81    feature = "css-napi",
82    feature = "napi-compatible"
83))]
84pub const CSS_EXTS: [&str; 2] = ["css", "scss"];
85
86#[cfg(any(feature = "elixir", feature = "all-parsers"))]
87pub const ELIXIR_EXTS: [&str; 2] = ["ex", "exs"];
88
89#[cfg(any(feature = "go", feature = "all-parsers"))]
90pub const GO_EXTS: [&str; 1] = ["go"];
91
92#[cfg(any(feature = "haskell", feature = "all-parsers"))]
93pub const HASKELL_EXTS: [&str; 2] = ["hs", "lhs"];
94
95#[cfg(any(feature = "hcl", feature = "all-parsers"))]
96pub const HCL_EXTS: [&str; 6] = ["hcl", "nomad", "tf", "tfvars", "tfstate", "workflow"];
97
98#[cfg(any(
99    feature = "html",
100    feature = "all-parsers",
101    feature = "html-napi",
102    feature = "napi-compatible"
103))]
104pub const HTML_EXTS: [&str; 4] = ["html", "htm", "xhtml", "shtml"];
105
106#[cfg(any(feature = "java", feature = "all-parsers"))]
107pub const JAVA_EXTS: [&str; 1] = ["java"];
108
109#[cfg(any(
110    feature = "javascript",
111    feature = "all-parsers",
112    feature = "javascript-napi",
113    feature = "napi-compatible"
114))]
115pub const JAVASCRIPT_EXTS: [&str; 5] = ["js", "mjs", "cjs", "jsx", "snap"];
116
117#[cfg(any(feature = "json", feature = "all-parsers"))]
118pub const JSON_EXTS: [&str; 3] = ["json", "json5", "jsonc"];
119
120#[cfg(any(feature = "kotlin", feature = "all-parsers"))]
121pub const KOTLIN_EXTS: [&str; 3] = ["kt", "kts", "ktm"];
122
123#[cfg(any(feature = "lua", feature = "all-parsers"))]
124pub const LUA_EXTS: [&str; 1] = ["lua"];
125
126#[cfg(any(feature = "nix", feature = "all-parsers"))]
127pub const NIX_EXTS: [&str; 1] = ["nix"];
128
129#[cfg(any(feature = "php", feature = "all-parsers"))]
130pub const PHP_EXTS: [&str; 2] = ["php", "phtml"];
131
132#[cfg(any(feature = "python", feature = "all-parsers"))]
133pub const PYTHON_EXTS: [&str; 4] = ["py", "py3", "pyi", "bzl"];
134
135#[cfg(any(feature = "ruby", feature = "all-parsers"))]
136pub const RUBY_EXTS: [&str; 4] = ["rb", "rbw", "rake", "gemspec"];
137
138#[cfg(any(feature = "rust", feature = "all-parsers"))]
139pub const RUST_EXTS: [&str; 1] = ["rs"];
140
141#[cfg(any(feature = "scala", feature = "all-parsers"))]
142pub const SCALA_EXTS: [&str; 4] = ["scala", "sc", "scm", "sbt"];
143
144#[cfg(any(feature = "solidity", feature = "all-parsers"))]
145pub const SOLIDITY_EXTS: [&str; 1] = ["sol"];
146
147#[cfg(any(feature = "swift", feature = "all-parsers"))]
148pub const SWIFT_EXTS: [&str; 2] = ["swift", "xctest"];
149
150#[cfg(any(
151    feature = "typescript",
152    feature = "all-parsers",
153    feature = "typescript-napi",
154    feature = "napi-compatible"
155))]
156pub const TYPESCRIPT_EXTS: [&str; 3] = ["ts", "cts", "mts"];
157
158#[cfg(any(
159    feature = "tsx",
160    feature = "all-parsers",
161    feature = "tsx-napi",
162    feature = "napi-compatible"
163))]
164pub const TSX_EXTS: [&str; 1] = ["tsx"];
165
166#[cfg(any(feature = "yaml", feature = "all-parsers"))]
167pub const YAML_EXTS: [&str; 2] = ["yaml", "yml"];
168
169cfg_if::cfg_if!(
170    if #[cfg(
171            not(
172                any(
173                    feature = "bash", feature = "c", feature = "cpp",
174                    feature = "csharp", feature = "css", feature = "elixir",
175                    feature = "go", feature = "haskell", feature = "hcl", feature = "html",
176                    feature = "java", feature = "javascript", feature = "json",
177                    feature = "kotlin", feature = "lua", feature = "nix", feature = "php",
178                    feature = "python", feature = "ruby", feature = "rust",
179                    feature = "scala", feature = "solidity", feature = "swift", feature = "tsx",
180                    feature = "typescript", feature = "yaml"
181                    )
182                )
183    )] {
184        pub const ENABLED_LANGS: &[&crate::SupportLang; 1] = &[&crate::SupportLang::NoEnabledLangs];
185    } else {
186    pub const ENABLED_LANGS: &[&SupportLang] = &{
187        // Count total enabled languages
188        use crate::SupportLang::*;
189        const fn count_enabled_langs() -> usize {
190
191            let mut count = 0;
192
193            #[cfg(any(feature = "bash", feature = "all-parsers"))]
194            { count += 1; }
195            #[cfg(any(feature = "c", feature = "all-parsers"))]
196            { count += 1; }
197            #[cfg(any(feature = "cpp", feature = "all-parsers"))]
198            { count += 1; }
199            #[cfg(any(feature = "csharp", feature = "all-parsers"))]
200            { count += 1; }
201            #[cfg(any(feature = "css", feature = "all-parsers", feature = "css-napi", feature = "napi-compatible"))]
202            { count += 1; }
203            #[cfg(any(feature = "elixir", feature = "all-parsers"))]
204            { count += 1; }
205            #[cfg(any(feature = "go", feature = "all-parsers"))]
206            { count += 1; }
207            #[cfg(any(feature = "haskell", feature = "all-parsers"))]
208            { count += 1; }
209            #[cfg(any(feature = "hcl", feature = "all-parsers"))]
210            { count += 1; }
211            #[cfg(any(feature = "html", feature = "all-parsers", feature = "html-napi", feature = "napi-compatible"))]
212            { count += 1; }
213            #[cfg(any(feature = "java", feature = "all-parsers"))]
214            { count += 1; }
215            #[cfg(any(feature = "javascript", feature = "all-parsers", feature = "javascript-napi", feature = "napi-compatible"))]
216            { count += 1; }
217            #[cfg(any(feature = "json", feature = "all-parsers"))]
218            { count += 1; }
219            #[cfg(any(feature = "kotlin", feature = "all-parsers"))]
220            { count += 1; }
221            #[cfg(any(feature = "lua", feature = "all-parsers"))]
222            { count += 1; }
223            #[cfg(any(feature = "nix", feature = "all-parsers"))]
224            { count += 1; }
225            #[cfg(any(feature = "php", feature = "all-parsers"))]
226            { count += 1; }
227            #[cfg(any(feature = "python", feature = "all-parsers"))]
228            { count += 1; }
229            #[cfg(any(feature = "ruby", feature = "all-parsers"))]
230            { count += 1; }
231            #[cfg(any(feature = "rust", feature = "all-parsers"))]
232            { count += 1; }
233            #[cfg(any(feature = "scala", feature = "all-parsers"))]
234            { count += 1; }
235            #[cfg(any(feature = "solidity", feature = "all-parsers"))]
236            { count += 1; }
237            #[cfg(any(feature = "swift", feature = "all-parsers"))]
238            { count += 1; }
239            #[cfg(any(feature = "typescript", feature = "all-parsers", feature = "typescript-napi", feature = "napi-compatible"))]
240            { count += 1; }
241            #[cfg(any(feature = "tsx", feature = "all-parsers", feature = "tsx-napi", feature = "napi-compatible"))]
242            {
243                count += 1;
244            }
245            #[cfg(any(feature = "yaml", feature = "all-parsers"))]
246            { count += 1; }
247
248            count
249        }
250
251        // Build the enabled languages array at compile time
252        const fn build_enabled_langs_array() -> [&'static SupportLang; count_enabled_langs()] {
253
254            let mut result: [&'static SupportLang; count_enabled_langs()] =
255                [&SupportLang::all_langs()[0]; count_enabled_langs()];
256
257                let mut index: usize = 0;
258
259                #[cfg(any(feature = "bash", feature = "all-parsers"))] {
260                    result[index] = &Bash;
261                    index += 1;
262                }
263                #[cfg(any(feature = "c", feature = "all-parsers"))] {
264                    result[index] = &C;
265                    index += 1;
266                }
267                #[cfg(any(feature = "cpp", feature = "all-parsers"))] {
268                    result[index] = &Cpp;
269                    index += 1;
270                }
271                #[cfg(any(feature = "csharp", feature = "all-parsers"))] {
272                    result[index] = &CSharp;
273                    index += 1;
274                }
275                #[cfg(any(feature = "css", feature = "all-parsers", feature = "css-napi", feature = "napi-compatible"))] {
276                    result[index] = &Css;
277                    index += 1;
278                }
279                #[cfg(any(feature = "elixir", feature = "all-parsers"))] {
280                    result[index] = &Elixir;
281                    index += 1;
282                }
283                #[cfg(any(feature = "go", feature = "all-parsers"))] {
284                    result[index] = &Go;
285                    index += 1;
286                }
287                #[cfg(any(feature = "haskell", feature = "all-parsers"))] {
288                    result[index] = &Haskell;
289                    index += 1;
290                }
291                #[cfg(any(feature = "hcl", feature = "all-parsers"))] {
292                    result[index] = &Hcl;
293                    index += 1;
294                }
295                #[cfg(any(feature = "html", feature = "all-parsers", feature = "html-napi", feature = "napi-compatible"))] {
296                    result[index] = &Html;
297                    index += 1;
298                }
299                #[cfg(any(feature = "java", feature = "all-parsers"))] {
300                    result[index] = &Java;
301                    index += 1;
302                }
303                #[cfg(any(feature = "javascript", feature = "all-parsers", feature = "javascript-napi", feature = "napi-compatible"))] {
304                    result[index] = &JavaScript;
305                    index += 1;
306                }
307                #[cfg(any(feature = "json", feature = "all-parsers"))] {
308                    result[index] = &Json;
309                    index += 1;
310                }
311                #[cfg(any(feature = "kotlin", feature = "all-parsers"))] {
312                    result[index] = &Kotlin;
313                    index += 1;
314                }
315                #[cfg(any(feature = "lua", feature = "all-parsers"))] {
316                    result[index] = &Lua;
317                    index += 1;
318                }
319                #[cfg(any(feature = "nix", feature = "all-parsers"))] {
320                    result[index] = &Nix;
321                    index += 1;
322                }
323                #[cfg(any(feature = "php", feature = "all-parsers"))] {
324                    result[index] = &Php;
325                    index += 1;
326                }
327                #[cfg(any(feature = "python", feature = "all-parsers"))] {
328                    result[index] = &Python;
329                    index += 1;
330                }
331                #[cfg(any(feature = "ruby", feature = "all-parsers"))] {
332                    result[index] = &Ruby;
333                    index += 1;
334                }
335                #[cfg(any(feature = "rust", feature = "all-parsers"))] {
336                    result[index] = &Rust;
337                    index += 1;
338                }
339                #[cfg(any(feature = "scala", feature = "all-parsers"))] {
340                    result[index] = &Scala;
341                    index += 1;
342                }
343                #[cfg(any(feature = "solidity", feature = "all-parsers"))] {
344                    result[index] = &Solidity;
345                    index += 1;
346                }
347                #[cfg(any(feature = "swift", feature = "all-parsers"))] {
348                    result[index] = &Swift;
349                    index += 1;
350                }
351                #[cfg(any(feature = "typescript", feature = "all-parsers", feature = "typescript-napi", feature = "napi-compatible"))] {
352                    result[index] = &TypeScript;
353                    index += 1;
354                }
355                #[cfg(any(feature = "tsx", feature = "all-parsers", feature = "tsx-napi", feature = "napi-compatible"))]
356                {
357                    result[index] = &Tsx;
358                    index += 1;
359                }
360                #[cfg(any(feature = "yaml", feature = "all-parsers"))] {
361                    result[index] = &Yaml;
362                    index += 1;
363                }
364                let _ = index; // Mark index as used to avoid unused assignment warning
365                result
366            }
367        build_enabled_langs_array()
368    };
369});
370
371cfg_if::cfg_if!(
372    if #[cfg(
373            not(
374                any(feature = "all-parsers", feature = "napi-compatible", feature = "css-napi", feature = "html-napi", feature = "javascript-napi", feature = "typescript-napi", feature = "tsx-napi",
375                    feature = "bash", feature = "c", feature = "cpp",
376                    feature = "csharp", feature = "css", feature = "elixir",
377                    feature = "go", feature = "haskell", feature = "hcl", feature = "html",
378                    feature = "java", feature = "javascript", feature = "json",
379                    feature = "kotlin", feature = "lua", feature = "nix", feature = "php",
380                    feature = "python", feature = "ruby", feature = "rust",
381                    feature = "scala", feature = "solidity", feature = "swift", feature = "tsx",
382                    feature = "typescript", feature = "yaml"
383                    )
384                )
385            )] {
386                pub const EXTENSIONS: &[&'static &str; 0] = &[];
387            } else {
388            pub const EXTENSIONS: &[&str] = &{
389                // Count total extensions needed
390                const fn count_total_extensions() -> usize {
391                    let mut count = 0;
392
393                    #[cfg(any(feature = "bash", feature = "all-parsers"))]
394                    { count += BASH_EXTS.len(); }
395
396                    #[cfg(all(feature = "c", not(feature = "cpp")))]
397                    { count += C_EXTS.len(); }
398                    #[cfg(all(feature = "c", feature = "cpp"))]
399                    { count += C_EXTS.len(); }
400
401                    #[cfg(any(feature = "cpp", feature = "all-parsers"))]
402                    { count += CPP_EXTS.len(); }
403
404                    #[cfg(any(feature = "csharp", feature = "all-parsers"))]
405                    { count += CSHARP_EXTS.len(); }
406
407                    #[cfg(any(feature = "css", feature = "all-parsers", feature = "css-napi", feature = "napi-compatible"))]
408                    { count += CSS_EXTS.len(); }
409
410                    #[cfg(any(feature = "elixir", feature = "all-parsers"))]
411                    { count += ELIXIR_EXTS.len(); }
412
413                    #[cfg(any(feature = "go", feature = "all-parsers"))]
414                    { count += GO_EXTS.len(); }
415
416                    #[cfg(any(feature = "haskell", feature = "all-parsers"))]
417                    { count += HASKELL_EXTS.len(); }
418
419                    #[cfg(any(feature = "hcl", feature = "all-parsers"))]
420                    { count += HCL_EXTS.len(); }
421
422                    #[cfg(any(feature = "html", feature = "all-parsers", feature = "html-napi", feature = "napi-compatible"))]
423                    { count += HTML_EXTS.len(); }
424
425                    #[cfg(any(feature = "java", feature = "all-parsers"))]
426                    { count += JAVA_EXTS.len(); }
427
428                    #[cfg(any(feature = "javascript", feature = "all-parsers", feature = "javascript-napi", feature = "napi-compatible"))]
429                    { count += JAVASCRIPT_EXTS.len(); }
430
431                    #[cfg(any(feature = "json", feature = "all-parsers"))]
432                    { count += JSON_EXTS.len(); }
433
434                    #[cfg(any(feature = "kotlin", feature = "all-parsers"))]
435                    { count += KOTLIN_EXTS.len(); }
436
437                    #[cfg(any(feature = "lua", feature = "all-parsers"))]
438                    { count += LUA_EXTS.len(); }
439
440                    #[cfg(any(feature = "nix", feature = "all-parsers"))]
441                    { count += NIX_EXTS.len(); }
442
443                    #[cfg(any(feature = "php", feature = "all-parsers"))]
444                    { count += PHP_EXTS.len(); }
445
446                    #[cfg(any(feature = "python", feature = "all-parsers"))]
447                    { count += PYTHON_EXTS.len(); }
448
449                    #[cfg(any(feature = "ruby", feature = "all-parsers"))]
450                    { count += RUBY_EXTS.len(); }
451
452                    #[cfg(any(feature = "rust", feature = "all-parsers"))]
453                    { count += RUST_EXTS.len(); }
454
455                    #[cfg(any(feature = "scala", feature = "all-parsers"))]
456                    { count += SCALA_EXTS.len(); }
457
458                    #[cfg(any(feature = "solidity", feature = "all-parsers"))]
459                    { count += SOLIDITY_EXTS.len(); }
460
461                    #[cfg(any(feature = "swift", feature = "all-parsers"))]
462                    { count += SWIFT_EXTS.len(); }
463
464                    #[cfg(any(feature = "typescript", feature = "all-parsers", feature = "typescript-napi", feature = "napi-compatible"))]
465                    { count += TYPESCRIPT_EXTS.len(); }
466
467                    #[cfg(any(feature = "tsx", feature = "all-parsers", feature = "tsx-napi", feature = "napi-compatible"))]
468                    { count += TSX_EXTS.len(); }
469
470                    #[cfg(any(feature = "yaml", feature = "all-parsers"))]
471                    { count += YAML_EXTS.len(); }
472
473                    count
474                }
475
476                // Build the flattened array at compile time
477                const fn build_extensions_array() -> [&'static str; count_total_extensions()] {
478                    let mut result = [""; count_total_extensions()];
479                    let mut index = 0;
480
481                    #[cfg(any(feature = "bash", feature = "all-parsers"))]
482                    {
483                        let mut i = 0;
484                        while i < BASH_EXTS.len() {
485                            result[index] = BASH_EXTS[i];
486                            index += 1;
487                            i += 1;
488                        }
489                    }
490
491                    #[cfg(all(feature = "c", not(feature = "cpp")))]
492                    {
493                        let mut i = 0;
494                        while i < C_EXTS.len() {
495                            result[index] = C_EXTS[i];
496                            index += 1;
497                            i += 1;
498                        }
499                    }
500                    #[cfg(all(feature = "c", feature = "cpp"))]
501                    {
502                        let mut i = 0;
503                        while i < C_EXTS.len() {
504                            result[index] = C_EXTS[i];
505                            index += 1;
506                            i += 1;
507                        }
508                    }
509
510                    #[cfg(any(feature = "cpp", feature = "all-parsers"))]
511                    {
512                        let mut i = 0;
513                        while i < CPP_EXTS.len() {
514                            result[index] = CPP_EXTS[i];
515                            index += 1;
516                            i += 1;
517                        }
518                    }
519
520                    #[cfg(any(feature = "csharp", feature = "all-parsers"))]
521                    {
522                        let mut i = 0;
523                        while i < CSHARP_EXTS.len() {
524                            result[index] = CSHARP_EXTS[i];
525                            index += 1;
526                            i += 1;
527                        }
528                    }
529
530                    #[cfg(any(feature = "css", feature = "all-parsers", feature = "css-napi", feature = "napi-compatible"))]
531                    {
532                        let mut i = 0;
533                        while i < CSS_EXTS.len() {
534                            result[index] = CSS_EXTS[i];
535                            index += 1;
536                            i += 1;
537                        }
538                    }
539
540                    #[cfg(any(feature = "elixir", feature = "all-parsers"))]
541                    {
542                        let mut i = 0;
543                        while i < ELIXIR_EXTS.len() {
544                            result[index] = ELIXIR_EXTS[i];
545                            index += 1;
546                            i += 1;
547                        }
548                    }
549
550                    #[cfg(any(feature = "go", feature = "all-parsers"))]
551                    {
552                        let mut i = 0;
553                        while i < GO_EXTS.len() {
554                            result[index] = GO_EXTS[i];
555                            index += 1;
556                            i += 1;
557                        }
558                    }
559
560                    #[cfg(any(feature = "haskell", feature = "all-parsers"))]
561                    {
562                        let mut i = 0;
563                        while i < HASKELL_EXTS.len() {
564                            result[index] = HASKELL_EXTS[i];
565                            index += 1;
566                            i += 1;
567                        }
568                    }
569
570                    #[cfg(any(feature = "hcl", feature = "all-parsers"))]
571                    {
572                        let mut i = 0;
573                        while i < HCL_EXTS.len() {
574                            result[index] = HCL_EXTS[i];
575                            index += 1;
576                            i += 1;
577                        }
578                    }
579
580                    #[cfg(any(feature = "html", feature = "all-parsers", feature = "html-napi", feature = "napi-compatible"))]
581                    {
582                        let mut i = 0;
583                        while i < HTML_EXTS.len() {
584                            result[index] = HTML_EXTS[i];
585                            index += 1;
586                            i += 1;
587                        }
588                    }
589
590                    #[cfg(any(feature = "java", feature = "all-parsers"))]
591                    {
592                        let mut i = 0;
593                        while i < JAVA_EXTS.len() {
594                            result[index] = JAVA_EXTS[i];
595                            index += 1;
596                            i += 1;
597                        }
598                    }
599
600                    #[cfg(any(feature = "javascript", feature = "all-parsers", feature = "javascript-napi", feature = "napi-compatible"))]
601                    {
602                        let mut i = 0;
603                        while i < JAVASCRIPT_EXTS.len() {
604                            result[index] = JAVASCRIPT_EXTS[i];
605                            index += 1;
606                            i += 1;
607                        }
608                    }
609
610                    #[cfg(any(feature = "json", feature = "all-parsers"))]
611                    {
612                        let mut i = 0;
613                        while i < JSON_EXTS.len() {
614                            result[index] = JSON_EXTS[i];
615                            index += 1;
616                            i += 1;
617                        }
618                    }
619
620                    #[cfg(any(feature = "kotlin", feature = "all-parsers"))]
621                    {
622                        let mut i = 0;
623                        while i < KOTLIN_EXTS.len() {
624                            result[index] = KOTLIN_EXTS[i];
625                            index += 1;
626                            i += 1;
627                        }
628                    }
629
630                    #[cfg(any(feature = "lua", feature = "all-parsers"))]
631                    {
632                        let mut i = 0;
633                        while i < LUA_EXTS.len() {
634                            result[index] = LUA_EXTS[i];
635                            index += 1;
636                            i += 1;
637                        }
638                    }
639
640                    #[cfg(any(feature = "nix", feature = "all-parsers"))]
641                    {
642                        let mut i = 0;
643                        while i < NIX_EXTS.len() {
644                            result[index] = NIX_EXTS[i];
645                            index += 1;
646                            i += 1;
647                        }
648                    }
649
650                    #[cfg(any(feature = "php", feature = "all-parsers"))]
651                    {
652                        let mut i = 0;
653                        while i < PHP_EXTS.len() {
654                            result[index] = PHP_EXTS[i];
655                            index += 1;
656                            i += 1;
657                        }
658                    }
659
660                    #[cfg(any(feature = "python", feature = "all-parsers"))]
661                    {
662                        let mut i = 0;
663                        while i < PYTHON_EXTS.len() {
664                            result[index] = PYTHON_EXTS[i];
665                            index += 1;
666                            i += 1;
667                        }
668                    }
669
670                    #[cfg(any(feature = "ruby", feature = "all-parsers"))]
671                    {
672                        let mut i = 0;
673                        while i < RUBY_EXTS.len() {
674                            result[index] = RUBY_EXTS[i];
675                            index += 1;
676                            i += 1;
677                        }
678                    }
679
680                    #[cfg(any(feature = "rust", feature = "all-parsers"))]
681                    {
682                        let mut i = 0;
683                        while i < RUST_EXTS.len() {
684                            result[index] = RUST_EXTS[i];
685                            index += 1;
686                            i += 1;
687                        }
688                    }
689
690                    #[cfg(any(feature = "scala", feature = "all-parsers"))]
691                    {
692                        let mut i = 0;
693                        while i < SCALA_EXTS.len() {
694                            result[index] = SCALA_EXTS[i];
695                            index += 1;
696                            i += 1;
697                        }
698                    }
699
700                    #[cfg(any(feature = "solidity", feature = "all-parsers"))]
701                    {
702                        let mut i = 0;
703                        while i < SOLIDITY_EXTS.len() {
704                            result[index] = SOLIDITY_EXTS[i];
705                            index += 1;
706                            i += 1;
707                        }
708                    }
709
710                    #[cfg(any(feature = "swift", feature = "all-parsers"))]
711                    {
712                        let mut i = 0;
713                        while i < SWIFT_EXTS.len() {
714                            result[index] = SWIFT_EXTS[i];
715                            index += 1;
716                            i += 1;
717                        }
718                    }
719
720                    #[cfg(any(feature = "typescript", feature = "all-parsers", feature = "typescript-napi", feature = "napi-compatible"))]
721                    {
722                        let mut i = 0;
723                        while i < TYPESCRIPT_EXTS.len() {
724                            result[index] = TYPESCRIPT_EXTS[i];
725                            index += 1;
726                            i += 1;
727                        }
728                    }
729
730                    #[cfg(any(feature = "tsx", feature = "all-parsers", feature = "tsx-napi", feature = "napi-compatible"))]
731                    {
732                        let mut i = 0;
733                        while i < TSX_EXTS.len() {
734                            result[index] = TSX_EXTS[i];
735                            index += 1;
736                            i += 1;
737                        }
738                    }
739
740                    #[cfg(any(feature = "yaml", feature = "all-parsers"))]
741                    {
742                        let mut i = 0;
743                        while i < YAML_EXTS.len() {
744                            result[index] = YAML_EXTS[i];
745                            index += 1;
746                            i += 1;
747                        }
748                    }
749
750                    let _ = index; // Mark index as used to avoid unused assignment warning
751                    result
752                }
753
754                build_extensions_array()
755            };
756
757            }
758);
759
760// Generate the flattened extensions array at compile time using const evaluation
761
762// Language lookup array for direct O(1) access from Aho-Corasick match indices.
763// Each language is repeated for each of its extensions in the same order as EXTENSIONS.
764// This allows us to directly map from a match index to the corresponding SupportLang.
765cfg_if::cfg_if!(
766        if #[cfg(
767            not(
768                any(
769                    feature = "bash", feature = "c", feature = "cpp",
770                    feature = "csharp", feature = "css", feature = "elixir",
771                    feature = "go", feature = "haskell", feature = "hcl", feature = "html",
772                    feature = "java", feature = "javascript", feature = "json",
773                    feature = "kotlin", feature = "lua", feature = "nix", feature = "php",
774                    feature = "python", feature = "ruby", feature = "rust",
775                    feature = "scala", feature = "solidity", feature = "swift", feature = "tsx",
776                    feature = "typescript", feature = "yaml", feature = "napi-compatible", feature = "css-napi", feature = "html-napi", feature = "javascript-napi", feature = "tsx-napi", feature = "typescript-napi"
777                    )
778                )
779            )] {
780                pub const EXTENSION_TO_LANG: &[SupportLang; 1] = &[crate::SupportLang::NoEnabledLangs];
781            } else {
782            pub const EXTENSION_TO_LANG: &[SupportLang] = &{
783                use crate::SupportLang;
784
785                // Count total extensions needed (same as EXTENSIONS array)
786                const fn count_total_extensions() -> usize {
787                    let mut count = 0;
788
789                    #[cfg(any(feature = "bash", feature = "all-parsers"))]
790                    { count += BASH_EXTS.len(); }
791
792                    #[cfg(any(feature = "c", feature = "all-parsers"))]
793                    { count += C_EXTS.len(); }
794
795                    #[cfg(any(feature = "cpp", feature = "all-parsers"))]
796                    { count += CPP_EXTS.len(); }
797
798                    #[cfg(any(feature = "csharp", feature = "all-parsers"))]
799                    { count += CSHARP_EXTS.len(); }
800
801                    #[cfg(any(feature = "css", feature = "all-parsers", feature = "css-napi", feature = "napi-compatible"))]
802                    { count += CSS_EXTS.len(); }
803
804                    #[cfg(any(feature = "elixir", feature = "all-parsers"))]
805                    { count += ELIXIR_EXTS.len(); }
806
807                    #[cfg(any(feature = "go", feature = "all-parsers"))]
808                    { count += GO_EXTS.len(); }
809
810                    #[cfg(any(feature = "haskell", feature = "all-parsers"))]
811                    { count += HASKELL_EXTS.len(); }
812
813                    #[cfg(any(feature = "hcl", feature = "all-parsers"))]
814                    { count += HCL_EXTS.len(); }
815
816                    #[cfg(any(feature = "html", feature = "all-parsers", feature = "html-napi", feature = "napi-compatible"))]
817                    { count += HTML_EXTS.len(); }
818
819                    #[cfg(any(feature = "java", feature = "all-parsers"))]
820                    { count += JAVA_EXTS.len(); }
821
822                    #[cfg(any(feature = "javascript", feature = "all-parsers", feature = "javascript-napi", feature = "napi-compatible"))]
823                    { count += JAVASCRIPT_EXTS.len(); }
824
825                    #[cfg(any(feature = "json", feature = "all-parsers"))]
826                    { count += JSON_EXTS.len(); }
827
828                    #[cfg(any(feature = "kotlin", feature = "all-parsers"))]
829                    { count += KOTLIN_EXTS.len(); }
830
831                    #[cfg(any(feature = "lua", feature = "all-parsers"))]
832                    { count += LUA_EXTS.len(); }
833
834                    #[cfg(any(feature = "nix", feature = "all-parsers"))]
835                    { count += NIX_EXTS.len(); }
836
837                    #[cfg(any(feature = "php", feature = "all-parsers"))]
838                    { count += PHP_EXTS.len(); }
839
840                    #[cfg(any(feature = "python", feature = "all-parsers"))]
841                    { count += PYTHON_EXTS.len(); }
842
843                    #[cfg(any(feature = "ruby", feature = "all-parsers"))]
844                    { count += RUBY_EXTS.len(); }
845
846                    #[cfg(any(feature = "rust", feature = "all-parsers"))]
847                    { count += RUST_EXTS.len(); }
848
849                    #[cfg(any(feature = "scala", feature = "all-parsers"))]
850                    { count += SCALA_EXTS.len(); }
851
852                    #[cfg(any(feature = "solidity", feature = "all-parsers"))]
853                    { count += SOLIDITY_EXTS.len(); }
854
855                    #[cfg(any(feature = "swift", feature = "all-parsers"))]
856                    { count += SWIFT_EXTS.len(); }
857
858                    #[cfg(any(feature = "typescript", feature = "all-parsers", feature = "typescript-napi", feature = "napi-compatible"))]
859                    { count += TYPESCRIPT_EXTS.len(); }
860
861                    #[cfg(any(feature = "tsx", feature = "all-parsers", feature = "tsx-napi", feature = "napi-compatible"))]
862                    { count += TSX_EXTS.len(); }
863
864                    #[cfg(any(feature = "yaml", feature = "all-parsers"))]
865                    { count += YAML_EXTS.len(); }
866
867                    count
868                }
869
870                // Build the language lookup array at compile time
871                const fn build_extension_to_lang_array() -> [SupportLang; count_total_extensions()] {
872                    let mut result = [SupportLang::all_langs()[0]; count_total_extensions()];
873                    let mut index = 0;
874
875                    #[cfg(any(feature = "bash", feature = "all-parsers"))]
876                    {
877                        let mut i = 0;
878                        while i < BASH_EXTS.len() {
879                            result[index] = SupportLang::Bash;
880                            index += 1;
881                            i += 1;
882                        }
883                    }
884
885                    #[cfg(any(feature = "c", feature = "all-parsers"))]
886                    {
887                        let mut i = 0;
888                        while i < C_EXTS.len() {
889                            result[index] = SupportLang::C;
890                            index += 1;
891                            i += 1;
892                        }
893                    }
894
895                    #[cfg(any(feature = "cpp", feature = "all-parsers"))]
896                    {
897                        let mut i = 0;
898                        while i < CPP_EXTS.len() {
899                            result[index] = SupportLang::Cpp;
900                            index += 1;
901                            i += 1;
902                        }
903                    }
904
905                    #[cfg(any(feature = "csharp", feature = "all-parsers"))]
906                    {
907                        let mut i = 0;
908                        while i < CSHARP_EXTS.len() {
909                            result[index] = SupportLang::CSharp;
910                            index += 1;
911                            i += 1;
912                        }
913                    }
914
915                    #[cfg(any(feature = "css", feature = "all-parsers", feature = "css-napi", feature = "napi-compatible"))]
916                    {
917                        let mut i = 0;
918                        while i < CSS_EXTS.len() {
919                            result[index] = SupportLang::Css;
920                            index += 1;
921                            i += 1;
922                        }
923                    }
924
925                    #[cfg(any(feature = "elixir", feature = "all-parsers"))]
926                    {
927                        let mut i = 0;
928                        while i < ELIXIR_EXTS.len() {
929                            result[index] = SupportLang::Elixir;
930                            index += 1;
931                            i += 1;
932                        }
933                    }
934
935                    #[cfg(any(feature = "go", feature = "all-parsers"))]
936                    {
937                        let mut i = 0;
938                        while i < GO_EXTS.len() {
939                            result[index] = SupportLang::Go;
940                            index += 1;
941                            i += 1;
942                        }
943                    }
944
945                    #[cfg(any(feature = "haskell", feature = "all-parsers"))]
946                    {
947                        let mut i = 0;
948                        while i < HASKELL_EXTS.len() {
949                            result[index] = SupportLang::Haskell;
950                            index += 1;
951                            i += 1;
952                        }
953                    }
954
955                    #[cfg(any(feature = "hcl", feature = "all-parsers"))]
956                    {
957                        let mut i = 0;
958                        while i < HCL_EXTS.len() {
959                            result[index] = SupportLang::Hcl;
960                            index += 1;
961                            i += 1;
962                        }
963                    }
964
965                    #[cfg(any(feature = "html", feature = "all-parsers", feature = "html-napi", feature = "napi-compatible"))]
966                    {
967                        let mut i = 0;
968                        while i < HTML_EXTS.len() {
969                            result[index] = SupportLang::Html;
970                            index += 1;
971                            i += 1;
972                        }
973                    }
974
975                    #[cfg(any(feature = "java", feature = "all-parsers"))]
976                    {
977                        let mut i = 0;
978                        while i < JAVA_EXTS.len() {
979                            result[index] = SupportLang::Java;
980                            index += 1;
981                            i += 1;
982                        }
983                    }
984
985                    #[cfg(any(feature = "javascript", feature = "all-parsers", feature = "javascript-napi", feature = "napi-compatible"))]
986                    {
987                        let mut i = 0;
988                        while i < JAVASCRIPT_EXTS.len() {
989                            result[index] = SupportLang::JavaScript;
990                            index += 1;
991                            i += 1;
992                        }
993                    }
994
995                    #[cfg(any(feature = "json", feature = "all-parsers"))]
996                    {
997                        let mut i = 0;
998                        while i < JSON_EXTS.len() {
999                            result[index] = SupportLang::Json;
1000                            index += 1;
1001                            i += 1;
1002                        }
1003                    }
1004
1005                    #[cfg(any(feature = "kotlin", feature = "all-parsers"))]
1006                    {
1007                        let mut i = 0;
1008                        while i < KOTLIN_EXTS.len() {
1009                            result[index] = SupportLang::Kotlin;
1010                            index += 1;
1011                            i += 1;
1012                        }
1013                    }
1014
1015                    #[cfg(any(feature = "lua", feature = "all-parsers"))]
1016                    {
1017                        let mut i = 0;
1018                        while i < LUA_EXTS.len() {
1019                            result[index] = SupportLang::Lua;
1020                            index += 1;
1021                            i += 1;
1022                        }
1023                    }
1024
1025                    #[cfg(any(feature = "nix", feature = "all-parsers"))]
1026                    {
1027                        let mut i = 0;
1028                        while i < NIX_EXTS.len() {
1029                            result[index] = SupportLang::Nix;
1030                            index += 1;
1031                            i += 1;
1032                        }
1033                    }
1034
1035                    #[cfg(any(feature = "php", feature = "all-parsers"))]
1036                    {
1037                        let mut i = 0;
1038                        while i < PHP_EXTS.len() {
1039                            result[index] = SupportLang::Php;
1040                            index += 1;
1041                            i += 1;
1042                        }
1043                    }
1044
1045                    #[cfg(any(feature = "python", feature = "all-parsers"))]
1046                    {
1047                        let mut i = 0;
1048                        while i < PYTHON_EXTS.len() {
1049                            result[index] = SupportLang::Python;
1050                            index += 1;
1051                            i += 1;
1052                        }
1053                    }
1054
1055                    #[cfg(any(feature = "ruby", feature = "all-parsers"))]
1056                    {
1057                        let mut i = 0;
1058                        while i < RUBY_EXTS.len() {
1059                            result[index] = SupportLang::Ruby;
1060                            index += 1;
1061                            i += 1;
1062                        }
1063                    }
1064
1065                    #[cfg(any(feature = "rust", feature = "all-parsers"))]
1066                    {
1067                        let mut i = 0;
1068                        while i < RUST_EXTS.len() {
1069                            result[index] = SupportLang::Rust;
1070                            index += 1;
1071                            i += 1;
1072                        }
1073                    }
1074
1075                    #[cfg(any(feature = "scala", feature = "all-parsers"))]
1076                    {
1077                        let mut i = 0;
1078                        while i < SCALA_EXTS.len() {
1079                            result[index] = SupportLang::Scala;
1080                            index += 1;
1081                            i += 1;
1082                        }
1083                    }
1084
1085                    #[cfg(any(feature = "solidity", feature = "all-parsers"))]
1086                    {
1087                        let mut i = 0;
1088                        while i < SOLIDITY_EXTS.len() {
1089                            result[index] = SupportLang::Solidity;
1090                            index += 1;
1091                            i += 1;
1092                        }
1093                    }
1094
1095                    #[cfg(any(feature = "swift", feature = "all-parsers"))]
1096                    {
1097                        let mut i = 0;
1098                        while i < SWIFT_EXTS.len() {
1099                            result[index] = SupportLang::Swift;
1100                            index += 1;
1101                            i += 1;
1102                        }
1103                    }
1104
1105                    #[cfg(any(feature = "typescript", feature = "all-parsers", feature = "typescript-napi", feature = "napi-compatible"))]
1106                    {
1107                        let mut i = 0;
1108                        while i < TYPESCRIPT_EXTS.len() {
1109                            result[index] = SupportLang::TypeScript;
1110                            index += 1;
1111                            i += 1;
1112                        }
1113                    }
1114
1115                    #[cfg(any(feature = "tsx", feature = "all-parsers", feature = "tsx-napi", feature = "napi-compatible"))]
1116                    {
1117                        let mut i = 0;
1118                        while i < TSX_EXTS.len() {
1119                            result[index] = SupportLang::Tsx;
1120                            index += 1;
1121                            i += 1;
1122                        }
1123                    }
1124
1125                    #[cfg(any(feature = "yaml", feature = "all-parsers"))]
1126                    {
1127                        let mut i = 0;
1128                        while i < YAML_EXTS.len() {
1129                            result[index] = SupportLang::Yaml;
1130                            index += 1;
1131                            i += 1;
1132                        }
1133                    }
1134
1135                    let _ = index; // Mark index as used to avoid unused assignment warning
1136                    result
1137                }
1138
1139                build_extension_to_lang_array()
1140            };
1141        }
1142);
1143
1144// ========== Constants for Planned Features ==========
1145// these aren't yet implemented
1146
1147/// List of files that DO NOT have an extension but are still associated with a language.
1148#[cfg(any(feature = "bash", feature = "all-parsers", feature = "ruby"))]
1149#[allow(dead_code)]
1150const LANG_RELATIONSHIPS_WITH_NO_EXTENSION: &[(&str, SupportLang)] = &[
1151    #[cfg(any(feature = "bash", feature = "all-parsers"))]
1152    ("profile", SupportLang::Bash),
1153    #[cfg(any(feature = "bash", feature = "all-parsers"))]
1154    ("bash_login", SupportLang::Bash),
1155    #[cfg(any(feature = "bash", feature = "all-parsers"))]
1156    ("bash_logout", SupportLang::Bash),
1157    #[cfg(any(feature = "bash", feature = "all-parsers"))]
1158    ("bashrc", SupportLang::Bash),
1159    #[cfg(any(feature = "bash", feature = "all-parsers"))]
1160    ("profile", SupportLang::Bash),
1161    #[cfg(any(feature = "ruby", feature = "all-parsers"))]
1162    ("Rakefile", SupportLang::Ruby),
1163    #[cfg(any(feature = "ruby", feature = "all-parsers"))]
1164    ("Gemfile", SupportLang::Ruby),
1165    #[cfg(any(feature = "ruby", feature = "all-parsers"))]
1166    ("config.ru", SupportLang::Ruby),
1167];
1168
1169/// Files whose presence can resolve language identification
1170#[cfg(any(all(feature = "cpp", feature = "c"), feature = "all-parsers"))]
1171#[allow(dead_code)]
1172const LANG_FILE_INDICATORS: &[(&str, SupportLang)] = &[
1173    #[cfg(any(all(feature = "cpp", feature = "c"), feature = "all-parsers"))]
1174    ("conanfile.txt", SupportLang::Cpp),
1175    #[cfg(any(all(feature = "cpp", feature = "c"), feature = "all-parsers"))]
1176    ("vcpkg.json", SupportLang::Cpp),
1177    #[cfg(any(all(feature = "cpp", feature = "c"), feature = "all-parsers"))]
1178    ("CMakeLists.txt", SupportLang::Cpp),
1179    #[cfg(any(all(feature = "cpp", feature = "c"), feature = "all-parsers"))]
1180    (".vcxproj", SupportLang::Cpp),
1181];
1182
1183#[cfg(test)]
1184mod test {
1185    use super::*;
1186
1187    #[test]
1188    fn no_duplicate_extensions() {
1189        let mut seen = std::collections::HashSet::new();
1190        for ext in EXTENSIONS {
1191            assert!(seen.insert(*ext), "Duplicate extension found: {}", ext);
1192        }
1193    }
1194}