1use llmcc_core::LanguageTraitImpl;
2use llmcc_core::graph_builder::BlockKind;
3use llmcc_core::ir::{HirKind, HirNode};
4use llmcc_core::lang_def::{LanguageTrait, ParseNode, ParseTree, TreeSitterParseTree};
5use llmcc_core::scope::{Scope, ScopeStack};
6use llmcc_core::symbol::{SymKind, Symbol};
7use llmcc_core::{CompileCtxt, CompileUnit};
8use llmcc_resolver::ResolverOption;
9
10#[allow(clippy::single_component_path_imports)]
11use tree_sitter_typescript;
12
13include!(concat!(env!("OUT_DIR"), "/typescript_tokens.rs"));
16
17impl LanguageTraitImpl for LangTypeScript {
18 fn block_kind_with_parent_impl(kind_id: u16, field_id: u16, _parent_kind_id: u16) -> BlockKind {
20 let field_kind = <Self as LanguageTrait>::block_kind(field_id);
22 if field_kind != BlockKind::Undefined {
23 field_kind
24 } else {
25 <Self as LanguageTrait>::block_kind(kind_id)
26 }
27 }
28
29 #[rustfmt::skip]
30 fn collect_init_impl<'tcx>(cc: &'tcx CompileCtxt<'tcx>) -> ScopeStack<'tcx> {
31 let stack = ScopeStack::new(cc.arena(), &cc.interner);
32 let globals = cc.create_globals();
33 stack.push(globals);
34 debug_assert!(stack.depth() == 1);
35
36 for prim in crate::TYPESCRIPT_PRIMITIVES {
37 let name = cc.interner.intern(prim);
38 let symbol_val = Symbol::new(CompileCtxt::GLOBAL_SCOPE_OWNER, name);
39 let sym_id = symbol_val.id().0;
40 let symbol = cc.arena().alloc_with_id(sym_id, symbol_val);
41 symbol.set_kind(SymKind::Primitive);
42 symbol.set_is_global(true);
43 globals.insert(symbol);
44 }
45
46 stack
47 }
48
49 fn parse_impl(text: impl AsRef<[u8]>) -> Option<Box<dyn ParseTree>> {
50 use std::cell::RefCell;
51
52 thread_local! {
54 static PARSER: RefCell<tree_sitter::Parser> = {
55 let mut parser = tree_sitter::Parser::new();
56 parser.set_language(&tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()).unwrap();
57 RefCell::new(parser)
58 };
59 }
60
61 PARSER.with(|parser| {
62 let mut parser = parser.borrow_mut();
63 let bytes = text.as_ref();
64 let tree = parser.parse(bytes, None)?;
65 Some(Box::new(TreeSitterParseTree { tree }) as Box<dyn ParseTree>)
66 })
67 }
68
69 fn supported_extensions_impl() -> &'static [&'static str] {
70 &["ts", "mts", "cts"]
71 }
72
73 fn manifest_name_impl() -> &'static str {
74 "package.json"
75 }
76
77 fn container_dirs_impl() -> &'static [&'static str] {
78 &["src", "lib", "dist", "build", "out", "source"]
79 }
80
81 fn is_test_attribute_impl(node: &dyn ParseNode, source: &[u8]) -> bool {
84 let kind_id = node.kind_id();
85
86 if kind_id == LangTypeScript::decorator {
88 let start = node.start_byte();
89 let end = node.end_byte();
90 if end <= start || end > source.len() {
91 return false;
92 }
93
94 let attr_text = match std::str::from_utf8(&source[start..end]) {
95 Ok(text) => text,
96 Err(_) => return false,
97 };
98
99 return attr_text.contains("@Test")
101 || attr_text.contains("@test")
102 || attr_text.contains("@it")
103 || attr_text.contains("@describe");
104 }
105
106 false
107 }
108
109 fn collect_symbols_impl<'tcx, C>(
110 unit: CompileUnit<'tcx>,
111 node: HirNode<'tcx>,
112 scope_stack: ScopeStack<'tcx>,
113 config: &C,
114 ) -> &'tcx Scope<'tcx> {
115 unsafe {
116 let config_ref = config as *const C as *const ResolverOption;
117 crate::collect::collect_symbols(unit, &node, scope_stack, &*config_ref)
118 }
119 }
120
121 fn bind_symbols_impl<'tcx, C>(
122 unit: CompileUnit<'tcx>,
123 node: HirNode<'tcx>,
124 globals: &'tcx Scope<'tcx>,
125 config: &C,
126 ) {
127 unsafe {
128 let config = config as *const C as *const ResolverOption;
129 crate::bind::bind_symbols(unit, &node, globals, &*config);
130 }
131 }
132}