1+ // Copyright 2025 CloudWeGo Authors
2+ //
3+ // Licensed under the Apache License, Version 2.0 (the "License");
4+ // you may not use this file except in compliance with the License.
5+ // You may obtain a copy of the License at
6+ //
7+ // https://www.apache.org/licenses/LICENSE-2.0
8+ //
9+ // Unless required by applicable law or agreed to in writing, software
10+ // distributed under the License is distributed on an "AS IS" BASIS,
11+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ // See the License for the specific language governing permissions and
13+ // limitations under the License.
14+
15+ package typescript
16+
17+ import (
18+ "fmt"
19+ "path/filepath"
20+ "strings"
21+
22+ lsp "github.com/cloudwego/abcoder/lang/lsp"
23+ "github.com/cloudwego/abcoder/lang/uniast"
24+ )
25+
26+ var _ lsp.LanguageSpec = (* TypeScriptSpec )(nil )
27+
28+ type TypeScriptSpec struct {
29+ repo string
30+ }
31+
32+ func NewTypeScriptSpec () * TypeScriptSpec {
33+ return & TypeScriptSpec {}
34+ }
35+
36+ func (c * TypeScriptSpec ) FileImports (content []byte ) ([]uniast.Import , error ) {
37+ // TODO: Parse TypeScript import statements
38+ return []uniast.Import {}, nil
39+ }
40+
41+ func (c * TypeScriptSpec ) IsExternalEntityToken (tok lsp.Token ) bool {
42+ if ! c .IsEntityToken (tok ) {
43+ return false
44+ }
45+ for _ , m := range tok .Modifiers {
46+ if m == "defaultLibrary" {
47+ return true
48+ }
49+ }
50+ return false
51+ }
52+
53+ func (c * TypeScriptSpec ) TokenKind (tok lsp.Token ) lsp.SymbolKind {
54+ switch tok .Type {
55+ case "class" :
56+ return lsp .SKClass
57+ case "interface" :
58+ return lsp .SKInterface
59+ case "function" :
60+ return lsp .SKFunction
61+ case "method" :
62+ return lsp .SKMethod
63+ case "property" :
64+ return lsp .SKProperty
65+ case "variable" :
66+ return lsp .SKVariable
67+ case "const" :
68+ return lsp .SKConstant
69+ case "enum" :
70+ return lsp .SKEnum
71+ case "enumMember" :
72+ return lsp .SKEnumMember
73+ case "type" :
74+ return lsp .SKTypeParameter
75+ case "namespace" :
76+ return lsp .SKNamespace
77+ case "module" :
78+ return lsp .SKModule
79+ default :
80+ return lsp .SKUnknown
81+ }
82+ }
83+
84+ func (c * TypeScriptSpec ) IsStdToken (tok lsp.Token ) bool {
85+ for _ , m := range tok .Modifiers {
86+ if m == "defaultLibrary" {
87+ return true
88+ }
89+ }
90+ return false
91+ }
92+
93+ func (c * TypeScriptSpec ) IsDocToken (tok lsp.Token ) bool {
94+ for _ , m := range tok .Modifiers {
95+ if m == "documentation" {
96+ return true
97+ }
98+ }
99+ return false
100+ }
101+
102+ func (c * TypeScriptSpec ) DeclareTokenOfSymbol (sym lsp.DocumentSymbol ) int {
103+ for i , t := range sym .Tokens {
104+ if c .IsDocToken (t ) {
105+ continue
106+ }
107+ for _ , m := range t .Modifiers {
108+ if m == "declaration" {
109+ return i
110+ }
111+ }
112+ }
113+ return - 1
114+ }
115+
116+ func (c * TypeScriptSpec ) IsPublicSymbol (sym lsp.DocumentSymbol ) bool {
117+ // In TypeScript, symbols are public by default unless marked private/protected
118+ id := c .DeclareTokenOfSymbol (sym )
119+ if id == - 1 {
120+ return true
121+ }
122+ for _ , m := range sym .Tokens [id ].Modifiers {
123+ if m == "private" || m == "protected" {
124+ return false
125+ }
126+ }
127+ return true
128+ }
129+
130+ func (c * TypeScriptSpec ) IsMainFunction (sym lsp.DocumentSymbol ) bool {
131+ // TypeScript doesn't have a main function concept
132+ return false
133+ }
134+
135+ func (c * TypeScriptSpec ) IsEntitySymbol (sym lsp.DocumentSymbol ) bool {
136+ typ := sym .Kind
137+ return typ == lsp .SKClass || typ == lsp .SKMethod || typ == lsp .SKFunction ||
138+ typ == lsp .SKVariable || typ == lsp .SKInterface || typ == lsp .SKConstant ||
139+ typ == lsp .SKEnum || typ == lsp .SKTypeParameter || typ == lsp .SKNamespace ||
140+ typ == lsp .SKModule
141+ }
142+
143+ func (c * TypeScriptSpec ) IsEntityToken (tok lsp.Token ) bool {
144+ typ := tok .Type
145+ return typ == "class" || typ == "interface" || typ == "function" ||
146+ typ == "method" || typ == "property" || typ == "variable" ||
147+ typ == "const" || typ == "enum" || typ == "enumMember" ||
148+ typ == "type" || typ == "namespace" || typ == "module"
149+ }
150+
151+ func (c * TypeScriptSpec ) HasImplSymbol () bool {
152+ // TypeScript uses class/interface implementation, not impl blocks like Rust
153+ return false
154+ }
155+
156+ func (c * TypeScriptSpec ) ImplSymbol (sym lsp.DocumentSymbol ) (int , int , int ) {
157+ // TypeScript doesn't have impl blocks
158+ return - 1 , - 1 , - 1
159+ }
160+
161+ func (c * TypeScriptSpec ) FunctionSymbol (sym lsp.DocumentSymbol ) (int , []int , []int , []int ) {
162+ // TODO: Implement TypeScript function parsing
163+ return - 1 , nil , nil , nil
164+ }
165+
166+ func (c * TypeScriptSpec ) ShouldSkip (path string ) bool {
167+ if strings .Contains (path , "/node_modules/" ) {
168+ return true
169+ }
170+ if ! strings .HasSuffix (path , ".ts" ) && ! strings .HasSuffix (path , ".tsx" ) {
171+ return true
172+ }
173+ return false
174+ }
175+
176+ func (c * TypeScriptSpec ) NameSpace (path string ) (string , string , error ) {
177+ if ! strings .HasPrefix (path , c .repo ) {
178+ // External module
179+ return "" , "" , fmt .Errorf ("external module: %s" , path )
180+ }
181+
182+ // Calculate relative path from repo root
183+ rel , err := filepath .Rel (c .repo , path )
184+ if err != nil {
185+ return "" , "" , err
186+ }
187+
188+ // Remove file extension
189+ rel = strings .TrimSuffix (rel , ".ts" )
190+ rel = strings .TrimSuffix (rel , ".tsx" )
191+
192+ // Remove index suffix if present
193+ if strings .HasSuffix (rel , "/index" ) {
194+ rel = strings .TrimSuffix (rel , "/index" )
195+ }
196+
197+ // Convert path to module name
198+ module := strings .ReplaceAll (rel , string (filepath .Separator ), "." )
199+
200+ return module , module , nil
201+ }
202+
203+ func (c * TypeScriptSpec ) WorkSpace (root string ) (map [string ]string , error ) {
204+ c .repo = root
205+ // For TypeScript, we don't need to collect modules like Rust
206+ // The module system is based on file paths
207+ return map [string ]string {}, nil
208+ }
209+
210+ func (c * TypeScriptSpec ) GetUnloadedSymbol (from lsp.Token , loc lsp.Location ) (string , error ) {
211+ // TODO: Implement TypeScript unloaded symbol extraction
212+ return "" , nil
213+ }
0 commit comments