1pub mod constants;
47pub mod ext_iden;
48#[cfg(any(
49 feature = "all-parsers",
50 feature = "napi-environment",
51 feature = "napi-compatible",
52 feature = "bash",
53 feature = "c",
54 feature = "cpp",
55 feature = "csharp",
56 feature = "css",
57 feature = "elixir",
58 feature = "go",
59 feature = "haskell",
60 feature = "hcl",
61 feature = "html",
62 feature = "java",
63 feature = "javascript",
64 feature = "json",
65 feature = "kotlin",
66 feature = "lua",
67 feature = "nix",
68 feature = "php",
69 feature = "python",
70 feature = "ruby",
71 feature = "rust",
72 feature = "scala",
73 feature = "solidity",
74 feature = "swift",
75 feature = "tsx",
76 feature = "typescript",
77 feature = "yaml"
78))]
79pub mod parsers;
80
81#[cfg(any(feature = "bash", feature = "all-parsers"))]
82mod bash;
83#[cfg(any(feature = "cpp", feature = "all-parsers"))]
84mod cpp;
85#[cfg(any(feature = "csharp", feature = "all-parsers"))]
86mod csharp;
87#[cfg(any(
88 feature = "css",
89 feature = "all-parsers",
90 feature = "css-napi",
91 feature = "napi-compatible"
92))]
93mod css;
94#[cfg(any(feature = "elixir", feature = "all-parsers"))]
95mod elixir;
96#[cfg(any(feature = "go", feature = "all-parsers"))]
97mod go;
98#[cfg(any(feature = "haskell", feature = "all-parsers"))]
99mod haskell;
100#[cfg(any(feature = "hcl", feature = "all-parsers"))]
101mod hcl;
102#[cfg(any(
103 feature = "html",
104 feature = "all-parsers",
105 feature = "html-napi",
106 feature = "napi-compatible"
107))]
108mod html;
109#[cfg(any(feature = "java", feature = "all-parsers"))]
110#[cfg(any(
111 feature = "javascript",
112 feature = "all-parsers",
113 feature = "javascript-napi",
114 feature = "napi-compatible"
115))]
116#[cfg(any(feature = "json", feature = "all-parsers"))]
117mod json;
118#[cfg(any(feature = "kotlin", feature = "all-parsers"))]
119mod kotlin;
120#[cfg(any(feature = "lua", feature = "all-parsers"))]
121mod lua;
122#[cfg(any(feature = "nix", feature = "all-parsers"))]
123mod nix;
124#[cfg(any(feature = "php", feature = "all-parsers"))]
125mod php;
126#[cfg(any(feature = "python", feature = "all-parsers"))]
127mod python;
128#[cfg(any(feature = "ruby", feature = "all-parsers"))]
129mod ruby;
130#[cfg(any(feature = "rust", feature = "all-parsers"))]
131mod rust;
132#[cfg(any(feature = "scala", feature = "all-parsers"))]
133mod scala;
134#[cfg(any(feature = "solidity", feature = "all-parsers"))]
135mod solidity;
136#[cfg(any(feature = "swift", feature = "all-parsers"))]
137mod swift;
138#[cfg(any(feature = "yaml", feature = "all-parsers"))]
139mod yaml;
140#[cfg(any(
141 feature = "html",
142 feature = "all-parsers",
143 feature = "html-napi",
144 feature = "napi-compatible"
145))]
146pub use html::Html;
147
148#[cfg(feature = "matching")]
149use thread_ast_engine::{Pattern, PatternBuilder, PatternError};
150#[cfg(feature = "profiling")]
151pub mod profiling;
152
153#[allow(unused_imports)]
154use ignore::types::{Types, TypesBuilder};
155#[allow(unused_imports)]
156use serde::de::Visitor;
157#[allow(unused_imports)]
158use serde::{Deserialize, Deserializer, Serialize, de};
159#[allow(unused_imports)]
160use std::borrow::Cow;
161use std::fmt::{self, Display, Formatter};
162use std::path::Path;
163use std::str::FromStr;
164
165#[allow(unused_imports)]
166use thread_ast_engine::Node;
167#[allow(unused_imports)]
168use thread_ast_engine::language::Language;
169#[allow(unused_imports)]
170#[cfg(feature = "matching")]
171use thread_ast_engine::meta_var::MetaVariable;
172#[allow(unused_imports)]
173#[cfg(feature = "tree-sitter-parsing")]
174use thread_ast_engine::tree_sitter::{LanguageExt, StrDoc, TSLanguage, TSRange};
175#[allow(unused_imports)]
176use thread_utilities::RapidMap;
177
178#[cfg(any(
193 feature = "all-parsers",
194 feature = "napi-compatible",
195 feature = "bash",
196 feature = "java",
197 feature = "javascript",
198 feature = "javascript-napi",
199 feature = "json",
200 feature = "lua",
201 feature = "solidity",
202 feature = "scala",
203 feature = "tsx",
204 feature = "tsx-napi",
205 feature = "typescript",
206 feature = "typescript-napi",
207 feature = "yaml",
208))]
209macro_rules! impl_lang {
210 ($lang: ident, $func: ident) => {
211 #[derive(Clone, Copy, Debug)]
212 pub struct $lang;
213 impl Language for $lang {
214 fn kind_to_id(&self, kind: &str) -> u16 {
215 self.get_ts_language()
216 .id_for_node_kind(kind, true)
217 }
218 fn field_to_id(&self, field: &str) -> Option<u16> {
219 self.get_ts_language()
220 .field_id_for_name(field)
221 .map(|f| f.get())
222 }
223 #[cfg(feature = "matching")]
224 fn build_pattern(&self, builder: &PatternBuilder) -> Result<Pattern, PatternError> {
225 builder.build(|src| StrDoc::try_new(src, self.clone()))
226 }
227 }
228 impl LanguageExt for $lang {
229 fn get_ts_language(&self) -> TSLanguage {
230 parsers::$func().into()
231 }
232 }
233 };
234}
235
236#[allow(dead_code)]
262fn pre_process_pattern(expando: char, query: &str) -> std::borrow::Cow<'_, str> {
263 let has_dollar = query.as_bytes().contains(&b'$');
265 if !has_dollar {
266 return std::borrow::Cow::Borrowed(query);
267 }
268
269 let mut size_needed = 0;
271 let mut needs_processing = false;
272 let mut dollar_count = 0;
273
274 for c in query.chars() {
275 if c == '$' {
276 dollar_count += 1;
277 } else {
278 let need_replace = matches!(c, 'A'..='Z' | '_') || dollar_count == 3;
279 if need_replace && dollar_count > 0 {
280 needs_processing = true;
281 }
282 size_needed += dollar_count + 1;
283 dollar_count = 0;
284 }
285 }
286 size_needed += dollar_count;
287
288 if !needs_processing {
290 return std::borrow::Cow::Borrowed(query);
291 }
292
293 let mut ret = String::with_capacity(size_needed);
295 dollar_count = 0;
296
297 for c in query.chars() {
298 if c == '$' {
299 dollar_count += 1;
300 continue;
301 }
302 let need_replace = matches!(c, 'A'..='Z' | '_') || dollar_count == 3;
303 let sigil = if need_replace { expando } else { '$' };
304
305 for _ in 0..dollar_count {
307 ret.push(sigil);
308 }
309 dollar_count = 0;
310 ret.push(c);
311 }
312
313 let sigil = if dollar_count == 3 { expando } else { '$' };
315 for _ in 0..dollar_count {
316 ret.push(sigil);
317 }
318
319 std::borrow::Cow::Owned(ret)
320}
321
322#[cfg(any(
352 feature = "all-parsers",
353 feature = "napi-compatible",
354 feature = "c",
355 feature = "cpp",
356 feature = "csharp",
357 feature = "css",
358 feature = "css-napi",
359 feature = "elixir",
360 feature = "go",
361 feature = "haskell",
362 feature = "hcl",
363 feature = "html",
364 feature = "html-napi",
365 feature = "kotlin",
366 feature = "nix",
367 feature = "php",
368 feature = "python",
369 feature = "ruby",
370 feature = "rust",
371))]
372macro_rules! impl_lang_expando {
373 ($lang: ident, $func: ident, $char: expr) => {
374 #[derive(Clone, Copy, Debug)]
375 pub struct $lang;
376 impl Language for $lang {
377 fn kind_to_id(&self, kind: &str) -> u16 {
378 self.get_ts_language()
379 .id_for_node_kind(kind, true)
380 }
381 fn field_to_id(&self, field: &str) -> Option<u16> {
382 self.get_ts_language()
383 .field_id_for_name(field)
384 .map(|f| f.get())
385 }
386 fn expando_char(&self) -> char {
387 $char
388 }
389 fn pre_process_pattern<'q>(&self, query: &'q str) -> std::borrow::Cow<'q, str> {
390 pre_process_pattern(self.expando_char(), query)
391 }
392 #[cfg(feature = "matching")]
393 fn build_pattern(&self, builder: &PatternBuilder) -> Result<Pattern, PatternError> {
394 builder.build(|src| StrDoc::try_new(src, self.clone()))
395 }
396 }
397 impl LanguageExt for $lang {
398 fn get_ts_language(&self) -> TSLanguage {
399 $crate::parsers::$func().into()
400 }
401 }
402 };
403}
404
405pub trait Alias: Display {
406 const ALIAS: &'static [&'static str];
407}
408
409#[cfg(all(
412 any(
413 feature = "all-parsers",
414 feature = "napi-compatible",
415 feature = "css-napi",
416 feature = "html-napi",
417 feature = "javascript-napi",
418 feature = "typescript-napi",
419 feature = "tsx-napi",
420 feature = "bash",
421 feature = "c",
422 feature = "cpp",
423 feature = "csharp",
424 feature = "css",
425 feature = "elixir",
426 feature = "go",
427 feature = "haskell",
428 feature = "hcl",
429 feature = "html",
430 feature = "java",
431 feature = "javascript",
432 feature = "json",
433 feature = "kotlin",
434 feature = "lua",
435 feature = "nix",
436 feature = "php",
437 feature = "python",
438 feature = "ruby",
439 feature = "rust",
440 feature = "scala",
441 feature = "solidity",
442 feature = "swift",
443 feature = "tsx",
444 feature = "typescript",
445 feature = "yaml"
446 ),
447 not(feature = "no-enabled-langs")
448))]
449macro_rules! impl_alias {
450 ($lang:ident => $as:expr) => {
451 impl Alias for $lang {
452 const ALIAS: &'static [&'static str] = $as;
453 }
454
455 impl fmt::Display for $lang {
456 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
457 write!(f, "{:?}", self)
458 }
459 }
460
461 impl<'de> Deserialize<'de> for $lang {
462 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
463 where
464 D: Deserializer<'de>,
465 {
466 let vis = AliasVisitor {
467 aliases: Self::ALIAS,
468 };
469 deserializer.deserialize_str(vis)?;
470 Ok($lang)
471 }
472 }
473
474 impl From<$lang> for SupportLang {
475 fn from(_: $lang) -> Self {
476 Self::$lang
477 }
478 }
479 };
480}
481#[cfg(all(
484 any(
485 feature = "all-parsers",
486 feature = "napi-compatible",
487 feature = "css-napi",
488 feature = "html-napi",
489 feature = "javascript-napi",
490 feature = "typescript-napi",
491 feature = "tsx-napi",
492 feature = "bash",
493 feature = "c",
494 feature = "cpp",
495 feature = "csharp",
496 feature = "css",
497 feature = "elixir",
498 feature = "go",
499 feature = "haskell",
500 feature = "hcl",
501 feature = "html",
502 feature = "java",
503 feature = "javascript",
504 feature = "json",
505 feature = "kotlin",
506 feature = "lua",
507 feature = "nix",
508 feature = "php",
509 feature = "python",
510 feature = "ruby",
511 feature = "rust",
512 feature = "scala",
513 feature = "solidity",
514 feature = "swift",
515 feature = "tsx",
516 feature = "typescript",
517 feature = "yaml"
518 ),
519 not(feature = "no-enabled-langs")
520))]
521macro_rules! impl_aliases {
522 ($($lang:ident, $feature:literal => $as:expr),* $(,)?) => {
523 $(#[cfg(feature = $feature)]
524 impl_alias!($lang => $as);
525 )*
526 #[allow(dead_code)]
527 const fn alias(lang: SupportLang) -> &'static [&'static str] {
528 match lang {
529 $(
530 #[cfg(feature = $feature)]
531 SupportLang::$lang => $lang::ALIAS,
532 )*
533 }
534 }
535 };
536}
537#[cfg(any(feature = "c", feature = "all-parsers"))]
543impl_lang_expando!(C, language_c, 'µ');
544#[cfg(any(feature = "cpp", feature = "all-parsers"))]
545impl_lang_expando!(Cpp, language_cpp, 'µ');
546
547#[cfg(any(feature = "csharp", feature = "all-parsers"))]
551impl_lang_expando!(CSharp, language_c_sharp, 'µ');
552
553#[cfg(any(
555 feature = "css",
556 feature = "all-parsers",
557 feature = "css-napi",
558 feature = "napi-compatible"
559))]
560impl_lang_expando!(Css, language_css, '_');
561
562#[cfg(any(feature = "elixir", feature = "all-parsers"))]
564impl_lang_expando!(Elixir, language_elixir, 'µ');
565
566#[cfg(any(feature = "go", feature = "all-parsers"))]
569impl_lang_expando!(Go, language_go, 'µ');
570
571#[cfg(any(feature = "haskell", feature = "all-parsers"))]
575impl_lang_expando!(Haskell, language_haskell, 'µ');
576
577#[cfg(any(feature = "hcl", feature = "all-parsers"))]
579impl_lang_expando!(Hcl, language_hcl, 'µ');
580
581#[cfg(any(feature = "kotlin", feature = "all-parsers"))]
583impl_lang_expando!(Kotlin, language_kotlin, 'µ');
584
585#[cfg(any(feature = "nix", feature = "all-parsers"))]
587impl_lang_expando!(Nix, language_nix, '_');
588
589#[cfg(any(feature = "php", feature = "all-parsers"))]
591impl_lang_expando!(Php, language_php, 'µ');
592
593#[cfg(any(feature = "python", feature = "all-parsers"))]
597impl_lang_expando!(Python, language_python, 'µ');
598
599#[cfg(any(feature = "ruby", feature = "all-parsers"))]
601impl_lang_expando!(Ruby, language_ruby, 'µ');
602
603#[cfg(any(feature = "rust", feature = "all-parsers"))]
606impl_lang_expando!(Rust, language_rust, 'µ');
607
608#[cfg(any(feature = "swift", feature = "all-parsers"))]
610impl_lang_expando!(Swift, language_swift, 'µ');
611
612#[cfg(any(feature = "bash", feature = "all-parsers"))]
615impl_lang!(Bash, language_bash);
616#[cfg(any(feature = "java", feature = "all-parsers"))]
617impl_lang!(Java, language_java);
618#[cfg(any(
619 feature = "javascript",
620 feature = "all-parsers",
621 feature = "javascript-napi",
622 feature = "napi-compatible"
623))]
624impl_lang!(JavaScript, language_javascript);
625#[cfg(any(feature = "json", feature = "all-parsers"))]
626impl_lang!(Json, language_json);
627#[cfg(any(feature = "lua", feature = "all-parsers"))]
628impl_lang!(Lua, language_lua);
629#[cfg(any(feature = "solidity", feature = "all-parsers"))]
630impl_lang!(Solidity, language_solidity);
631#[cfg(any(feature = "scala", feature = "all-parsers"))]
632impl_lang!(Scala, language_scala);
633#[cfg(any(
634 feature = "tsx",
635 feature = "all-parsers",
636 feature = "tsx-napi",
637 feature = "napi-compatible"
638))]
639impl_lang!(Tsx, language_tsx);
640#[cfg(any(
641 feature = "typescript",
642 feature = "all-parsers",
643 feature = "typescript-napi",
644 feature = "napi-compatible"
645))]
646impl_lang!(TypeScript, language_typescript);
647#[cfg(any(feature = "yaml", feature = "all-parsers"))]
648impl_lang!(Yaml, language_yaml);
649
650#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Hash)]
682pub enum SupportLang {
683 #[cfg(any(feature = "bash", feature = "all-parsers"))]
684 Bash,
685 #[cfg(any(feature = "c", feature = "all-parsers"))]
686 C,
687 #[cfg(any(feature = "cpp", feature = "all-parsers"))]
688 Cpp,
689 #[cfg(any(feature = "csharp", feature = "all-parsers"))]
690 CSharp,
691 #[cfg(any(
692 feature = "css",
693 feature = "all-parsers",
694 feature = "css-napi",
695 feature = "napi-compatible"
696 ))]
697 Css,
698 #[cfg(any(feature = "elixir", feature = "all-parsers"))]
699 Elixir,
700 #[cfg(any(feature = "go", feature = "all-parsers"))]
701 Go,
702 #[cfg(any(feature = "haskell", feature = "all-parsers"))]
703 Haskell,
704 #[cfg(any(feature = "hcl", feature = "all-parsers"))]
705 Hcl,
706 #[cfg(any(
707 feature = "html",
708 feature = "all-parsers",
709 feature = "html-napi",
710 feature = "napi-compatible"
711 ))]
712 Html,
713 #[cfg(any(feature = "java", feature = "all-parsers"))]
714 Java,
715 #[cfg(any(
716 feature = "javascript",
717 feature = "all-parsers",
718 feature = "javascript-napi",
719 feature = "napi-compatible"
720 ))]
721 JavaScript,
722 #[cfg(any(feature = "json", feature = "all-parsers"))]
723 Json,
724 #[cfg(any(feature = "kotlin", feature = "all-parsers"))]
725 Kotlin,
726 #[cfg(any(feature = "lua", feature = "all-parsers"))]
727 Lua,
728 #[cfg(any(feature = "nix", feature = "all-parsers"))]
729 Nix,
730 #[cfg(any(feature = "php", feature = "all-parsers"))]
731 Php,
732 #[cfg(any(feature = "python", feature = "all-parsers"))]
733 Python,
734 #[cfg(any(feature = "ruby", feature = "all-parsers"))]
735 Ruby,
736 #[cfg(any(feature = "rust", feature = "all-parsers"))]
737 Rust,
738 #[cfg(any(feature = "scala", feature = "all-parsers"))]
739 Scala,
740 #[cfg(any(feature = "solidity", feature = "all-parsers"))]
741 Solidity,
742 #[cfg(any(feature = "swift", feature = "all-parsers"))]
743 Swift,
744 #[cfg(any(
745 feature = "tsx",
746 feature = "all-parsers",
747 feature = "tsx-napi",
748 feature = "napi-compatible"
749 ))]
750 Tsx,
751 #[cfg(any(
752 feature = "typescript",
753 feature = "all-parsers",
754 feature = "typescript-napi",
755 feature = "napi-compatible"
756 ))]
757 TypeScript,
758 #[cfg(any(feature = "yaml", feature = "all-parsers"))]
759 Yaml,
760 #[cfg(not(any(
761 feature = "all-parsers",
762 feature = "napi-compatible",
763 feature = "css-napi",
764 feature = "html-napi",
765 feature = "javascript-napi",
766 feature = "typescript-napi",
767 feature = "tsx-napi",
768 feature = "bash",
769 feature = "c",
770 feature = "cpp",
771 feature = "csharp",
772 feature = "css",
773 feature = "elixir",
774 feature = "go",
775 feature = "haskell",
776 feature = "hcl",
777 feature = "html",
778 feature = "java",
779 feature = "javascript",
780 feature = "json",
781 feature = "kotlin",
782 feature = "nix",
783 feature = "lua",
784 feature = "php",
785 feature = "python",
786 feature = "ruby",
787 feature = "rust",
788 feature = "scala",
789 feature = "solidity",
790 feature = "swift",
791 feature = "tsx",
792 feature = "typescript",
793 feature = "yaml"
794 )))]
795 NoEnabledLangs,
796}
797
798impl SupportLang {
799 pub const fn all_langs() -> &'static [SupportLang] {
800 use SupportLang::*;
801 &[
802 #[cfg(any(feature = "bash", feature = "all-parsers"))]
803 Bash,
804 #[cfg(any(feature = "c", feature = "all-parsers"))]
805 C,
806 #[cfg(any(feature = "cpp", feature = "all-parsers"))]
807 Cpp,
808 #[cfg(any(feature = "csharp", feature = "all-parsers"))]
809 CSharp,
810 #[cfg(any(
811 feature = "css",
812 feature = "all-parsers",
813 feature = "css-napi",
814 feature = "napi-compatible"
815 ))]
816 Css,
817 #[cfg(any(feature = "elixir", feature = "all-parsers"))]
818 Elixir,
819 #[cfg(any(feature = "go", feature = "all-parsers"))]
820 Go,
821 #[cfg(any(feature = "haskell", feature = "all-parsers"))]
822 Haskell,
823 #[cfg(any(feature = "hcl", feature = "all-parsers"))]
824 Hcl,
825 #[cfg(any(
826 feature = "html",
827 feature = "all-parsers",
828 feature = "html-napi",
829 feature = "napi-compatible"
830 ))]
831 Html,
832 #[cfg(any(feature = "java", feature = "all-parsers"))]
833 Java,
834 #[cfg(any(
835 feature = "javascript",
836 feature = "all-parsers",
837 feature = "javascript-napi",
838 feature = "napi-compatible"
839 ))]
840 JavaScript,
841 #[cfg(any(feature = "json", feature = "all-parsers"))]
842 Json,
843 #[cfg(any(feature = "kotlin", feature = "all-parsers"))]
844 Kotlin,
845 #[cfg(any(feature = "lua", feature = "all-parsers"))]
846 Lua,
847 #[cfg(any(feature = "nix", feature = "all-parsers"))]
848 Nix,
849 #[cfg(any(feature = "php", feature = "all-parsers"))]
850 Php,
851 #[cfg(any(feature = "python", feature = "all-parsers"))]
852 Python,
853 #[cfg(any(feature = "ruby", feature = "all-parsers"))]
854 Ruby,
855 #[cfg(any(feature = "rust", feature = "all-parsers"))]
856 Rust,
857 #[cfg(any(feature = "scala", feature = "all-parsers"))]
858 Scala,
859 #[cfg(any(feature = "solidity", feature = "all-parsers"))]
860 Solidity,
861 #[cfg(any(feature = "swift", feature = "all-parsers"))]
862 Swift,
863 #[cfg(any(
864 feature = "tsx",
865 feature = "all-parsers",
866 feature = "tsx-napi",
867 feature = "napi-compatible"
868 ))]
869 Tsx,
870 #[cfg(any(
871 feature = "typescript",
872 feature = "all-parsers",
873 feature = "typescript-napi",
874 feature = "napi-compatible"
875 ))]
876 TypeScript,
877 #[cfg(any(feature = "yaml", feature = "all-parsers"))]
878 Yaml,
879 #[cfg(not(any(
880 feature = "all-parsers",
881 feature = "napi-compatible",
882 feature = "css-napi",
883 feature = "html-napi",
884 feature = "javascript-napi",
885 feature = "typescript-napi",
886 feature = "tsx-napi",
887 feature = "bash",
888 feature = "c",
889 feature = "cpp",
890 feature = "csharp",
891 feature = "css",
892 feature = "elixir",
893 feature = "go",
894 feature = "haskell",
895 feature = "hcl",
896 feature = "html",
897 feature = "java",
898 feature = "javascript",
899 feature = "json",
900 feature = "kotlin",
901 feature = "lua",
902 feature = "nix",
903 feature = "php",
904 feature = "python",
905 feature = "ruby",
906 feature = "rust",
907 feature = "scala",
908 feature = "solidity",
909 feature = "swift",
910 feature = "tsx",
911 feature = "typescript",
912 feature = "yaml"
913 )))]
914 NoEnabledLangs,
915 ]
916 }
917
918 pub fn file_types(&self) -> Types {
919 file_types(*self)
920 }
921}
922
923impl fmt::Display for SupportLang {
924 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
925 write!(f, "{self:?}")
926 }
927}
928
929#[derive(Debug)]
930pub enum SupportLangErr {
931 LanguageNotSupported(String),
932 LanguageNotEnabled(String),
933}
934
935impl Display for SupportLangErr {
936 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
937 use SupportLangErr::*;
938 match self {
939 LanguageNotSupported(lang) => write!(f, "{lang} is not supported!"),
940 LanguageNotEnabled(lang) => write!(
941 f,
942 "{lang} is available but not enabled. You need to enable the feature flag for this language."
943 ),
944 }
945 }
946}
947
948impl std::error::Error for SupportLangErr {}
949
950#[cfg(any(
951 feature = "all-parsers",
952 feature = "napi-compatible",
953 feature = "css-napi",
954 feature = "html-napi",
955 feature = "javascript-napi",
956 feature = "typescript-napi",
957 feature = "tsx-napi",
958 feature = "bash",
959 feature = "c",
960 feature = "cpp",
961 feature = "csharp",
962 feature = "css",
963 feature = "elixir",
964 feature = "go",
965 feature = "haskell",
966 feature = "hcl",
967 feature = "html",
968 feature = "java",
969 feature = "javascript",
970 feature = "json",
971 feature = "kotlin",
972 feature = "lua",
973 feature = "nix",
974 feature = "php",
975 feature = "python",
976 feature = "ruby",
977 feature = "rust",
978 feature = "scala",
979 feature = "solidity",
980 feature = "swift",
981 feature = "tsx",
982 feature = "typescript",
983 feature = "yaml"
984))]
985impl<'de> Deserialize<'de> for SupportLang {
986 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
987 where
988 D: Deserializer<'de>,
989 {
990 deserializer.deserialize_str(SupportLangVisitor)
991 }
992}
993#[allow(dead_code)]
994struct SupportLangVisitor;
995
996#[cfg(any(
997 feature = "all-parsers",
998 feature = "napi-compatible",
999 feature = "css-napi",
1000 feature = "html-napi",
1001 feature = "javascript-napi",
1002 feature = "typescript-napi",
1003 feature = "tsx-napi",
1004 feature = "bash",
1005 feature = "c",
1006 feature = "cpp",
1007 feature = "csharp",
1008 feature = "css",
1009 feature = "elixir",
1010 feature = "go",
1011 feature = "haskell",
1012 feature = "hcl",
1013 feature = "html",
1014 feature = "java",
1015 feature = "javascript",
1016 feature = "json",
1017 feature = "kotlin",
1018 feature = "lua",
1019 feature = "nix",
1020 feature = "php",
1021 feature = "python",
1022 feature = "ruby",
1023 feature = "rust",
1024 feature = "scala",
1025 feature = "solidity",
1026 feature = "swift",
1027 feature = "tsx",
1028 feature = "typescript",
1029 feature = "yaml"
1030))]
1031impl Visitor<'_> for SupportLangVisitor {
1032 type Value = SupportLang;
1033
1034 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
1035 f.write_str("SupportLang")
1036 }
1037
1038 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
1039 where
1040 E: de::Error,
1041 {
1042 v.parse().map_err(de::Error::custom)
1043 }
1044}
1045
1046#[allow(dead_code)]
1047struct AliasVisitor {
1048 aliases: &'static [&'static str],
1049}
1050#[cfg(any(
1051 feature = "all-parsers",
1052 feature = "napi-compatible",
1053 feature = "css-napi",
1054 feature = "html-napi",
1055 feature = "javascript-napi",
1056 feature = "typescript-napi",
1057 feature = "tsx-napi",
1058 feature = "bash",
1059 feature = "c",
1060 feature = "cpp",
1061 feature = "csharp",
1062 feature = "css",
1063 feature = "elixir",
1064 feature = "go",
1065 feature = "haskell",
1066 feature = "hcl",
1067 feature = "html",
1068 feature = "java",
1069 feature = "javascript",
1070 feature = "json",
1071 feature = "kotlin",
1072 feature = "lua",
1073 feature = "nix",
1074 feature = "php",
1075 feature = "python",
1076 feature = "ruby",
1077 feature = "rust",
1078 feature = "scala",
1079 feature = "solidity",
1080 feature = "swift",
1081 feature = "tsx",
1082 feature = "typescript",
1083 feature = "yaml"
1084))]
1085impl Visitor<'_> for AliasVisitor {
1086 type Value = &'static str;
1087
1088 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
1089 write!(f, "one of {:?}", self.aliases)
1090 }
1091
1092 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
1093 where
1094 E: de::Error,
1095 {
1096 self.aliases
1097 .iter()
1098 .copied()
1099 .find(|&a| v.eq_ignore_ascii_case(a))
1100 .ok_or_else(|| de::Error::invalid_value(de::Unexpected::Str(v), &self))
1101 }
1102}
1103#[cfg(all(
1104 any(
1105 feature = "all-parsers",
1106 feature = "napi-compatible",
1107 feature = "css-napi",
1108 feature = "html-napi",
1109 feature = "javascript-napi",
1110 feature = "typescript-napi",
1111 feature = "tsx-napi",
1112 feature = "bash",
1113 feature = "c",
1114 feature = "cpp",
1115 feature = "csharp",
1116 feature = "css",
1117 feature = "elixir",
1118 feature = "go",
1119 feature = "haskell",
1120 feature = "hcl",
1121 feature = "html",
1122 feature = "java",
1123 feature = "javascript",
1124 feature = "json",
1125 feature = "kotlin",
1126 feature = "lua",
1127 feature = "nix",
1128 feature = "php",
1129 feature = "python",
1130 feature = "ruby",
1131 feature = "rust",
1132 feature = "scala",
1133 feature = "solidity",
1134 feature = "swift",
1135 feature = "tsx",
1136 feature = "typescript",
1137 feature = "yaml"
1138 ),
1139 not(feature = "no-enabled-langs")
1140))]
1141impl_aliases! {
1142 Bash, "bash" => &["bash"],
1143 C, "c" => &["c"],
1144 Cpp, "cpp" => &["cc", "c++", "cpp", "cxx"],
1145 CSharp, "csharp" => &["cs", "csharp"],
1146 Css, "css" => &["css"],
1147 Elixir, "elixir" => &["ex", "elixir"],
1148 Go, "go" => &["go", "golang"],
1149 Haskell, "haskell" => &["hs", "haskell"],
1150 Hcl, "hcl" => &["hcl", "terraform"],
1151 Html, "html" => &["html"],
1152 Java, "java" => &["java"],
1153 JavaScript, "javascript" => &["javascript", "js", "jsx"],
1154 Json, "json" => &["json"],
1155 Kotlin, "kotlin" => &["kotlin", "kt"],
1156 Lua, "lua" => &["lua"],
1157 Nix, "nix" => &["nix"],
1158 Php, "php" => &["php"],
1159 Python, "python" => &["py", "python"],
1160 Ruby, "ruby" => &["rb", "ruby"],
1161 Rust, "rust" => &["rs", "rust"],
1162 Scala, "scala" => &["scala"],
1163 Solidity, "solidity" => &["sol", "solidity"],
1164 Swift, "swift" => &["swift"],
1165 TypeScript, "typescript" => &["ts", "typescript"],
1166 Tsx, "tsx" => &["tsx"],
1167 Yaml, "yaml" => &["yaml", "yml"],
1168 NoEnabledLangs, "no-enabled-langs" => &["no-enabled-langs"],
1169}
1170
1171impl FromStr for SupportLang {
1173 type Err = SupportLangErr;
1174 fn from_str(s: &str) -> Result<Self, Self::Err> {
1175 let mut str_matcher = s.trim().to_string();
1176 str_matcher.make_ascii_lowercase();
1177 match str_matcher.as_str() {
1178 #[cfg(any(feature = "bash", feature = "all-parsers"))]
1179 "bash" => Ok(SupportLang::Bash),
1180 #[cfg(any(feature = "c", feature = "all-parsers"))]
1181 "c" => Ok(SupportLang::C),
1182 #[cfg(any(feature = "cpp", feature = "all-parsers"))]
1183 "cpp" | "c++" => Ok(SupportLang::Cpp),
1184 #[cfg(any(feature = "csharp", feature = "all-parsers"))]
1185 "cs" | "csharp" => Ok(SupportLang::CSharp),
1186 #[cfg(any(
1187 feature = "css",
1188 feature = "all-parsers",
1189 feature = "css-napi",
1190 feature = "napi-compatible"
1191 ))]
1192 "css" => Ok(SupportLang::Css),
1193 #[cfg(any(feature = "elixir", feature = "all-parsers"))]
1194 "elixir" | "ex" => Ok(SupportLang::Elixir),
1195 #[cfg(any(feature = "go", feature = "all-parsers"))]
1196 "go" | "golang" => Ok(SupportLang::Go),
1197 #[cfg(any(feature = "haskell", feature = "all-parsers"))]
1198 "haskell" | "hs" => Ok(SupportLang::Haskell),
1199 #[cfg(any(feature = "hcl", feature = "all-parsers"))]
1200 "hcl" | "terraform" => Ok(SupportLang::Hcl),
1201 #[cfg(any(
1202 feature = "html",
1203 feature = "all-parsers",
1204 feature = "html-napi",
1205 feature = "napi-compatible"
1206 ))]
1207 "html" => Ok(SupportLang::Html),
1208 #[cfg(any(feature = "java", feature = "all-parsers"))]
1209 "java" => Ok(SupportLang::Java),
1210 #[cfg(any(
1211 feature = "javascript",
1212 feature = "all-parsers",
1213 feature = "javascript-napi",
1214 feature = "napi-compatible"
1215 ))]
1216 "javascript" | "js" => Ok(SupportLang::JavaScript),
1217 #[cfg(any(feature = "json", feature = "all-parsers"))]
1218 "json" => Ok(SupportLang::Json),
1219 #[cfg(any(feature = "kotlin", feature = "all-parsers"))]
1220 "kotlin" | "kt" => Ok(SupportLang::Kotlin),
1221 #[cfg(any(feature = "lua", feature = "all-parsers"))]
1222 "lua" => Ok(SupportLang::Lua),
1223 #[cfg(any(feature = "nix", feature = "all-parsers"))]
1224 "nix" => Ok(SupportLang::Nix),
1225 #[cfg(any(feature = "php", feature = "all-parsers"))]
1226 "php" => Ok(SupportLang::Php),
1227 #[cfg(any(feature = "python", feature = "all-parsers"))]
1228 "python" | "py" => Ok(SupportLang::Python),
1229 #[cfg(any(feature = "ruby", feature = "all-parsers"))]
1230 "ruby" | "rb" => Ok(SupportLang::Ruby),
1231 #[cfg(any(feature = "rust", feature = "all-parsers"))]
1232 "rust" | "rs" => Ok(SupportLang::Rust),
1233 #[cfg(any(feature = "scala", feature = "all-parsers"))]
1234 "scala" => Ok(SupportLang::Scala),
1235 #[cfg(any(feature = "solidity", feature = "all-parsers"))]
1236 "solidity" | "sol" => Ok(SupportLang::Solidity),
1237 #[cfg(any(feature = "swift", feature = "all-parsers"))]
1238 "swift" => Ok(SupportLang::Swift),
1239 #[cfg(any(
1240 feature = "typescript",
1241 feature = "all-parsers",
1242 feature = "typescript-napi",
1243 feature = "napi-compatible"
1244 ))]
1245 "typescript" | "ts" => Ok(SupportLang::TypeScript),
1246 #[cfg(any(
1247 feature = "tsx",
1248 feature = "all-parsers",
1249 feature = "tsx-napi",
1250 feature = "napi-compatible"
1251 ))]
1252 "tsx" => Ok(SupportLang::Tsx),
1253 #[cfg(any(feature = "yaml", feature = "all-parsers"))]
1254 "yaml" | "yml" => Ok(SupportLang::Yaml),
1255 #[cfg(not(any(
1256 feature = "all-parsers",
1257 feature = "napi-compatible",
1258 feature = "css-napi",
1259 feature = "html-napi",
1260 feature = "javascript-napi",
1261 feature = "typescript-napi",
1262 feature = "tsx-napi",
1263 feature = "bash",
1264 feature = "c",
1265 feature = "cpp",
1266 feature = "csharp",
1267 feature = "css",
1268 feature = "elixir",
1269 feature = "go",
1270 feature = "haskell",
1271 feature = "hcl",
1272 feature = "html",
1273 feature = "java",
1274 feature = "javascript",
1275 feature = "json",
1276 feature = "kotlin",
1277 feature = "lua",
1278 feature = "nix",
1279 feature = "php",
1280 feature = "python",
1281 feature = "ruby",
1282 feature = "rust",
1283 feature = "scala",
1284 feature = "solidity",
1285 feature = "swift",
1286 feature = "tsx",
1287 feature = "typescript",
1288 feature = "yaml"
1289 )))]
1290 "no-enabled-langs" => Ok(SupportLang::NoEnabledLangs),
1291
1292 _ => {
1293 if constants::ALL_SUPPORTED_LANGS.contains(&str_matcher.as_str()) {
1294 Err(SupportLangErr::LanguageNotEnabled(format!(
1295 "language {} was detected, but it is not enabled by feature flags. If you want to parse this kind of file, enable the flag in `thread-language`",
1296 &str_matcher
1297 )))
1298 } else {
1299 Err(SupportLangErr::LanguageNotSupported(format!(
1300 "language {} is not supported",
1301 &str_matcher
1302 )))
1303 }
1304 }
1305 }
1306 }
1307}
1308#[cfg(any(
1309 feature = "all-parsers",
1310 feature = "napi-compatible",
1311 feature = "css-napi",
1312 feature = "html-napi",
1313 feature = "javascript-napi",
1314 feature = "typescript-napi",
1315 feature = "tsx-napi",
1316 feature = "bash",
1317 feature = "c",
1318 feature = "cpp",
1319 feature = "csharp",
1320 feature = "css",
1321 feature = "elixir",
1322 feature = "go",
1323 feature = "haskell",
1324 feature = "hcl",
1325 feature = "html",
1326 feature = "java",
1327 feature = "javascript",
1328 feature = "json",
1329 feature = "kotlin",
1330 feature = "lua",
1331 feature = "nix",
1332 feature = "php",
1333 feature = "python",
1334 feature = "ruby",
1335 feature = "rust",
1336 feature = "scala",
1337 feature = "solidity",
1338 feature = "swift",
1339 feature = "tsx",
1340 feature = "typescript",
1341 feature = "yaml"
1342))]
1343macro_rules! execute_lang_method {
1344 ($me: path, $method: ident, $($pname:tt),*) => {
1345 use SupportLang as S;
1346 match $me {
1347 #[cfg(any(feature = "bash", feature = "all-parsers"))]
1348 S::Bash => Bash.$method($($pname,)*),
1349 #[cfg(any(feature = "c", feature = "all-parsers"))]
1350 S::C => C.$method($($pname,)*),
1351 #[cfg(any(feature = "cpp", feature = "all-parsers"))]
1352 S::Cpp => Cpp.$method($($pname,)*),
1353 #[cfg(any(feature = "csharp", feature = "all-parsers"))]
1354 S::CSharp => CSharp.$method($($pname,)*),
1355 #[cfg(any(feature = "css", feature = "all-parsers", feature = "css-napi", feature = "napi-compatible"))]
1356 S::Css => Css.$method($($pname,)*),
1357 #[cfg(any(feature = "elixir", feature = "all-parsers"))]
1358 S::Elixir => Elixir.$method($($pname,)*),
1359 #[cfg(any(feature = "go", feature = "all-parsers"))]
1360 S::Go => Go.$method($($pname,)*),
1361 #[cfg(any(feature = "haskell", feature = "all-parsers"))]
1362 S::Haskell => Haskell.$method($($pname,)*),
1363 #[cfg(any(feature = "hcl", feature = "all-parsers"))]
1364 S::Hcl => Hcl.$method($($pname,)*),
1365 #[cfg(any(feature = "html", feature = "all-parsers", feature = "html-napi", feature = "napi-compatible"))]
1366 S::Html => Html.$method($($pname,)*),
1367 #[cfg(any(feature = "java", feature = "all-parsers"))]
1368 S::Java => Java.$method($($pname,)*),
1369 #[cfg(any(feature = "javascript", feature = "all-parsers", feature = "javascript-napi", feature = "napi-compatible"))]
1370 S::JavaScript => JavaScript.$method($($pname,)*),
1371 #[cfg(any(feature = "json", feature = "all-parsers"))]
1372 S::Json => Json.$method($($pname,)*),
1373 #[cfg(any(feature = "kotlin", feature = "all-parsers"))]
1374 S::Kotlin => Kotlin.$method($($pname,)*),
1375 #[cfg(any(feature = "lua", feature = "all-parsers"))]
1376 S::Lua => Lua.$method($($pname,)*),
1377 #[cfg(any(feature = "nix", feature = "all-parsers"))]
1378 S::Nix => Nix.$method($($pname,)*),
1379 #[cfg(any(feature = "php", feature = "all-parsers"))]
1380 S::Php => Php.$method($($pname,)*),
1381 #[cfg(any(feature = "python", feature = "all-parsers"))]
1382 S::Python => Python.$method($($pname,)*),
1383 #[cfg(any(feature = "ruby", feature = "all-parsers"))]
1384 S::Ruby => Ruby.$method($($pname,)*),
1385 #[cfg(any(feature = "rust", feature = "all-parsers"))]
1386 S::Rust => Rust.$method($($pname,)*),
1387 #[cfg(any(feature = "scala", feature = "all-parsers"))]
1388 S::Scala => Scala.$method($($pname,)*),
1389 #[cfg(any(feature = "solidity", feature = "all-parsers"))]
1390 S::Solidity => Solidity.$method($($pname,)*),
1391 #[cfg(any(feature = "swift", feature = "all-parsers"))]
1392 S::Swift => Swift.$method($($pname,)*),
1393 #[cfg(any(feature = "tsx", feature = "all-parsers", feature = "tsx-napi", feature = "napi-compatible"))]
1394 S::Tsx => Tsx.$method($($pname,)*),
1395 #[cfg(any(feature = "typescript", feature = "all-parsers", feature = "typescript-napi", feature = "napi-compatible"))]
1396 S::TypeScript => TypeScript.$method($($pname,)*),
1397 #[cfg(any(feature = "yaml", feature = "all-parsers"))]
1398 S::Yaml => Yaml.$method($($pname,)*),
1399 #[cfg(not(any(
1400 feature = "all-parsers",
1401 feature = "napi-compatible",
1402 feature = "css-napi",
1403 feature = "html-napi",
1404 feature = "javascript-napi",
1405 feature = "typescript-napi",
1406 feature = "tsx-napi",
1407 feature = "bash",
1408 feature = "c",
1409 feature = "cpp",
1410 feature = "csharp",
1411 feature = "css",
1412 feature = "elixir",
1413 feature = "go",
1414 feature = "haskell",
1415 feature = "hcl",
1416 feature = "html",
1417 feature = "java",
1418 feature = "javascript",
1419 feature = "json",
1420 feature = "kotlin",
1421 feature = "lua",
1422 feature = "nix",
1423 feature = "php",
1424 feature = "python",
1425 feature = "ruby",
1426 feature = "rust",
1427 feature = "scala",
1428 feature = "solidity",
1429 feature = "swift",
1430 feature = "tsx",
1431 feature = "typescript",
1432 feature = "yaml"
1433 )))]
1434 S::NoEnabledLangs => {
1435 return Err(SupportLangErr::LanguageNotEnabled(
1436 "no-enabled-langs".to_string(),
1437 ))
1438 }
1439 }
1440 }
1441}
1442#[cfg(any(
1443 feature = "all-parsers",
1444 feature = "napi-compatible",
1445 feature = "css-napi",
1446 feature = "javascript-napi",
1447 feature = "html-napi",
1448 feature = "typescript-napi",
1449 feature = "tsx-napi",
1450 feature = "bash",
1451 feature = "c",
1452 feature = "cpp",
1453 feature = "csharp",
1454 feature = "css",
1455 feature = "elixir",
1456 feature = "go",
1457 feature = "haskell",
1458 feature = "hcl",
1459 feature = "html",
1460 feature = "java",
1461 feature = "javascript",
1462 feature = "json",
1463 feature = "kotlin",
1464 feature = "lua",
1465 feature = "nix",
1466 feature = "php",
1467 feature = "python",
1468 feature = "ruby",
1469 feature = "rust",
1470 feature = "scala",
1471 feature = "solidity",
1472 feature = "swift",
1473 feature = "tsx",
1474 feature = "typescript",
1475 feature = "yaml"
1476))]
1477macro_rules! impl_lang_method {
1478 ($method: ident, ($($pname:tt: $ptype:ty),*) => $return_type: ty) => {
1479 #[inline]
1480 fn $method(&self, $($pname: $ptype),*) -> $return_type {
1481 execute_lang_method!{ self, $method, $($pname),* }
1482 }
1483 };
1484}
1485#[cfg(all(
1486 feature = "matching",
1487 any(
1488 feature = "all-parsers",
1489 feature = "napi-environment",
1490 feature = "napi-compatible",
1491 feature = "bash",
1492 feature = "c",
1493 feature = "cpp",
1494 feature = "csharp",
1495 feature = "css",
1496 feature = "elixir",
1497 feature = "go",
1498 feature = "haskell",
1499 feature = "hcl",
1500 feature = "html",
1501 feature = "java",
1502 feature = "javascript",
1503 feature = "json",
1504 feature = "kotlin",
1505 feature = "lua",
1506 feature = "nix",
1507 feature = "php",
1508 feature = "python",
1509 feature = "ruby",
1510 feature = "rust",
1511 feature = "scala",
1512 feature = "solidity",
1513 feature = "swift",
1514 feature = "tsx",
1515 feature = "typescript",
1516 feature = "yaml"
1517 )
1518))]
1519impl Language for SupportLang {
1520 impl_lang_method!(kind_to_id, (kind: &str) => u16);
1521 impl_lang_method!(field_to_id, (field: &str) => Option<u16>);
1522 impl_lang_method!(meta_var_char, () => char);
1523 impl_lang_method!(expando_char, () => char);
1524 impl_lang_method!(extract_meta_var, (source: &str) => Option<MetaVariable>);
1525 impl_lang_method!(build_pattern, (builder: &PatternBuilder) => Result<Pattern, PatternError>);
1526 fn pre_process_pattern<'q>(&self, query: &'q str) -> Cow<'q, str> {
1527 execute_lang_method! { self, pre_process_pattern, query }
1528 }
1529 fn from_path<P: AsRef<Path>>(path: P) -> Option<Self> {
1530 from_extension(path.as_ref())
1531 }
1532}
1533
1534#[cfg(all(
1535 feature = "matching",
1536 any(
1537 feature = "all-parsers",
1538 feature = "napi-compatible",
1539 feature = "css-napi",
1540 feature = "html-napi",
1541 feature = "javascript-napi",
1542 feature = "typescript-napi",
1543 feature = "tsx-napi",
1544 feature = "bash",
1545 feature = "c",
1546 feature = "cpp",
1547 feature = "csharp",
1548 feature = "css",
1549 feature = "elixir",
1550 feature = "go",
1551 feature = "haskell",
1552 feature = "hcl",
1553 feature = "html",
1554 feature = "java",
1555 feature = "javascript",
1556 feature = "json",
1557 feature = "kotlin",
1558 feature = "lua",
1559 feature = "nix",
1560 feature = "php",
1561 feature = "python",
1562 feature = "ruby",
1563 feature = "rust",
1564 feature = "scala",
1565 feature = "solidity",
1566 feature = "swift",
1567 feature = "tsx",
1568 feature = "typescript",
1569 feature = "yaml"
1570 )
1571))]
1572impl LanguageExt for SupportLang {
1573 impl_lang_method!(get_ts_language, () => TSLanguage);
1574 impl_lang_method!(injectable_languages, () => Option<&'static [&'static str]>);
1575 fn extract_injections<L: LanguageExt>(
1576 &self,
1577 _root: Node<StrDoc<L>>,
1578 ) -> RapidMap<String, Vec<TSRange>> {
1579 match self {
1580 #[cfg(feature = "html-embedded")]
1581 SupportLang::Html => Html.extract_injections(_root),
1582 _ => RapidMap::default(),
1583 }
1584 }
1585}
1586
1587pub const fn extensions(lang: SupportLang) -> &'static [&'static str] {
1588 use SupportLang::*;
1589 match lang {
1590 #[cfg(any(feature = "bash", feature = "all-parsers"))]
1591 Bash => &constants::BASH_EXTS,
1592 #[cfg(any(feature = "c", feature = "all-parsers"))]
1593 C => &constants::C_EXTS,
1594 #[cfg(any(feature = "cpp", feature = "all-parsers"))]
1595 Cpp => &constants::CPP_EXTS,
1596 #[cfg(any(feature = "csharp", feature = "all-parsers"))]
1597 CSharp => &constants::CSHARP_EXTS,
1598 #[cfg(any(
1599 feature = "css",
1600 feature = "all-parsers",
1601 feature = "css-napi",
1602 feature = "napi-compatible"
1603 ))]
1604 Css => &constants::CSS_EXTS,
1605 #[cfg(any(feature = "elixir", feature = "all-parsers"))]
1606 Elixir => &constants::ELIXIR_EXTS,
1607 #[cfg(any(feature = "go", feature = "all-parsers"))]
1608 Go => &constants::GO_EXTS,
1609 #[cfg(any(feature = "haskell", feature = "all-parsers"))]
1610 Haskell => &constants::HASKELL_EXTS,
1611 #[cfg(any(feature = "hcl", feature = "all-parsers"))]
1612 Hcl => &constants::HCL_EXTS,
1613 #[cfg(any(
1614 feature = "html",
1615 feature = "all-parsers",
1616 feature = "html-napi",
1617 feature = "napi-compatible"
1618 ))]
1619 Html => &constants::HTML_EXTS,
1620 #[cfg(any(feature = "java", feature = "all-parsers"))]
1621 Java => &constants::JAVA_EXTS,
1622 #[cfg(any(
1623 feature = "javascript",
1624 feature = "all-parsers",
1625 feature = "javascript-napi",
1626 feature = "napi-compatible"
1627 ))]
1628 JavaScript => &constants::JAVASCRIPT_EXTS,
1629 #[cfg(any(feature = "json", feature = "all-parsers"))]
1630 Json => &constants::JSON_EXTS,
1631 #[cfg(any(feature = "kotlin", feature = "all-parsers"))]
1632 Kotlin => &constants::KOTLIN_EXTS,
1633 #[cfg(any(feature = "lua", feature = "all-parsers"))]
1634 Lua => &constants::LUA_EXTS,
1635 #[cfg(any(feature = "nix", feature = "all-parsers"))]
1636 Nix => &constants::NIX_EXTS,
1637 #[cfg(any(feature = "php", feature = "all-parsers"))]
1638 Php => &constants::PHP_EXTS,
1639 #[cfg(any(feature = "python", feature = "all-parsers"))]
1640 Python => &constants::PYTHON_EXTS,
1641 #[cfg(any(feature = "ruby", feature = "all-parsers"))]
1642 Ruby => &constants::RUBY_EXTS,
1643 #[cfg(any(feature = "rust", feature = "all-parsers"))]
1644 Rust => &constants::RUST_EXTS,
1645 #[cfg(any(feature = "scala", feature = "all-parsers"))]
1646 Scala => &constants::SCALA_EXTS,
1647 #[cfg(any(feature = "solidity", feature = "all-parsers"))]
1648 Solidity => &constants::SOLIDITY_EXTS,
1649 #[cfg(any(feature = "swift", feature = "all-parsers"))]
1650 Swift => &constants::SWIFT_EXTS,
1651 #[cfg(any(
1652 feature = "typescript",
1653 feature = "all-parsers",
1654 feature = "typescript-napi",
1655 feature = "napi-compatible"
1656 ))]
1657 TypeScript => &constants::TYPESCRIPT_EXTS,
1658 #[cfg(any(
1659 feature = "tsx",
1660 feature = "all-parsers",
1661 feature = "tsx-napi",
1662 feature = "napi-compatible"
1663 ))]
1664 Tsx => &constants::TSX_EXTS,
1665 #[cfg(any(feature = "yaml", feature = "all-parsers"))]
1666 Yaml => &constants::YAML_EXTS,
1667 #[cfg(not(any(
1668 feature = "all-parsers",
1669 feature = "napi-environment",
1670 feature = "napi-compatible",
1671 feature = "css-napi",
1672 feature = "html-napi",
1673 feature = "javascript-napi",
1674 feature = "typescript-napi",
1675 feature = "tsx-napi",
1676 feature = "bash",
1677 feature = "c",
1678 feature = "cpp",
1679 feature = "csharp",
1680 feature = "css",
1681 feature = "elixir",
1682 feature = "go",
1683 feature = "haskell",
1684 feature = "hcl",
1685 feature = "html",
1686 feature = "java",
1687 feature = "javascript",
1688 feature = "json",
1689 feature = "kotlin",
1690 feature = "lua",
1691 feature = "nix",
1692 feature = "php",
1693 feature = "python",
1694 feature = "ruby",
1695 feature = "rust",
1696 feature = "scala",
1697 feature = "solidity",
1698 feature = "swift",
1699 feature = "tsx",
1700 feature = "typescript",
1701 feature = "yaml"
1702 )))]
1703 NoEnabledLangs => &[],
1704 }
1705}
1706
1707#[inline]
1714pub fn from_extension(path: &Path) -> Option<SupportLang> {
1715 let ext = path.extension()?.to_str()?.to_ascii_lowercase();
1716 from_extension_str(&ext)
1717}
1718
1719#[inline]
1720pub fn from_extension_str(ext: &str) -> Option<SupportLang> {
1721 let ext = ext.to_ascii_lowercase();
1722 if ext.is_empty() {
1724 return None;
1725 }
1726 match ext.as_str() {
1727 #[cfg(any(feature = "python", feature = "all-parsers"))]
1728 "py" => Some(SupportLang::Python),
1729 #[cfg(any(
1730 feature = "javascript",
1731 feature = "all-parsers",
1732 feature = "javascript-napi",
1733 feature = "napi-compatible"
1734 ))]
1735 "js" => Some(SupportLang::JavaScript),
1736 #[cfg(any(
1737 feature = "typescript",
1738 feature = "all-parsers",
1739 feature = "typescript-napi",
1740 feature = "napi-compatible"
1741 ))]
1742 "ts" => Some(SupportLang::TypeScript),
1743 #[cfg(any(feature = "java", feature = "all-parsers"))]
1744 "java" => Some(SupportLang::Java),
1745 #[cfg(any(feature = "go", feature = "all-parsers"))]
1746 "go" => Some(SupportLang::Go),
1747 #[cfg(any(feature = "cpp", feature = "all-parsers"))]
1748 "cpp" => Some(SupportLang::Cpp),
1749 #[cfg(any(feature = "rust", feature = "all-parsers"))]
1750 "rs" => Some(SupportLang::Rust),
1751 #[cfg(any(feature = "c", feature = "all-parsers"))]
1752 "c" => Some(SupportLang::C),
1753 #[cfg(any(feature = "json", feature = "all-parsers"))]
1755 "json" => Some(SupportLang::Json),
1756 #[cfg(any(feature = "yaml", feature = "all-parsers"))]
1757 "yaml" | "yml" => Some(SupportLang::Yaml),
1758 _ => ext_iden::match_by_aho_corasick(&ext),
1759 }
1760}
1761
1762fn add_custom_file_type<'b>(
1763 builder: &'b mut TypesBuilder,
1764 file_type: &str,
1765 suffix_list: &[&str],
1766) -> &'b mut TypesBuilder {
1767 for suffix in suffix_list {
1768 let glob = format!("*.{suffix}");
1769 builder
1770 .add(file_type, &glob)
1771 .expect("file pattern must compile");
1772 }
1773 builder.select(file_type)
1774}
1775
1776fn file_types(lang: SupportLang) -> Types {
1777 let mut builder = TypesBuilder::new();
1778 let exts = extensions(lang);
1779 let lang_name = lang.to_string();
1780 add_custom_file_type(&mut builder, &lang_name, exts);
1781 builder.build().expect("file type must be valid")
1782}
1783
1784pub fn config_file_type() -> Types {
1785 let mut builder = TypesBuilder::new();
1786 let builder = add_custom_file_type(&mut builder, "yml", &["yml", "yaml"]);
1787 builder.build().expect("yaml type must be valid")
1788}
1789
1790#[cfg(test)]
1791mod test {
1792 use super::*;
1793 use thread_ast_engine::{Pattern, matcher::MatcherExt};
1794
1795 pub fn test_match_lang(query: &str, source: &str, lang: impl LanguageExt) {
1796 let cand = lang.ast_grep(source);
1797 let pattern = Pattern::new(query, &lang);
1798 assert!(
1799 pattern.find_node(cand.root()).is_some(),
1800 "goal: {pattern:?}, candidate: {}",
1801 cand.root().get_inner_node().to_sexp(),
1802 );
1803 }
1804
1805 pub fn test_non_match_lang(query: &str, source: &str, lang: impl LanguageExt) {
1806 let cand = lang.ast_grep(source);
1807 let pattern = Pattern::new(query, &lang);
1808 assert!(
1809 pattern.find_node(cand.root()).is_none(),
1810 "goal: {pattern:?}, candidate: {}",
1811 cand.root().get_inner_node().to_sexp(),
1812 );
1813 }
1814
1815 pub fn test_replace_lang(
1816 src: &str,
1817 pattern: &str,
1818 replacer: &str,
1819 lang: impl LanguageExt,
1820 ) -> String {
1821 let mut source = lang.ast_grep(src);
1822 assert!(
1823 source
1824 .replace(pattern, replacer)
1825 .expect("should parse successfully")
1826 );
1827 source.generate()
1828 }
1829
1830 #[test]
1831 fn test_js_string() {
1832 test_match_lang("'a'", "'a'", JavaScript);
1833 test_match_lang("\"\"", "\"\"", JavaScript);
1834 test_match_lang("''", "''", JavaScript);
1835 }
1836
1837 #[test]
1838 fn test_guess_by_extension() {
1839 let path = Path::new("foo.rs");
1840 assert_eq!(from_extension(path), Some(SupportLang::Rust));
1841 }
1842
1843 #[test]
1844 fn test_optimized_extension_matching() {
1845 let test_cases = [
1847 ("main.rs", Some(SupportLang::Rust)),
1848 ("app.js", Some(SupportLang::JavaScript)),
1849 ("main.tf", Some(SupportLang::Hcl)),
1850 ("index.html", Some(SupportLang::Html)),
1851 ("data.json", Some(SupportLang::Json)),
1852 ("script.py", Some(SupportLang::Python)),
1853 ("main.go", Some(SupportLang::Go)),
1854 ("style.css", Some(SupportLang::Css)),
1855 ("component.tsx", Some(SupportLang::Tsx)),
1856 ("build.gradle.kts", Some(SupportLang::Kotlin)),
1857 ("somefile.nix", Some(SupportLang::Nix)),
1858 ("config.yml", Some(SupportLang::Yaml)),
1859 ("script.sh", Some(SupportLang::Bash)),
1860 ("app.swift", Some(SupportLang::Swift)),
1861 ("main.cpp", Some(SupportLang::Cpp)),
1862 ("header.hpp", Some(SupportLang::Cpp)),
1863 ("style.scss", Some(SupportLang::Css)),
1864 ("script.rb", Some(SupportLang::Ruby)),
1865 ("supercryptodude.sol", Some(SupportLang::Solidity)),
1866 ("main.scala", Some(SupportLang::Scala)),
1867 ("app.kt", Some(SupportLang::Kotlin)),
1868 ("Main.RS", Some(SupportLang::Rust)),
1870 ("App.JS", Some(SupportLang::JavaScript)),
1871 ("Config.YML", Some(SupportLang::Yaml)),
1872 ("file.xyz", None),
1874 ("test.unknown", None),
1875 ];
1876
1877 for (filename, expected) in test_cases {
1878 let path = Path::new(filename);
1879 let result = from_extension(path);
1880 assert_eq!(result, expected, "Failed for {}", filename);
1881
1882 if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
1884 let direct_result = ext_iden::match_by_aho_corasick(ext);
1885 assert_eq!(
1886 direct_result, expected,
1887 "Direct matching failed for {}",
1888 ext
1889 );
1890 }
1891 }
1892 }
1893
1894 }