Skip to main content

cpd_tokenizer/
formats.rs

1use std::collections::HashMap;
2use std::sync::LazyLock;
3
4#[derive(Debug, Clone)]
5pub struct FormatEntry {
6    pub name: &'static str,
7    pub extensions: &'static [&'static str],
8    pub parent: Option<&'static str>,
9}
10
11/// All supported language formats (223 entries).
12pub static SUPPORTED_FORMATS: &[FormatEntry] = &[
13    FormatEntry {
14        name: "abap",
15        extensions: &[],
16        parent: None,
17    },
18    FormatEntry {
19        name: "actionscript",
20        extensions: &["as"],
21        parent: None,
22    },
23    FormatEntry {
24        name: "ada",
25        extensions: &["ada"],
26        parent: None,
27    },
28    FormatEntry {
29        name: "apacheconf",
30        extensions: &[],
31        parent: None,
32    },
33    FormatEntry {
34        name: "apl",
35        extensions: &["apl"],
36        parent: None,
37    },
38    FormatEntry {
39        name: "applescript",
40        extensions: &[],
41        parent: None,
42    },
43    FormatEntry {
44        name: "arduino",
45        extensions: &[],
46        parent: None,
47    },
48    FormatEntry {
49        name: "arff",
50        extensions: &[],
51        parent: None,
52    },
53    FormatEntry {
54        name: "asciidoc",
55        extensions: &[],
56        parent: None,
57    },
58    FormatEntry {
59        name: "asm6502",
60        extensions: &[],
61        parent: None,
62    },
63    FormatEntry {
64        name: "aspnet",
65        extensions: &["asp", "aspx"],
66        parent: None,
67    },
68    FormatEntry {
69        name: "autohotkey",
70        extensions: &[],
71        parent: None,
72    },
73    FormatEntry {
74        name: "autoit",
75        extensions: &[],
76        parent: None,
77    },
78    FormatEntry {
79        name: "bash",
80        extensions: &["sh", "ksh", "bash"],
81        parent: None,
82    },
83    FormatEntry {
84        name: "basic",
85        extensions: &["bas"],
86        parent: None,
87    },
88    FormatEntry {
89        name: "batch",
90        extensions: &[],
91        parent: None,
92    },
93    FormatEntry {
94        name: "bison",
95        extensions: &[],
96        parent: None,
97    },
98    FormatEntry {
99        name: "brainfuck",
100        extensions: &["b", "bf"],
101        parent: None,
102    },
103    FormatEntry {
104        name: "bro",
105        extensions: &[],
106        parent: None,
107    },
108    FormatEntry {
109        name: "c",
110        extensions: &["c", "z80"],
111        parent: None,
112    },
113    FormatEntry {
114        name: "c-header",
115        extensions: &["h"],
116        parent: None,
117    },
118    FormatEntry {
119        name: "clike",
120        extensions: &[],
121        parent: None,
122    },
123    FormatEntry {
124        name: "clojure",
125        extensions: &["cljs", "clj", "cljc", "cljx", "edn"],
126        parent: None,
127    },
128    FormatEntry {
129        name: "coffeescript",
130        extensions: &["coffee"],
131        parent: None,
132    },
133    FormatEntry {
134        name: "comments",
135        extensions: &[],
136        parent: None,
137    },
138    FormatEntry {
139        name: "cpp",
140        extensions: &["cpp", "c++", "cc", "cxx"],
141        parent: None,
142    },
143    FormatEntry {
144        name: "cpp-header",
145        extensions: &["hpp", "h++", "hh", "hxx"],
146        parent: None,
147    },
148    FormatEntry {
149        name: "crystal",
150        extensions: &["cr"],
151        parent: None,
152    },
153    FormatEntry {
154        name: "csharp",
155        extensions: &["cs"],
156        parent: None,
157    },
158    FormatEntry {
159        name: "csp",
160        extensions: &[],
161        parent: None,
162    },
163    FormatEntry {
164        name: "css-extras",
165        extensions: &[],
166        parent: None,
167    },
168    FormatEntry {
169        name: "css",
170        extensions: &["css", "gss"],
171        parent: None,
172    },
173    FormatEntry {
174        name: "d",
175        extensions: &["d"],
176        parent: None,
177    },
178    FormatEntry {
179        name: "dart",
180        extensions: &["dart"],
181        parent: None,
182    },
183    FormatEntry {
184        name: "diff",
185        extensions: &["diff", "patch"],
186        parent: None,
187    },
188    FormatEntry {
189        name: "django",
190        extensions: &[],
191        parent: None,
192    },
193    FormatEntry {
194        name: "docker",
195        extensions: &[],
196        parent: None,
197    },
198    FormatEntry {
199        name: "eiffel",
200        extensions: &["e"],
201        parent: None,
202    },
203    FormatEntry {
204        name: "elixir",
205        extensions: &[],
206        parent: None,
207    },
208    FormatEntry {
209        name: "elm",
210        extensions: &["elm"],
211        parent: None,
212    },
213    FormatEntry {
214        name: "erb",
215        extensions: &[],
216        parent: None,
217    },
218    FormatEntry {
219        name: "erlang",
220        extensions: &["erl", "erlang"],
221        parent: None,
222    },
223    FormatEntry {
224        name: "flow",
225        extensions: &[],
226        parent: None,
227    },
228    FormatEntry {
229        name: "fortran",
230        extensions: &["f", "for", "f77", "f90"],
231        parent: None,
232    },
233    FormatEntry {
234        name: "fsharp",
235        extensions: &["fs"],
236        parent: None,
237    },
238    FormatEntry {
239        name: "gdscript",
240        extensions: &["gd"],
241        parent: None,
242    },
243    FormatEntry {
244        name: "gedcom",
245        extensions: &[],
246        parent: None,
247    },
248    FormatEntry {
249        name: "gherkin",
250        extensions: &["feature"],
251        parent: None,
252    },
253    FormatEntry {
254        name: "git",
255        extensions: &[],
256        parent: None,
257    },
258    FormatEntry {
259        name: "glsl",
260        extensions: &[],
261        parent: None,
262    },
263    FormatEntry {
264        name: "go",
265        extensions: &["go"],
266        parent: None,
267    },
268    FormatEntry {
269        name: "graphql",
270        extensions: &["graphql"],
271        parent: None,
272    },
273    FormatEntry {
274        name: "groovy",
275        extensions: &["groovy", "gradle"],
276        parent: None,
277    },
278    FormatEntry {
279        name: "haml",
280        extensions: &["haml"],
281        parent: None,
282    },
283    FormatEntry {
284        name: "handlebars",
285        extensions: &["hb", "hbs", "handlebars"],
286        parent: None,
287    },
288    FormatEntry {
289        name: "haskell",
290        extensions: &["hs", "lhs"],
291        parent: None,
292    },
293    FormatEntry {
294        name: "haxe",
295        extensions: &["hx", "hxml"],
296        parent: None,
297    },
298    FormatEntry {
299        name: "hpkp",
300        extensions: &[],
301        parent: None,
302    },
303    FormatEntry {
304        name: "hsts",
305        extensions: &[],
306        parent: None,
307    },
308    FormatEntry {
309        name: "http",
310        extensions: &[],
311        parent: None,
312    },
313    FormatEntry {
314        name: "ichigojam",
315        extensions: &[],
316        parent: None,
317    },
318    FormatEntry {
319        name: "icon",
320        extensions: &[],
321        parent: None,
322    },
323    FormatEntry {
324        name: "inform7",
325        extensions: &[],
326        parent: None,
327    },
328    FormatEntry {
329        name: "ini",
330        extensions: &["ini"],
331        parent: None,
332    },
333    FormatEntry {
334        name: "io",
335        extensions: &[],
336        parent: None,
337    },
338    FormatEntry {
339        name: "j",
340        extensions: &[],
341        parent: None,
342    },
343    FormatEntry {
344        name: "java",
345        extensions: &["java"],
346        parent: None,
347    },
348    FormatEntry {
349        name: "javascript",
350        extensions: &["js", "es", "es6", "mjs", "cjs"],
351        parent: None,
352    },
353    FormatEntry {
354        name: "jolie",
355        extensions: &[],
356        parent: None,
357    },
358    FormatEntry {
359        name: "json",
360        extensions: &["json", "map", "jsonld"],
361        parent: None,
362    },
363    FormatEntry {
364        name: "jsx",
365        extensions: &["jsx"],
366        parent: None,
367    },
368    FormatEntry {
369        name: "julia",
370        extensions: &["jl"],
371        parent: None,
372    },
373    FormatEntry {
374        name: "keymap",
375        extensions: &[],
376        parent: None,
377    },
378    FormatEntry {
379        name: "kotlin",
380        extensions: &["kt", "kts"],
381        parent: None,
382    },
383    FormatEntry {
384        name: "latex",
385        extensions: &["tex"],
386        parent: None,
387    },
388    FormatEntry {
389        name: "less",
390        extensions: &["less"],
391        parent: None,
392    },
393    FormatEntry {
394        name: "liquid",
395        extensions: &[],
396        parent: None,
397    },
398    FormatEntry {
399        name: "lisp",
400        extensions: &["cl", "lisp", "el"],
401        parent: None,
402    },
403    FormatEntry {
404        name: "livescript",
405        extensions: &["ls"],
406        parent: None,
407    },
408    FormatEntry {
409        name: "lolcode",
410        extensions: &[],
411        parent: None,
412    },
413    FormatEntry {
414        name: "lua",
415        extensions: &["lua"],
416        parent: None,
417    },
418    FormatEntry {
419        name: "makefile",
420        extensions: &[],
421        parent: None,
422    },
423    FormatEntry {
424        name: "markdown",
425        extensions: &["md", "markdown", "mkd"],
426        parent: None,
427    },
428    FormatEntry {
429        name: "markup",
430        extensions: &["html", "htm", "xml", "xsl", "xslt", "svg", "ejs", "jsp"],
431        parent: None,
432    },
433    FormatEntry {
434        name: "matlab",
435        extensions: &[],
436        parent: None,
437    },
438    FormatEntry {
439        name: "mel",
440        extensions: &[],
441        parent: None,
442    },
443    FormatEntry {
444        name: "mizar",
445        extensions: &[],
446        parent: None,
447    },
448    FormatEntry {
449        name: "monkey",
450        extensions: &[],
451        parent: None,
452    },
453    FormatEntry {
454        name: "n4js",
455        extensions: &[],
456        parent: None,
457    },
458    FormatEntry {
459        name: "nasm",
460        extensions: &[],
461        parent: None,
462    },
463    FormatEntry {
464        name: "nginx",
465        extensions: &[],
466        parent: None,
467    },
468    FormatEntry {
469        name: "nim",
470        extensions: &[],
471        parent: None,
472    },
473    FormatEntry {
474        name: "nix",
475        extensions: &[],
476        parent: None,
477    },
478    FormatEntry {
479        name: "nsis",
480        extensions: &["nsh", "nsi"],
481        parent: None,
482    },
483    FormatEntry {
484        name: "objectivec",
485        extensions: &["m", "mm"],
486        parent: None,
487    },
488    FormatEntry {
489        name: "ocaml",
490        extensions: &["ocaml", "ml", "mli", "mll", "mly"],
491        parent: None,
492    },
493    FormatEntry {
494        name: "opencl",
495        extensions: &[],
496        parent: None,
497    },
498    FormatEntry {
499        name: "oz",
500        extensions: &["oz"],
501        parent: None,
502    },
503    FormatEntry {
504        name: "parigp",
505        extensions: &[],
506        parent: None,
507    },
508    FormatEntry {
509        name: "pascal",
510        extensions: &["pas", "p"],
511        parent: None,
512    },
513    FormatEntry {
514        name: "perl",
515        extensions: &["pl", "pm"],
516        parent: None,
517    },
518    FormatEntry {
519        name: "php",
520        extensions: &["php", "phtml"],
521        parent: None,
522    },
523    FormatEntry {
524        name: "plsql",
525        extensions: &["plsql"],
526        parent: None,
527    },
528    FormatEntry {
529        name: "powershell",
530        extensions: &["ps1", "psd1", "psm1"],
531        parent: None,
532    },
533    FormatEntry {
534        name: "processing",
535        extensions: &[],
536        parent: None,
537    },
538    FormatEntry {
539        name: "prolog",
540        extensions: &["pro"],
541        parent: None,
542    },
543    FormatEntry {
544        name: "properties",
545        extensions: &["properties"],
546        parent: None,
547    },
548    FormatEntry {
549        name: "protobuf",
550        extensions: &["proto"],
551        parent: None,
552    },
553    FormatEntry {
554        name: "pug",
555        extensions: &["pug", "jade"],
556        parent: None,
557    },
558    FormatEntry {
559        name: "puppet",
560        extensions: &["pp", "puppet"],
561        parent: None,
562    },
563    FormatEntry {
564        name: "pure",
565        extensions: &[],
566        parent: None,
567    },
568    FormatEntry {
569        name: "python",
570        extensions: &["py", "pyx", "pxd", "pxi"],
571        parent: None,
572    },
573    FormatEntry {
574        name: "q",
575        extensions: &["q"],
576        parent: None,
577    },
578    FormatEntry {
579        name: "qore",
580        extensions: &[],
581        parent: None,
582    },
583    FormatEntry {
584        name: "r",
585        extensions: &["r", "R"],
586        parent: None,
587    },
588    FormatEntry {
589        name: "reason",
590        extensions: &[],
591        parent: None,
592    },
593    FormatEntry {
594        name: "renpy",
595        extensions: &[],
596        parent: None,
597    },
598    FormatEntry {
599        name: "rest",
600        extensions: &[],
601        parent: None,
602    },
603    FormatEntry {
604        name: "rip",
605        extensions: &[],
606        parent: None,
607    },
608    FormatEntry {
609        name: "roboconf",
610        extensions: &[],
611        parent: None,
612    },
613    FormatEntry {
614        name: "ruby",
615        extensions: &["rb"],
616        parent: None,
617    },
618    FormatEntry {
619        name: "rust",
620        extensions: &["rs"],
621        parent: None,
622    },
623    FormatEntry {
624        name: "sas",
625        extensions: &["sas"],
626        parent: None,
627    },
628    FormatEntry {
629        name: "sass",
630        extensions: &["sass"],
631        parent: None,
632    },
633    FormatEntry {
634        name: "scala",
635        extensions: &["scala"],
636        parent: None,
637    },
638    FormatEntry {
639        name: "scheme",
640        extensions: &["scm", "ss"],
641        parent: None,
642    },
643    FormatEntry {
644        name: "scss",
645        extensions: &["scss"],
646        parent: None,
647    },
648    FormatEntry {
649        name: "svelte",
650        extensions: &["svelte"],
651        parent: None,
652    },
653    FormatEntry {
654        name: "smalltalk",
655        extensions: &["st"],
656        parent: None,
657    },
658    FormatEntry {
659        name: "smarty",
660        extensions: &["smarty", "tpl"],
661        parent: None,
662    },
663    FormatEntry {
664        name: "soy",
665        extensions: &["soy"],
666        parent: None,
667    },
668    FormatEntry {
669        name: "sql",
670        extensions: &["sql", "cql"],
671        parent: None,
672    },
673    FormatEntry {
674        name: "stylus",
675        extensions: &["styl", "stylus"],
676        parent: None,
677    },
678    FormatEntry {
679        name: "swift",
680        extensions: &["swift"],
681        parent: None,
682    },
683    FormatEntry {
684        name: "tap",
685        extensions: &["tap"],
686        parent: None,
687    },
688    FormatEntry {
689        name: "tcl",
690        extensions: &["tcl"],
691        parent: None,
692    },
693    FormatEntry {
694        name: "textile",
695        extensions: &["textile"],
696        parent: None,
697    },
698    FormatEntry {
699        name: "tsx",
700        extensions: &["tsx"],
701        parent: None,
702    },
703    FormatEntry {
704        name: "tt2",
705        extensions: &["tt2"],
706        parent: None,
707    },
708    FormatEntry {
709        name: "twig",
710        extensions: &["twig"],
711        parent: None,
712    },
713    FormatEntry {
714        name: "typescript",
715        extensions: &["ts", "mts", "cts"],
716        parent: None,
717    },
718    FormatEntry {
719        name: "txt",
720        extensions: &["txt"],
721        parent: None,
722    },
723    FormatEntry {
724        name: "vbnet",
725        extensions: &["vb"],
726        parent: None,
727    },
728    FormatEntry {
729        name: "velocity",
730        extensions: &["vtl"],
731        parent: None,
732    },
733    FormatEntry {
734        name: "verilog",
735        extensions: &["v"],
736        parent: None,
737    },
738    FormatEntry {
739        name: "vhdl",
740        extensions: &["vhd", "vhdl"],
741        parent: None,
742    },
743    FormatEntry {
744        name: "vim",
745        extensions: &[],
746        parent: None,
747    },
748    FormatEntry {
749        name: "visual-basic",
750        extensions: &[],
751        parent: None,
752    },
753    FormatEntry {
754        name: "astro",
755        extensions: &["astro"],
756        parent: None,
757    },
758    FormatEntry {
759        name: "vue",
760        extensions: &["vue"],
761        parent: None,
762    },
763    FormatEntry {
764        name: "wasm",
765        extensions: &[],
766        parent: None,
767    },
768    FormatEntry {
769        name: "wiki",
770        extensions: &[],
771        parent: None,
772    },
773    FormatEntry {
774        name: "xeora",
775        extensions: &[],
776        parent: None,
777    },
778    FormatEntry {
779        name: "xojo",
780        extensions: &[],
781        parent: None,
782    },
783    FormatEntry {
784        name: "xquery",
785        extensions: &["xy", "xquery"],
786        parent: None,
787    },
788    FormatEntry {
789        name: "yaml",
790        extensions: &["yaml", "yml"],
791        parent: None,
792    },
793    FormatEntry {
794        name: "abnf",
795        extensions: &[],
796        parent: None,
797    },
798    FormatEntry {
799        name: "agda",
800        extensions: &[],
801        parent: None,
802    },
803    FormatEntry {
804        name: "antlr4",
805        extensions: &["g4"],
806        parent: None,
807    },
808    FormatEntry {
809        name: "apex",
810        extensions: &["cls", "trigger", "apex"],
811        parent: None,
812    },
813    FormatEntry {
814        name: "aql",
815        extensions: &[],
816        parent: None,
817    },
818    FormatEntry {
819        name: "armasm",
820        extensions: &[],
821        parent: None,
822    },
823    FormatEntry {
824        name: "awk",
825        extensions: &["awk"],
826        parent: None,
827    },
828    FormatEntry {
829        name: "bicep",
830        extensions: &["bicep"],
831        parent: None,
832    },
833    FormatEntry {
834        name: "bnf",
835        extensions: &[],
836        parent: None,
837    },
838    FormatEntry {
839        name: "cfscript",
840        extensions: &["cfc"],
841        parent: None,
842    },
843    FormatEntry {
844        name: "cfml",
845        extensions: &["cfm"],
846        parent: None,
847    },
848    FormatEntry {
849        name: "cmake",
850        extensions: &["cmake"],
851        parent: None,
852    },
853    FormatEntry {
854        name: "cobol",
855        extensions: &[],
856        parent: None,
857    },
858    FormatEntry {
859        name: "csv",
860        extensions: &["csv"],
861        parent: None,
862    },
863    FormatEntry {
864        name: "cypher",
865        extensions: &[],
866        parent: None,
867    },
868    FormatEntry {
869        name: "dhall",
870        extensions: &[],
871        parent: None,
872    },
873    FormatEntry {
874        name: "dns-zone-file",
875        extensions: &[],
876        parent: None,
877    },
878    FormatEntry {
879        name: "dot",
880        extensions: &["dot", "gv"],
881        parent: None,
882    },
883    FormatEntry {
884        name: "ebnf",
885        extensions: &[],
886        parent: None,
887    },
888    FormatEntry {
889        name: "editorconfig",
890        extensions: &[],
891        parent: None,
892    },
893    FormatEntry {
894        name: "excel-formula",
895        extensions: &["xlsx", "xls"],
896        parent: None,
897    },
898    FormatEntry {
899        name: "factor",
900        extensions: &[],
901        parent: None,
902    },
903    FormatEntry {
904        name: "ftl",
905        extensions: &[],
906        parent: None,
907    },
908    FormatEntry {
909        name: "gcode",
910        extensions: &[],
911        parent: None,
912    },
913    FormatEntry {
914        name: "gettext",
915        extensions: &["po"],
916        parent: None,
917    },
918    FormatEntry {
919        name: "gml",
920        extensions: &[],
921        parent: None,
922    },
923    FormatEntry {
924        name: "go-module",
925        extensions: &[],
926        parent: None,
927    },
928    FormatEntry {
929        name: "hcl",
930        extensions: &["tf", "hcl"],
931        parent: None,
932    },
933    FormatEntry {
934        name: "hlsl",
935        extensions: &[],
936        parent: None,
937    },
938    FormatEntry {
939        name: "idris",
940        extensions: &["idr"],
941        parent: None,
942    },
943    FormatEntry {
944        name: "ignore",
945        extensions: &["gitignore"],
946        parent: None,
947    },
948    FormatEntry {
949        name: "jq",
950        extensions: &[],
951        parent: None,
952    },
953    FormatEntry {
954        name: "json5",
955        extensions: &["json5"],
956        parent: None,
957    },
958    FormatEntry {
959        name: "kusto",
960        extensions: &[],
961        parent: None,
962    },
963    FormatEntry {
964        name: "lilypond",
965        extensions: &["ly"],
966        parent: None,
967    },
968    FormatEntry {
969        name: "linker-script",
970        extensions: &["ld"],
971        parent: None,
972    },
973    FormatEntry {
974        name: "llvm",
975        extensions: &["ll"],
976        parent: None,
977    },
978    FormatEntry {
979        name: "log",
980        extensions: &["log"],
981        parent: None,
982    },
983    FormatEntry {
984        name: "mermaid",
985        extensions: &[],
986        parent: None,
987    },
988    FormatEntry {
989        name: "mongodb",
990        extensions: &[],
991        parent: None,
992    },
993    FormatEntry {
994        name: "n1ql",
995        extensions: &[],
996        parent: None,
997    },
998    FormatEntry {
999        name: "odin",
1000        extensions: &[],
1001        parent: None,
1002    },
1003    FormatEntry {
1004        name: "openqasm",
1005        extensions: &["qasm"],
1006        parent: None,
1007    },
1008    FormatEntry {
1009        name: "plant-uml",
1010        extensions: &["puml", "plantuml"],
1011        parent: None,
1012    },
1013    FormatEntry {
1014        name: "powerquery",
1015        extensions: &["pq"],
1016        parent: None,
1017    },
1018    FormatEntry {
1019        name: "promql",
1020        extensions: &[],
1021        parent: None,
1022    },
1023    FormatEntry {
1024        name: "purescript",
1025        extensions: &["purs"],
1026        parent: None,
1027    },
1028    FormatEntry {
1029        name: "qsharp",
1030        extensions: &["qs"],
1031        parent: None,
1032    },
1033    FormatEntry {
1034        name: "racket",
1035        extensions: &["rkt"],
1036        parent: None,
1037    },
1038    FormatEntry {
1039        name: "regex",
1040        extensions: &[],
1041        parent: None,
1042    },
1043    FormatEntry {
1044        name: "rego",
1045        extensions: &[],
1046        parent: None,
1047    },
1048    FormatEntry {
1049        name: "rescript",
1050        extensions: &["res"],
1051        parent: None,
1052    },
1053    FormatEntry {
1054        name: "robotframework",
1055        extensions: &["robot"],
1056        parent: None,
1057    },
1058    FormatEntry {
1059        name: "shell-session",
1060        extensions: &[],
1061        parent: None,
1062    },
1063    FormatEntry {
1064        name: "smali",
1065        extensions: &[],
1066        parent: None,
1067    },
1068    FormatEntry {
1069        name: "solidity",
1070        extensions: &["sol"],
1071        parent: None,
1072    },
1073    FormatEntry {
1074        name: "sparql",
1075        extensions: &["rq"],
1076        parent: None,
1077    },
1078    FormatEntry {
1079        name: "stata",
1080        extensions: &[],
1081        parent: None,
1082    },
1083    FormatEntry {
1084        name: "toml",
1085        extensions: &["toml"],
1086        parent: None,
1087    },
1088    FormatEntry {
1089        name: "turtle",
1090        extensions: &["ttl"],
1091        parent: None,
1092    },
1093    FormatEntry {
1094        name: "typoscript",
1095        extensions: &[],
1096        parent: None,
1097    },
1098    FormatEntry {
1099        name: "unrealscript",
1100        extensions: &["uc"],
1101        parent: None,
1102    },
1103    FormatEntry {
1104        name: "uri",
1105        extensions: &[],
1106        parent: None,
1107    },
1108    FormatEntry {
1109        name: "vala",
1110        extensions: &[],
1111        parent: None,
1112    },
1113    FormatEntry {
1114        name: "wgsl",
1115        extensions: &["wgsl"],
1116        parent: None,
1117    },
1118    FormatEntry {
1119        name: "wolfram",
1120        extensions: &["wl", "nb"],
1121        parent: None,
1122    },
1123    FormatEntry {
1124        name: "zig",
1125        extensions: &["zig"],
1126        parent: None,
1127    },
1128];
1129
1130static EXT_TO_FORMAT: LazyLock<HashMap<&'static str, &'static str>> = LazyLock::new(|| {
1131    let mut map = HashMap::new();
1132    for entry in SUPPORTED_FORMATS {
1133        for ext in entry.extensions {
1134            map.insert(*ext, entry.name);
1135        }
1136    }
1137    map
1138});
1139
1140/// O(1) lookup: file extension → format name
1141pub fn get_format_by_extension(ext: &str) -> Option<&'static str> {
1142    EXT_TO_FORMAT.get(ext).copied()
1143}
1144
1145/// Shebang detection: first line → format name
1146pub fn get_format_by_shebang(first_line: &str) -> Option<&'static str> {
1147    if first_line.contains("python3") || first_line.contains("python") {
1148        Some("python")
1149    } else if first_line.contains("node") || first_line.contains("nodejs") {
1150        Some("javascript")
1151    } else if first_line.contains("ruby") {
1152        Some("ruby")
1153    } else if first_line.contains("bash") || first_line.contains("/sh") {
1154        Some("bash")
1155    } else if first_line.contains("perl") {
1156        Some("perl")
1157    } else if first_line.contains("php") {
1158        Some("php")
1159    } else {
1160        None
1161    }
1162}
1163
1164/// Returns all supported format names (for --list flag)
1165pub fn list_formats() -> Vec<&'static str> {
1166    SUPPORTED_FORMATS.iter().map(|e| e.name).collect()
1167}
1168
1169static SYNONYMS: LazyLock<HashMap<&'static str, &'static str>> = LazyLock::new(|| {
1170    let mut map = HashMap::new();
1171    map.insert("node", "javascript");
1172    map.insert("shell", "bash");
1173    map.insert("zsh", "bash");
1174    map.insert("golang", "go");
1175    map
1176});
1177
1178pub fn resolve_format(hint: &str) -> Option<&'static str> {
1179    let normalized = hint.to_lowercase();
1180    if let Some(name) = SYNONYMS.get(normalized.as_str()) {
1181        return Some(*name);
1182    }
1183    if let Some(name) = get_format_by_extension(&normalized) {
1184        return Some(name);
1185    }
1186    SUPPORTED_FORMATS
1187        .iter()
1188        .find(|entry| entry.name == normalized)
1189        .map(|entry| entry.name)
1190}
1191
1192#[cfg(test)]
1193mod tests {
1194    use super::*;
1195
1196    #[test]
1197    fn js_extension_resolves() {
1198        assert_eq!(get_format_by_extension("js"), Some("javascript"));
1199    }
1200
1201    #[test]
1202    fn ts_extension_resolves() {
1203        assert_eq!(get_format_by_extension("ts"), Some("typescript"));
1204    }
1205
1206    #[test]
1207    fn unknown_extension_returns_none() {
1208        assert_eq!(get_format_by_extension("unknown_xyz_abc"), None);
1209    }
1210
1211    #[test]
1212    fn python_shebang_resolves() {
1213        assert_eq!(
1214            get_format_by_shebang("#!/usr/bin/env python3"),
1215            Some("python")
1216        );
1217    }
1218
1219    #[test]
1220    fn list_formats_has_at_least_100_entries() {
1221        assert!(list_formats().len() >= 100);
1222    }
1223
1224    #[test]
1225    fn supported_formats_has_223_entries() {
1226        assert_eq!(SUPPORTED_FORMATS.len(), 223);
1227    }
1228
1229    #[test]
1230    fn resolve_format_js_extension() {
1231        assert_eq!(resolve_format("js"), Some("javascript"));
1232    }
1233
1234    #[test]
1235    fn resolve_format_shell_synonym() {
1236        assert_eq!(resolve_format("shell"), Some("bash"));
1237    }
1238
1239    #[test]
1240    fn resolve_format_golang_synonym() {
1241        assert_eq!(resolve_format("golang"), Some("go"));
1242    }
1243
1244    #[test]
1245    fn resolve_format_unknown_returns_none() {
1246        assert_eq!(resolve_format("unknownxyz"), None);
1247    }
1248
1249    #[test]
1250    fn resolve_format_python_name() {
1251        assert_eq!(resolve_format("python"), Some("python"));
1252    }
1253
1254    #[test]
1255    fn empty_source_tokenize_returns_empty() {
1256        use crate::tokenizer::{Mode, tokenize};
1257        let result = std::panic::catch_unwind(|| tokenize("javascript", "", Mode::Mild));
1258        assert!(result.is_ok());
1259    }
1260}