Skip to content

Commit 112d1fd

Browse files
authored
Merge pull request #56 from zerochae/refactor/oop-structure-improvement
refactor: convert to middleclass OOP architecture and improve code organization
2 parents d1bb4c4 + cec9b97 commit 112d1fd

45 files changed

Lines changed: 2259 additions & 1335 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

doc/endpoint.txt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,8 @@ endpoint.nvim uses a modern Object-Oriented architecture with:
294294
• Framework: Base class for all framework implementations
295295
• Parser: Handles endpoint parsing specific to each framework
296296
• Detector: Unified detection system (integrated into Framework)
297-
• EndpointManager: Manages all registered frameworks
297+
• Endpoint: Main orchestrator managing all components
298+
• FrameworkRegistry: Manages framework registration and detection
298299

299300
Framework Detection:~
300301

@@ -364,7 +365,7 @@ The plugin uses a modern OOP architecture. Each framework consists of:
364365
1. Framework Class (inherits from base Framework)
365366
2. Parser Class (inherits from base Parser)
366367

367-
Framework classes must be registered in EndpointManager.lua.
368+
Framework classes are automatically registered in FrameworkRegistry.
368369

369370
See wiki/Adding-New-Frameworks.md for detailed implementation guide.
370371

@@ -389,7 +390,7 @@ A: Verify detection files exist:
389390
• Spring: pom.xml, build.gradle, or application config files
390391
• Rails: Gemfile, config/routes.rb, or app/controllers/
391392
• Express: package.json with express dependency
392-
• Check EndpointManager registration for your framework
393+
• Check FrameworkRegistry for your framework registration
393394

394395
Q: Icons not displaying
395396
A: Ensure:
@@ -412,7 +413,7 @@ A: Consider:
412413

413414
Debug Information:~
414415
View current config: `lua print(vim.inspect(require("endpoint").get_config()))`
415-
Check framework detection: `lua print(vim.inspect(require("endpoint.manager.EndpointManager"):new():get_detected_frameworks()))`
416+
Check framework detection: `lua print(vim.inspect(require("endpoint").detect_frameworks()))`
416417
Clear cache and retry: `:Endpoint ClearCache`
417418
Enable framework debugging: `lua vim.g.endpoint_debug = true`
418419

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,31 @@
1-
---@class endpoint.CacheManager
2-
local CacheManager = {}
3-
CacheManager.__index = CacheManager
1+
local class = require "endpoint.lib.middleclass"
42

5-
function CacheManager:new()
6-
local cache_instance = setmetatable({}, self)
7-
cache_instance.cached_endpoints = {}
8-
cache_instance.cache_timestamps = {}
9-
cache_instance.cache_mode = "session" -- Will be set by EndpointManager
10-
return cache_instance
3+
---@class endpoint.Cache
4+
local Cache = class "Cache"
5+
6+
function Cache:initialize()
7+
self.cached_endpoints = {}
8+
self.cache_timestamps = {}
9+
self.cache_mode = "session"
1110
end
1211

13-
function CacheManager:set_mode(mode)
12+
function Cache:set_mode(mode)
1413
self.cache_mode = mode
1514
end
1615

17-
function CacheManager:_get_cache_key(method)
16+
function Cache:_get_cache_key(method)
1817
return method or "all"
1918
end
2019

21-
function CacheManager:_get_cache_dir()
20+
function Cache:_get_cache_dir()
2221
return vim.fn.stdpath "cache" .. "/endpoint.nvim"
2322
end
2423

25-
function CacheManager:_get_project_hash()
26-
-- Use current working directory name as simple project identifier
27-
return vim.fn.fnamemodify(vim.fn.getcwd(), ":t"):gsub("[^%w]", "_")
24+
function Cache:_get_project_hash()
25+
return (vim.fn.fnamemodify(vim.fn.getcwd(), ":t"):gsub("[^%w]", "_"))
2826
end
2927

30-
function CacheManager:_get_cache_file_path(method)
28+
function Cache:_get_cache_file_path(method)
3129
local cache_dir = self:_get_cache_dir()
3230
local project_hash = self:_get_project_hash()
3331
local cache_key = self:_get_cache_key(method)
@@ -40,24 +38,24 @@ function CacheManager:_get_cache_file_path(method)
4038
end
4139
end
4240

43-
function CacheManager:_ensure_cache_dir()
41+
function Cache:_ensure_cache_dir()
4442
local cache_dir = self:_get_cache_dir()
4543
if vim.fn.isdirectory(cache_dir) == 0 then
4644
vim.fn.mkdir(cache_dir, "p")
4745
end
4846
end
4947

50-
function CacheManager:is_valid(method)
48+
function Cache:is_valid(method)
5149
if self.cache_mode == "persistent" then
5250
local loaded_data = self:_load_from_disk(method)
5351
return loaded_data ~= nil and #loaded_data > 0
5452
else
5553
local cache_key = self:_get_cache_key(method)
56-
return self.cached_endpoints[cache_key] and #self.cached_endpoints[cache_key] > 0
54+
return self.cached_endpoints[cache_key] ~= nil and #self.cached_endpoints[cache_key] > 0
5755
end
5856
end
5957

