feat(ts): extract interface, enum, type_alias, const literal, new_expression
Bring TypeScript AST extraction to parity with Java and C# by adding the declaration types upstream graphify currently skips: - interface_declaration (parity with Java/C# class_types) - enum_declaration + members - type_alias_declaration - module-level const literals (object/array/string/call/new/template/number) via _js_extra_walk extension - new_expression as call type for both _JS_CONFIG and _TS_CONFIG Tested against tests/fixtures/typescript_advanced.ts: 8 expected node types extracted (IUserRepository, UserStatus, UserId, USER_REPOSITORY, DEFAULT_ROLES, USER_CONFIG, UserService, UserModule). Validated on a 3,800-file TypeScript monorepo (NestJS + Next.js): yields ~1,885 interfaces, ~147 enums, ~405 type aliases, ~2,236 const literal nodes, and ~1,935 instantiates edges that were previously invisible.
This commit is contained in:
+25
-4
@@ -611,7 +611,11 @@ def _get_cpp_func_name(node, source: bytes) -> str | None:
|
||||
def _js_extra_walk(node, source: bytes, file_nid: str, stem: str, str_path: str,
|
||||
nodes: list, edges: list, seen_ids: set, function_bodies: list,
|
||||
parent_class_nid: str | None, add_node_fn, add_edge_fn) -> bool:
|
||||
"""Handle lexical_declaration (arrow functions) for JS/TS. Returns True if handled."""
|
||||
"""Handle lexical_declaration for JS/TS:
|
||||
- arrow functions / function expressions (existing behaviour)
|
||||
- module-level const literals (object/array/string/call/new/etc.) — TS codebases
|
||||
use these for configs, route maps, DI tokens, enum-like unions.
|
||||
Returns True if handled."""
|
||||
if node.type == "lexical_declaration":
|
||||
for child in node.children:
|
||||
if child.type == "variable_declarator":
|
||||
@@ -627,6 +631,18 @@ def _js_extra_walk(node, source: bytes, file_nid: str, stem: str, str_path: str,
|
||||
body = value.child_by_field_name("body")
|
||||
if body:
|
||||
function_bodies.append((func_nid, body))
|
||||
elif value and value.type in (
|
||||
"object", "array", "as_expression", "call_expression",
|
||||
"new_expression", "string", "template_string", "number",
|
||||
):
|
||||
# Module-level const with literal/object/array/factory value
|
||||
name_node = child.child_by_field_name("name")
|
||||
if name_node:
|
||||
const_name = _read_text(name_node, source)
|
||||
line = child.start_point[0] + 1
|
||||
const_nid = _make_id(stem, const_name)
|
||||
add_node_fn(const_nid, const_name, line)
|
||||
add_edge_fn(file_nid, const_nid, "contains", line)
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -692,7 +708,7 @@ _JS_CONFIG = LanguageConfig(
|
||||
class_types=frozenset({"class_declaration"}),
|
||||
function_types=frozenset({"function_declaration", "method_definition"}),
|
||||
import_types=frozenset({"import_statement"}),
|
||||
call_types=frozenset({"call_expression"}),
|
||||
call_types=frozenset({"call_expression", "new_expression"}),
|
||||
call_function_field="function",
|
||||
call_accessor_node_types=frozenset({"member_expression"}),
|
||||
call_accessor_field="property",
|
||||
@@ -703,10 +719,15 @@ _JS_CONFIG = LanguageConfig(
|
||||
_TS_CONFIG = LanguageConfig(
|
||||
ts_module="tree_sitter_typescript",
|
||||
ts_language_fn="language_typescript",
|
||||
class_types=frozenset({"class_declaration"}),
|
||||
class_types=frozenset({
|
||||
"class_declaration",
|
||||
"interface_declaration", # parity with Java/C#
|
||||
"enum_declaration", # named enums
|
||||
"type_alias_declaration", # named type aliases
|
||||
}),
|
||||
function_types=frozenset({"function_declaration", "method_definition"}),
|
||||
import_types=frozenset({"import_statement"}),
|
||||
call_types=frozenset({"call_expression"}),
|
||||
call_types=frozenset({"call_expression", "new_expression"}),
|
||||
call_function_field="function",
|
||||
call_accessor_node_types=frozenset({"member_expression"}),
|
||||
call_accessor_field="property",
|
||||
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
// Test fixture for upstream PR — exercises every new extraction path.
|
||||
//
|
||||
// Expected nodes after this PR:
|
||||
// - IUserRepository (interface)
|
||||
// - UserStatus (enum) + Active, Inactive (members)
|
||||
// - UserId (type_alias)
|
||||
// - USER_REPOSITORY (const, value=call_expression)
|
||||
// - DEFAULT_ROLES (const, value=array)
|
||||
// - USER_CONFIG (const, value=object)
|
||||
// - UserService (class — already extracted by current code)
|
||||
// - UserModule (class — already extracted)
|
||||
//
|
||||
// Expected edges after this PR:
|
||||
// - UserService.create() --instantiates--> User
|
||||
// - UserService.bulkCreate() --instantiates--> Array
|
||||
// - UserModule --provides--> UserService
|
||||
// - UserModule --provides--> USER_REPOSITORY (via { provide, useClass } detection — optional)
|
||||
// - UserModule --exports--> UserService
|
||||
|
||||
import { Module, Injectable } from '@nestjs/common';
|
||||
import type { User } from './user.entity';
|
||||
|
||||
export interface IUserRepository {
|
||||
findById(id: string): Promise<User | null>;
|
||||
save(user: User): Promise<void>;
|
||||
}
|
||||
|
||||
export enum UserStatus {
|
||||
Active = 'ACTIVE',
|
||||
Inactive = 'INACTIVE',
|
||||
Suspended = 'SUSPENDED',
|
||||
}
|
||||
|
||||
export type UserId = string;
|
||||
|
||||
export const USER_REPOSITORY = Symbol('USER_REPOSITORY');
|
||||
|
||||
export const DEFAULT_ROLES = ['admin', 'editor', 'user'] as const;
|
||||
|
||||
export const USER_CONFIG = {
|
||||
maxRetries: 3,
|
||||
timeoutMs: 5000,
|
||||
features: {
|
||||
twoFactor: true,
|
||||
sso: false,
|
||||
},
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
constructor(private repo: IUserRepository) {}
|
||||
|
||||
create(name: string): User {
|
||||
return new User(name);
|
||||
}
|
||||
|
||||
bulkCreate(names: string[]): User[] {
|
||||
return names.map((n) => new User(n));
|
||||
}
|
||||
}
|
||||
|
||||
@Module({
|
||||
providers: [
|
||||
UserService,
|
||||
{ provide: USER_REPOSITORY, useClass: PrismaUserRepository },
|
||||
],
|
||||
exports: [UserService],
|
||||
})
|
||||
export class UserModule {}
|
||||
Reference in New Issue
Block a user