60-
function CacheManager:get_endpoints(method)
58+
function Cache:get_endpoints(method)
6159
if self.cache_mode == "persistent" then
6260
local endpoints = self:_load_from_disk(method)
6361
return endpoints or {}
@@ -67,7 +65,7 @@ function CacheManager:get_endpoints(method)
6765
end
6866
end
6967

70-
function CacheManager:save_endpoints(endpoints, method)
68+
function Cache:save_endpoints(endpoints, method)
7169
local cache_key = self:_get_cache_key(method)
7270

7371
-- Always save to memory for session access
@@ -80,7 +78,7 @@ function CacheManager:save_endpoints(endpoints, method)
8078
end
8179
end
8280

83-
function CacheManager:_save_to_disk(endpoints, method)
81+
function Cache:_save_to_disk(endpoints, method)
8482
local success, err = pcall(function()
8583
self:_ensure_cache_dir()
8684
local file_path = self:_get_cache_file_path(method)
@@ -104,7 +102,7 @@ function CacheManager:_save_to_disk(endpoints, method)
104102
end
105103
end
106104

107-
function CacheManager:_serialize_table(tbl)
105+
function Cache:_serialize_table(tbl)
108106
if type(tbl) ~= "table" then
109107
if type(tbl) == "string" then
110108
return string.format("%q", tbl)
@@ -132,7 +130,7 @@ function CacheManager:_serialize_table(tbl)
132130
return table.concat(parts)
133131
end
134132

135-
function CacheManager:_load_from_disk(method)
133+
function Cache:_load_from_disk(method)
136134
local success, result = pcall(function()
137135
local file_path = self:_get_cache_file_path(method)
138136

@@ -158,7 +156,7 @@ function CacheManager:_load_from_disk(method)
158156
end
159157
end
160158

161-
function CacheManager:clear()
159+
function Cache:clear()
162160
self.cached_endpoints = {}
163161
self.cache_timestamps = {}
164162

@@ -168,7 +166,7 @@ function CacheManager:clear()
168166
end
169167
end
170168

171-
function CacheManager:_clear_disk_cache()
169+
function Cache:_clear_disk_cache()
172170
local success, err = pcall(function()
173171
local cache_dir = self:_get_cache_dir()
174172
local project_hash = self:_get_project_hash()
@@ -194,7 +192,7 @@ function CacheManager:_clear_disk_cache()
194192
end
195193
end
196194

197-
function CacheManager:get_stats()
195+
function Cache:get_stats()
198196
local total_endpoints = 0
199197
for _, endpoints in pairs(self.cached_endpoints) do
200198
total_endpoints = total_endpoints + #endpoints
@@ -208,5 +206,5 @@ function CacheManager:get_stats()
208206
}
209207
end
210208

211-
-- Export the CacheManager class for OOP usage
212-
return CacheManager
209+
-- Export the Cache class for OOP usage
210+
return Cache

lua/endpoint/core/Detector.lua

Lines changed: 40 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,34 @@
11
local fs = require "endpoint.utils.fs"
2+
local class = require "endpoint.lib.middleclass"
23

34
---@class endpoint.Detector
4-
local Detector = {}
5-
Detector.__index = Detector
6-
7-
---Creates a new Detector instance with optional fields
8-
function Detector:new(detection_name, fields)
9-
local detector = setmetatable({}, self)
10-
detector.detection_name = detection_name or "unknown"
11-
12-
-- Set additional fields if provided
13-
if fields then
14-
for key, value in pairs(fields) do
15-
detector[key] = value
16-
end
17-
end
18-
19-
return detector
20-
end
5+
local Detector = class "Detector"
216

22-
---Creates a new Detector for dependency-based detection
23-
function Detector:new_dependency_detector(required_dependencies, manifest_files, detection_name)
24-
local detector = self:new(detection_name or "dependency_based_detection", {
25-
required_dependencies = required_dependencies or {},
26-
manifest_files = manifest_files or {},
27-
})
28-
return detector
7+
function Detector:initialize(required_dependencies, manifest_files, detection_name)
8+
self.detection_name = detection_name or "dependency_detection"
9+
self.required_dependencies = required_dependencies or {}
10+
self.manifest_files = manifest_files or {}
2911
end
3012

31-
---Detects if any of the required dependencies are present in manifest files
3213
function Detector:is_target_detected()
33-
-- If we have dependencies and manifest files, use dependency detection
34-
if self.required_dependencies and self.manifest_files then
35-
-- First check root level manifest files
36-
for _, manifest_file_path in ipairs(self.manifest_files) do
37-
if fs.has_file { manifest_file_path } then
38-
if self:_check_manifest_file_for_dependencies(manifest_file_path) then
39-
return true
40-
end
14+
for _, manifest_file_path in ipairs(self.manifest_files) do
15+
if fs.has_file { manifest_file_path } then
16+
if self:_check_manifest_file_for_dependencies(manifest_file_path) then
17+
return true
4118
end
4219
end
20+
end
4321

44-
-- For Maven projects, also check submodules
45-
if self:_should_check_submodules() then
46-
local submodule_manifest_files = self:_find_submodule_manifest_files()
47-
for _, submodule_manifest_path in ipairs(submodule_manifest_files) do
48-
if self:_check_manifest_file_for_dependencies(submodule_manifest_path) then
49-
return true
50-
end
22+
if self:_should_check_submodules() then
23+
local submodule_manifest_files = self:_find_submodule_manifest_files()
24+
for _, submodule_manifest_path in ipairs(submodule_manifest_files) do
25+
if self:_check_manifest_file_for_dependencies(submodule_manifest_path) then
26+
return true
5127
end
5228
end
53-
54-
return false
5529
end
5630

57-
-- Default implementation for subclasses
58-
error("is_target_detected() must be implemented by subclass: " .. self.detection_name)
31+
return false
5932
end
6033

6134
---Checks a specific manifest file for required dependencies
@@ -74,89 +47,66 @@ function Detector:get_name()
7447
return self.detection_name
7548
end
7649

77-
---Gets detailed information about what was detected
7850
function Detector:get_detection_details()
7951
if not self:is_target_detected() then
8052
return nil
8153
end
8254

83-
local base_details = {
84-
detector_name = self.detection_name,
85-
detected_at = os.time(),
86-
is_detected = true,
87-
}
55+
local detected_dependencies = {}
56+
local searched_manifest_files = {}
57+
58+
for _, manifest_file_path in ipairs(self.manifest_files) do
59+
if fs.has_file { manifest_file_path } then
60+
table.insert(searched_manifest_files, manifest_file_path)
8861

89-
-- Add dependency-specific details if applicable
90-
if self.required_dependencies and self.manifest_files then
91-
local detected_dependencies = {}
92-
local searched_manifest_files = {}
93-
94-
for _, manifest_file_path in ipairs(self.manifest_files) do
95-
if fs.has_file { manifest_file_path } then
96-
table.insert(searched_manifest_files, manifest_file_path)
97-
98-
for _, required_dependency_identifier in ipairs(self.required_dependencies) do
99-
if fs.file_contains(manifest_file_path, required_dependency_identifier) then
100-
table.insert(detected_dependencies, {
101-
dependency_identifier = required_dependency_identifier,
102-
found_in_manifest = manifest_file_path,
103-
})
104-
end
62+
for _, required_dependency_identifier in ipairs(self.required_dependencies) do
63+
if fs.file_contains(manifest_file_path, required_dependency_identifier) then
64+
table.insert(detected_dependencies, {
65+
dependency_identifier = required_dependency_identifier,
66+
found_in_manifest = manifest_file_path,
67+
})
10568
end
10669
end
10770
end
108-
109-
base_details.detected_dependencies = detected_dependencies
110-
base_details.searched_manifest_files = searched_manifest_files
111-
base_details.total_required_dependencies = #self.required_dependencies
112-
base_details.total_detected_dependencies = #detected_dependencies
11371
end
11472

115-
return base_details
73+
return {
74+
detector_name = self.detection_name,
75+
detected_at = os.time(),
76+
is_detected = true,
77+
detected_dependencies = detected_dependencies,
78+
searched_manifest_files = searched_manifest_files,
79+
total_required_dependencies = #self.required_dependencies,
80+
total_detected_dependencies = #detected_dependencies,
81+
}
11682
end
11783

118-
---Adds additional required dependencies to the detection criteria
11984
function Detector:add_required_dependencies(additional_dependencies)
120-
if not self.required_dependencies then
121-
self.required_dependencies = {}
122-
end
12385
for _, additional_dependency_identifier in ipairs(additional_dependencies) do
12486
table.insert(self.required_dependencies, additional_dependency_identifier)
12587
end
12688
end
12789

128-
---Adds additional manifest files to search in
12990
function Detector:add_manifest_files(additional_manifest_files)
130-
if not self.manifest_files then
131-
self.manifest_files = {}
132-
end
13391
for _, additional_manifest_file_path in ipairs(additional_manifest_files) do
13492
table.insert(self.manifest_files, additional_manifest_file_path)
13593
end
13694
end
13795

138-
---Gets the list of required dependencies
13996
function Detector:get_required_dependencies()
140-
return vim.deepcopy(self.required_dependencies or {})
97+
return vim.deepcopy(self.required_dependencies)
14198
end
14299

143-
---Gets the list of manifest files to search
144100
function Detector:get_manifest_files()
145-
return vim.deepcopy(self.manifest_files or {})
101+
return vim.deepcopy(self.manifest_files)
146102
end
147103

148104
function Detector:_should_check_submodules()
149-
if not self.manifest_files then
150-
return false
151-
end
152-
153-
-- Check if this is a Maven project
154105
for _, manifest_file in ipairs(self.manifest_files) do
155106
if manifest_file == "pom.xml" then
156107
return fs.has_file { "pom.xml" }
157108
end
158109
end
159-
160110
return false
161111
end
162112

0 commit comments

Comments
 (0)