@wtdlee/repomap 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +527 -0
- package/dist/analyzers/base-analyzer.d.ts +46 -0
- package/dist/analyzers/base-analyzer.d.ts.map +1 -0
- package/dist/analyzers/base-analyzer.js +48 -0
- package/dist/analyzers/base-analyzer.js.map +1 -0
- package/dist/analyzers/dataflow-analyzer.d.ts +30 -0
- package/dist/analyzers/dataflow-analyzer.d.ts.map +1 -0
- package/dist/analyzers/dataflow-analyzer.js +426 -0
- package/dist/analyzers/dataflow-analyzer.js.map +1 -0
- package/dist/analyzers/graphql-analyzer.d.ts +23 -0
- package/dist/analyzers/graphql-analyzer.d.ts.map +1 -0
- package/dist/analyzers/graphql-analyzer.js +387 -0
- package/dist/analyzers/graphql-analyzer.js.map +1 -0
- package/dist/analyzers/index.d.ts +6 -0
- package/dist/analyzers/index.d.ts.map +1 -0
- package/dist/analyzers/index.js +6 -0
- package/dist/analyzers/index.js.map +1 -0
- package/dist/analyzers/pages-analyzer.d.ts +85 -0
- package/dist/analyzers/pages-analyzer.d.ts.map +1 -0
- package/dist/analyzers/pages-analyzer.js +1696 -0
- package/dist/analyzers/pages-analyzer.js.map +1 -0
- package/dist/analyzers/rails/index.d.ts +47 -0
- package/dist/analyzers/rails/index.d.ts.map +1 -0
- package/dist/analyzers/rails/index.js +146 -0
- package/dist/analyzers/rails/index.js.map +1 -0
- package/dist/analyzers/rails/rails-controller-analyzer.d.ts +83 -0
- package/dist/analyzers/rails/rails-controller-analyzer.d.ts.map +1 -0
- package/dist/analyzers/rails/rails-controller-analyzer.js +479 -0
- package/dist/analyzers/rails/rails-controller-analyzer.js.map +1 -0
- package/dist/analyzers/rails/rails-grpc-analyzer.d.ts +45 -0
- package/dist/analyzers/rails/rails-grpc-analyzer.d.ts.map +1 -0
- package/dist/analyzers/rails/rails-grpc-analyzer.js +263 -0
- package/dist/analyzers/rails/rails-grpc-analyzer.js.map +1 -0
- package/dist/analyzers/rails/rails-model-analyzer.d.ts +89 -0
- package/dist/analyzers/rails/rails-model-analyzer.d.ts.map +1 -0
- package/dist/analyzers/rails/rails-model-analyzer.js +494 -0
- package/dist/analyzers/rails/rails-model-analyzer.js.map +1 -0
- package/dist/analyzers/rails/rails-react-analyzer.d.ts +42 -0
- package/dist/analyzers/rails/rails-react-analyzer.d.ts.map +1 -0
- package/dist/analyzers/rails/rails-react-analyzer.js +530 -0
- package/dist/analyzers/rails/rails-react-analyzer.js.map +1 -0
- package/dist/analyzers/rails/rails-routes-analyzer.d.ts +63 -0
- package/dist/analyzers/rails/rails-routes-analyzer.d.ts.map +1 -0
- package/dist/analyzers/rails/rails-routes-analyzer.js +541 -0
- package/dist/analyzers/rails/rails-routes-analyzer.js.map +1 -0
- package/dist/analyzers/rails/rails-view-analyzer.d.ts +50 -0
- package/dist/analyzers/rails/rails-view-analyzer.d.ts.map +1 -0
- package/dist/analyzers/rails/rails-view-analyzer.js +387 -0
- package/dist/analyzers/rails/rails-view-analyzer.js.map +1 -0
- package/dist/analyzers/rails/ruby-parser.d.ts +64 -0
- package/dist/analyzers/rails/ruby-parser.d.ts.map +1 -0
- package/dist/analyzers/rails/ruby-parser.js +213 -0
- package/dist/analyzers/rails/ruby-parser.js.map +1 -0
- package/dist/analyzers/rest-api-analyzer.d.ts +66 -0
- package/dist/analyzers/rest-api-analyzer.d.ts.map +1 -0
- package/dist/analyzers/rest-api-analyzer.js +480 -0
- package/dist/analyzers/rest-api-analyzer.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +550 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/cache.d.ts +48 -0
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js +152 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/engine.d.ts +47 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +320 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +1 -0
- package/dist/generators/assets/common.css +187 -0
- package/dist/generators/assets/docs.css +363 -0
- package/dist/generators/assets/page-map.css +305 -0
- package/dist/generators/assets/rails-map.css +473 -0
- package/dist/generators/index.d.ts +4 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +4 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/generators/markdown-generator.d.ts +26 -0
- package/dist/generators/markdown-generator.d.ts.map +1 -0
- package/dist/generators/markdown-generator.js +783 -0
- package/dist/generators/markdown-generator.js.map +1 -0
- package/dist/generators/mermaid-generator.d.ts +36 -0
- package/dist/generators/mermaid-generator.d.ts.map +1 -0
- package/dist/generators/mermaid-generator.js +365 -0
- package/dist/generators/mermaid-generator.js.map +1 -0
- package/dist/generators/page-map-generator.d.ts +23 -0
- package/dist/generators/page-map-generator.d.ts.map +1 -0
- package/dist/generators/page-map-generator.js +3563 -0
- package/dist/generators/page-map-generator.js.map +1 -0
- package/dist/generators/rails-map-generator.d.ts +22 -0
- package/dist/generators/rails-map-generator.d.ts.map +1 -0
- package/dist/generators/rails-map-generator.js +909 -0
- package/dist/generators/rails-map-generator.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/server/doc-server.d.ts +31 -0
- package/dist/server/doc-server.d.ts.map +1 -0
- package/dist/server/doc-server.js +1233 -0
- package/dist/server/doc-server.js.map +1 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +2 -0
- package/dist/server/index.js.map +1 -0
- package/dist/types.d.ts +294 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/env-detector.d.ts +32 -0
- package/dist/utils/env-detector.d.ts.map +1 -0
- package/dist/utils/env-detector.js +189 -0
- package/dist/utils/env-detector.js.map +1 -0
- package/dist/utils/parallel.d.ts +24 -0
- package/dist/utils/parallel.d.ts.map +1 -0
- package/dist/utils/parallel.js +71 -0
- package/dist/utils/parallel.js.map +1 -0
- package/package.json +131 -0
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rails View Analyzer
|
|
3
|
+
* Analyzes HAML/ERB views and their connections to controllers and APIs
|
|
4
|
+
*/
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import * as fs from 'fs/promises';
|
|
7
|
+
import { glob } from 'glob';
|
|
8
|
+
export async function analyzeRailsViews(rootPath) {
|
|
9
|
+
const viewsPath = path.join(rootPath, 'app/views');
|
|
10
|
+
const controllersPath = path.join(rootPath, 'app/controllers');
|
|
11
|
+
// Check if views directory exists
|
|
12
|
+
try {
|
|
13
|
+
await fs.access(viewsPath);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return {
|
|
17
|
+
views: [],
|
|
18
|
+
pages: [],
|
|
19
|
+
summary: { totalViews: 0, totalPages: 0, byController: {}, byTemplate: {} },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// Find all view files (including .yml for SSR React pages)
|
|
23
|
+
const viewFiles = await glob('**/*.{haml,erb,html.haml,html.erb,yml}', {
|
|
24
|
+
cwd: viewsPath,
|
|
25
|
+
nodir: true,
|
|
26
|
+
});
|
|
27
|
+
const views = [];
|
|
28
|
+
const byController = {};
|
|
29
|
+
const byTemplate = {};
|
|
30
|
+
for (const file of viewFiles) {
|
|
31
|
+
const view = await parseViewFile(viewsPath, file);
|
|
32
|
+
if (view) {
|
|
33
|
+
views.push(view);
|
|
34
|
+
// Count by controller
|
|
35
|
+
byController[view.controller] = (byController[view.controller] || 0) + 1;
|
|
36
|
+
// Count by template
|
|
37
|
+
byTemplate[view.template] = (byTemplate[view.template] || 0) + 1;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Analyze controllers and map to pages
|
|
41
|
+
const pages = await analyzeControllersForPages(controllersPath, views, rootPath);
|
|
42
|
+
return {
|
|
43
|
+
views,
|
|
44
|
+
pages,
|
|
45
|
+
summary: {
|
|
46
|
+
totalViews: views.length,
|
|
47
|
+
totalPages: pages.length,
|
|
48
|
+
byController,
|
|
49
|
+
byTemplate,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async function parseViewFile(viewsPath, relativePath) {
|
|
54
|
+
const fullPath = path.join(viewsPath, relativePath);
|
|
55
|
+
try {
|
|
56
|
+
const content = await fs.readFile(fullPath, 'utf-8');
|
|
57
|
+
const parts = relativePath.split('/');
|
|
58
|
+
// Skip mailer views, layouts, shared
|
|
59
|
+
if (parts.some((p) => p.endsWith('_mailer') || p === 'layouts' || p === 'shared' || p === 'devise')) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
// Parse controller and action from path
|
|
63
|
+
// e.g., users/show.html.haml -> controller: users, action: show
|
|
64
|
+
const fileName = parts.pop() || '';
|
|
65
|
+
const controller = parts.join('/') || 'application';
|
|
66
|
+
// Parse filename: action.format.template
|
|
67
|
+
const nameParts = fileName.split('.');
|
|
68
|
+
const action = nameParts[0].replace(/^_/, ''); // Remove leading underscore for partials
|
|
69
|
+
const isPartial = fileName.startsWith('_');
|
|
70
|
+
// Detect template type
|
|
71
|
+
let template;
|
|
72
|
+
if (fileName.endsWith('.yml')) {
|
|
73
|
+
template = 'yml';
|
|
74
|
+
}
|
|
75
|
+
else if (fileName.endsWith('.haml')) {
|
|
76
|
+
template = 'haml';
|
|
77
|
+
}
|
|
78
|
+
else if (fileName.endsWith('.erb')) {
|
|
79
|
+
template = 'erb';
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
template = 'other';
|
|
83
|
+
}
|
|
84
|
+
const format = nameParts.length > 2 ? nameParts[1] : 'html';
|
|
85
|
+
// Skip partials for main page list
|
|
86
|
+
if (isPartial)
|
|
87
|
+
return null;
|
|
88
|
+
// Extract information from content
|
|
89
|
+
let partials = [];
|
|
90
|
+
let helpers = [];
|
|
91
|
+
let instanceVars = [];
|
|
92
|
+
let reactComponents = [];
|
|
93
|
+
if (template === 'yml') {
|
|
94
|
+
// YML files are SSR React pages - extract data fields as "instance vars"
|
|
95
|
+
instanceVars = extractYmlFields(content);
|
|
96
|
+
// Mark as SSR React page
|
|
97
|
+
reactComponents = [{ name: 'App', ssr: true, propsVar: '@yml_data' }];
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
partials = extractPartials(content, template);
|
|
101
|
+
helpers = extractHelpers(content, template);
|
|
102
|
+
instanceVars = extractInstanceVars(content);
|
|
103
|
+
reactComponents = extractReactComponents(content, template);
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
name: action,
|
|
107
|
+
path: relativePath,
|
|
108
|
+
controller,
|
|
109
|
+
action,
|
|
110
|
+
format,
|
|
111
|
+
template,
|
|
112
|
+
partials,
|
|
113
|
+
helpers,
|
|
114
|
+
instanceVars,
|
|
115
|
+
reactComponents,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function extractPartials(content, template) {
|
|
123
|
+
const partials = [];
|
|
124
|
+
if (template === 'haml') {
|
|
125
|
+
// HAML: = render 'partial' or = render partial: 'name'
|
|
126
|
+
const matches = content.matchAll(/=\s*render\s+(?:partial:\s*)?['"]([^'"]+)['"]/g);
|
|
127
|
+
for (const match of matches) {
|
|
128
|
+
partials.push(match[1]);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else if (template === 'erb') {
|
|
132
|
+
// ERB: <%= render 'partial' %>
|
|
133
|
+
const matches = content.matchAll(/<%=?\s*render\s+(?:partial:\s*)?['"]([^'"]+)['"]/g);
|
|
134
|
+
for (const match of matches) {
|
|
135
|
+
partials.push(match[1]);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return [...new Set(partials)];
|
|
139
|
+
}
|
|
140
|
+
function extractHelpers(content, _template) {
|
|
141
|
+
const helpers = [];
|
|
142
|
+
// Common helpers: link_to, form_for, image_tag, etc.
|
|
143
|
+
const helperPattern = /\b(link_to|form_for|form_with|image_tag|content_for|yield|render|t|l|raw|html_safe|simple_form_for)\b/g;
|
|
144
|
+
const matches = content.matchAll(helperPattern);
|
|
145
|
+
for (const match of matches) {
|
|
146
|
+
helpers.push(match[1]);
|
|
147
|
+
}
|
|
148
|
+
return [...new Set(helpers)];
|
|
149
|
+
}
|
|
150
|
+
function extractReactComponents(content, _template) {
|
|
151
|
+
const components = [];
|
|
152
|
+
// Pattern 1: render_react_component "ComponentName", {}, ssr: true/false
|
|
153
|
+
// e.g., = render_react_component("App", {}, ssr: true)
|
|
154
|
+
const renderReactPattern = /render_react_component\s*\(?\s*["']([^"']+)["'](?:,\s*\{[^}]*\})?\s*(?:,\s*ssr:\s*(true|false))?\)?/g;
|
|
155
|
+
let match;
|
|
156
|
+
while ((match = renderReactPattern.exec(content)) !== null) {
|
|
157
|
+
components.push({
|
|
158
|
+
name: match[1],
|
|
159
|
+
ssr: match[2] === 'true',
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
// Pattern 2: data: { react_component: "ComponentName", react_component_props: props.to_json }
|
|
163
|
+
// e.g., %div{ data: { react_component: "OrgPage", react_component_props: @react_state.to_json } }
|
|
164
|
+
const dataReactPattern = /data:\s*\{\s*react_component:\s*["']([^"']+)["'](?:,\s*react_component_props:\s*(@?\w+)(?:\.to_json)?)?/g;
|
|
165
|
+
while ((match = dataReactPattern.exec(content)) !== null) {
|
|
166
|
+
components.push({
|
|
167
|
+
name: match[1],
|
|
168
|
+
propsVar: match[2],
|
|
169
|
+
ssr: false,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
// Pattern 3: ReactComponent name="ComponentName" (ERB style)
|
|
173
|
+
const reactComponentPattern = /ReactComponent\s+name=["']([^"']+)["']/g;
|
|
174
|
+
while ((match = reactComponentPattern.exec(content)) !== null) {
|
|
175
|
+
components.push({
|
|
176
|
+
name: match[1],
|
|
177
|
+
ssr: false,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
// Deduplicate by name
|
|
181
|
+
const seen = new Set();
|
|
182
|
+
return components.filter((c) => {
|
|
183
|
+
if (seen.has(c.name))
|
|
184
|
+
return false;
|
|
185
|
+
seen.add(c.name);
|
|
186
|
+
return true;
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
function extractYmlFields(content) {
|
|
190
|
+
// Extract top-level keys from YML file as "data fields"
|
|
191
|
+
const fields = [];
|
|
192
|
+
const lines = content.split('\n');
|
|
193
|
+
for (const line of lines) {
|
|
194
|
+
// Top-level keys (not indented)
|
|
195
|
+
const topMatch = line.match(/^([a-z_]+):/);
|
|
196
|
+
if (topMatch && !topMatch[1].startsWith('_')) {
|
|
197
|
+
fields.push(topMatch[1]);
|
|
198
|
+
}
|
|
199
|
+
// _fields array items
|
|
200
|
+
const fieldMatch = line.match(/^\s+-\s+(\w+)/);
|
|
201
|
+
if (fieldMatch) {
|
|
202
|
+
fields.push(fieldMatch[1]);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return [...new Set(fields)].slice(0, 50); // Limit to 50 fields
|
|
206
|
+
}
|
|
207
|
+
function extractInstanceVars(content) {
|
|
208
|
+
const vars = [];
|
|
209
|
+
const matches = content.matchAll(/@(\w+)/g);
|
|
210
|
+
for (const match of matches) {
|
|
211
|
+
if (!['import', 'media', 'keyframes', 'charset'].includes(match[1])) {
|
|
212
|
+
vars.push(match[1]);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return [...new Set(vars)];
|
|
216
|
+
}
|
|
217
|
+
async function analyzeControllersForPages(controllersPath, views, rootPath) {
|
|
218
|
+
const pages = [];
|
|
219
|
+
try {
|
|
220
|
+
await fs.access(controllersPath);
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
return pages;
|
|
224
|
+
}
|
|
225
|
+
const controllerFiles = await glob('**/*_controller.rb', {
|
|
226
|
+
cwd: controllersPath,
|
|
227
|
+
nodir: true,
|
|
228
|
+
});
|
|
229
|
+
// Load routes if available
|
|
230
|
+
const routesMap = await loadRoutesMap(rootPath);
|
|
231
|
+
for (const file of controllerFiles) {
|
|
232
|
+
const fullPath = path.join(controllersPath, file);
|
|
233
|
+
const content = await fs.readFile(fullPath, 'utf-8');
|
|
234
|
+
// Parse controller name from filename
|
|
235
|
+
// e.g., users_controller.rb -> users
|
|
236
|
+
const controllerName = file.replace(/_controller\.rb$/, '').replace(/\//g, '/');
|
|
237
|
+
// Extract actions and their API calls
|
|
238
|
+
const controllerPages = parseControllerActions(content, controllerName, file, views, routesMap);
|
|
239
|
+
pages.push(...controllerPages);
|
|
240
|
+
}
|
|
241
|
+
return pages;
|
|
242
|
+
}
|
|
243
|
+
async function loadRoutesMap(rootPath) {
|
|
244
|
+
const routesMap = new Map();
|
|
245
|
+
try {
|
|
246
|
+
// Try to load from previously analyzed routes
|
|
247
|
+
const railsDataPath = path.join(rootPath, '.repomap', 'rails-routes.json');
|
|
248
|
+
const data = await fs.readFile(railsDataPath, 'utf-8');
|
|
249
|
+
const routes = JSON.parse(data);
|
|
250
|
+
for (const route of routes) {
|
|
251
|
+
const key = `${route.controller}#${route.action}`;
|
|
252
|
+
routesMap.set(key, { path: route.path, method: route.method });
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
// Routes not available
|
|
257
|
+
}
|
|
258
|
+
return routesMap;
|
|
259
|
+
}
|
|
260
|
+
function parseControllerActions(content, controllerName, sourceFile, views, routesMap) {
|
|
261
|
+
const pages = [];
|
|
262
|
+
// Extract public actions (methods before private/protected)
|
|
263
|
+
const publicSection = content.split(/\n\s*(private|protected)\b/)[0];
|
|
264
|
+
// Match action definitions
|
|
265
|
+
const actionPattern = /def\s+(\w+)/g;
|
|
266
|
+
let match;
|
|
267
|
+
while ((match = actionPattern.exec(publicSection)) !== null) {
|
|
268
|
+
const action = match[1];
|
|
269
|
+
// Skip common non-action methods
|
|
270
|
+
if (['initialize', 'new', 'create', 'update', 'destroy', 'index', 'show', 'edit'].includes(action) ||
|
|
271
|
+
action.startsWith('set_') ||
|
|
272
|
+
action.startsWith('_')) {
|
|
273
|
+
// These ARE valid actions, don't skip
|
|
274
|
+
}
|
|
275
|
+
// Find the action body
|
|
276
|
+
const actionStart = match.index;
|
|
277
|
+
const actionBody = extractActionBody(publicSection, actionStart);
|
|
278
|
+
// Extract API calls from action
|
|
279
|
+
const apis = extractApiCalls(actionBody, sourceFile);
|
|
280
|
+
const services = extractServiceCalls(actionBody);
|
|
281
|
+
const grpcCalls = extractGrpcCalls(actionBody);
|
|
282
|
+
const modelAccess = extractModelAccess(actionBody);
|
|
283
|
+
// Find matching view
|
|
284
|
+
const view = views.find((v) => v.controller === controllerName && v.action === action);
|
|
285
|
+
// Get route info
|
|
286
|
+
const routeKey = `${controllerName}#${action}`;
|
|
287
|
+
const routeInfo = routesMap.get(routeKey);
|
|
288
|
+
pages.push({
|
|
289
|
+
route: routeInfo?.path || `/${controllerName}/${action}`,
|
|
290
|
+
method: routeInfo?.method || 'GET',
|
|
291
|
+
controller: controllerName,
|
|
292
|
+
action,
|
|
293
|
+
view,
|
|
294
|
+
apis,
|
|
295
|
+
services,
|
|
296
|
+
grpcCalls,
|
|
297
|
+
modelAccess,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
return pages;
|
|
301
|
+
}
|
|
302
|
+
function extractActionBody(content, startIndex) {
|
|
303
|
+
// Simple extraction - find matching 'end'
|
|
304
|
+
let depth = 0;
|
|
305
|
+
let started = false;
|
|
306
|
+
let body = '';
|
|
307
|
+
for (let i = startIndex; i < content.length; i++) {
|
|
308
|
+
const line = content.slice(i, content.indexOf('\n', i) + 1 || content.length);
|
|
309
|
+
if (line.match(/^\s*(def|class|module|if|unless|case|while|until|for|begin|do)\b/)) {
|
|
310
|
+
depth++;
|
|
311
|
+
started = true;
|
|
312
|
+
}
|
|
313
|
+
if (line.match(/^\s*end\b/)) {
|
|
314
|
+
depth--;
|
|
315
|
+
if (started && depth === 0) {
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
body += line;
|
|
320
|
+
i = content.indexOf('\n', i);
|
|
321
|
+
if (i === -1)
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
return body;
|
|
325
|
+
}
|
|
326
|
+
function extractApiCalls(content, sourceFile) {
|
|
327
|
+
const apis = [];
|
|
328
|
+
// HTTP client calls
|
|
329
|
+
const httpPatterns = [
|
|
330
|
+
/HTTPClient\.(get|post|put|patch|delete)\s*\(\s*['"]([^'"]+)['"]/gi,
|
|
331
|
+
/RestClient\.(get|post|put|patch|delete)\s*\(\s*['"]([^'"]+)['"]/gi,
|
|
332
|
+
/Faraday\.(get|post|put|patch|delete)\s*\(\s*['"]([^'"]+)['"]/gi,
|
|
333
|
+
/Net::HTTP\.(get|post)\s*\(/gi,
|
|
334
|
+
];
|
|
335
|
+
for (const pattern of httpPatterns) {
|
|
336
|
+
let match;
|
|
337
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
338
|
+
apis.push({
|
|
339
|
+
type: 'http',
|
|
340
|
+
name: match[2] || 'HTTP call',
|
|
341
|
+
method: match[1]?.toUpperCase(),
|
|
342
|
+
source: sourceFile,
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return apis;
|
|
347
|
+
}
|
|
348
|
+
function extractServiceCalls(content) {
|
|
349
|
+
const services = [];
|
|
350
|
+
// Match Service.call or Service.call! or Service.new.call
|
|
351
|
+
const pattern = /(\w+(?:::\w+)*Service)\.(?:call!?|new)/g;
|
|
352
|
+
let match;
|
|
353
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
354
|
+
services.push(match[1]);
|
|
355
|
+
}
|
|
356
|
+
return [...new Set(services)];
|
|
357
|
+
}
|
|
358
|
+
function extractGrpcCalls(content) {
|
|
359
|
+
const grpcCalls = [];
|
|
360
|
+
// Match gRPC calls: Grpc::XxxService or XxxGrpcService
|
|
361
|
+
const patterns = [
|
|
362
|
+
/(\w+(?:::\w+)*Grpc(?:::\w+)?)\./g,
|
|
363
|
+
/Grpc::(\w+(?:::\w+)*)/g,
|
|
364
|
+
/(\w+GrpcService)\./g,
|
|
365
|
+
];
|
|
366
|
+
for (const pattern of patterns) {
|
|
367
|
+
let match;
|
|
368
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
369
|
+
grpcCalls.push(match[1]);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return [...new Set(grpcCalls)];
|
|
373
|
+
}
|
|
374
|
+
function extractModelAccess(content) {
|
|
375
|
+
const models = [];
|
|
376
|
+
// Match model access: ModelName.find, ModelName.where, etc.
|
|
377
|
+
const pattern = /([A-Z][a-zA-Z0-9]+)\.(?:find|where|find_by|first|last|all|create|update|destroy|new)/g;
|
|
378
|
+
let match;
|
|
379
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
380
|
+
// Skip common non-model classes
|
|
381
|
+
if (!['File', 'Dir', 'Time', 'Date', 'DateTime', 'JSON', 'YAML', 'CSV', 'Logger'].includes(match[1])) {
|
|
382
|
+
models.push(match[1]);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return [...new Set(models)];
|
|
386
|
+
}
|
|
387
|
+
//# sourceMappingURL=rails-view-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rails-view-analyzer.js","sourceRoot":"","sources":["../../../src/analyzers/rails/rails-view-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ruby Parser using web-tree-sitter
|
|
3
|
+
* web-tree-sitterを使用したRubyパーサー
|
|
4
|
+
*/
|
|
5
|
+
import { Parser, Node, Tree } from 'web-tree-sitter';
|
|
6
|
+
export type SyntaxNode = Node;
|
|
7
|
+
export { Tree };
|
|
8
|
+
/**
|
|
9
|
+
* Initialize the Ruby parser
|
|
10
|
+
*/
|
|
11
|
+
export declare function initRubyParser(): Promise<Parser>;
|
|
12
|
+
/**
|
|
13
|
+
* Parse Ruby code
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseRuby(code: string): Promise<Tree>;
|
|
16
|
+
/**
|
|
17
|
+
* Parse Ruby file
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseRubyFile(filePath: string): Promise<Tree>;
|
|
20
|
+
/**
|
|
21
|
+
* Find all nodes of a specific type
|
|
22
|
+
*/
|
|
23
|
+
export declare function findNodes(node: SyntaxNode, type: string): SyntaxNode[];
|
|
24
|
+
/**
|
|
25
|
+
* Find all nodes matching multiple types
|
|
26
|
+
*/
|
|
27
|
+
export declare function findNodesByTypes(node: SyntaxNode, types: string[]): SyntaxNode[];
|
|
28
|
+
/**
|
|
29
|
+
* Get the text of a named child
|
|
30
|
+
*/
|
|
31
|
+
export declare function getChildText(node: SyntaxNode, fieldName: string): string | null;
|
|
32
|
+
/**
|
|
33
|
+
* Get the first child of a specific type
|
|
34
|
+
*/
|
|
35
|
+
export declare function getChildByType(node: SyntaxNode, type: string): SyntaxNode | null;
|
|
36
|
+
/**
|
|
37
|
+
* Get all children of a specific type
|
|
38
|
+
*/
|
|
39
|
+
export declare function getChildrenByType(node: SyntaxNode, type: string): SyntaxNode[];
|
|
40
|
+
/**
|
|
41
|
+
* Extract method call arguments
|
|
42
|
+
*/
|
|
43
|
+
export declare function getCallArguments(callNode: SyntaxNode): SyntaxNode[];
|
|
44
|
+
/**
|
|
45
|
+
* Check if node is inside a specific block type
|
|
46
|
+
*/
|
|
47
|
+
export declare function isInsideBlock(node: SyntaxNode, blockType: string): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Get the class name from a class node
|
|
50
|
+
*/
|
|
51
|
+
export declare function getClassName(classNode: SyntaxNode): string | null;
|
|
52
|
+
/**
|
|
53
|
+
* Get the superclass from a class node
|
|
54
|
+
*/
|
|
55
|
+
export declare function getSuperclass(classNode: SyntaxNode): string | null;
|
|
56
|
+
/**
|
|
57
|
+
* Get method name from a method node
|
|
58
|
+
*/
|
|
59
|
+
export declare function getMethodName(methodNode: SyntaxNode): string | null;
|
|
60
|
+
/**
|
|
61
|
+
* Get method parameters
|
|
62
|
+
*/
|
|
63
|
+
export declare function getMethodParameters(methodNode: SyntaxNode): string[];
|
|
64
|
+
//# sourceMappingURL=ruby-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ruby-parser.d.ts","sourceRoot":"","sources":["../../../src/analyzers/rails/ruby-parser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAY,MAAM,iBAAiB,CAAC;AAM/D,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC;AAC9B,OAAO,EAAE,IAAI,EAAE,CAAC;AAShB;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAqCtD;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO3D;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGnE;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,CAetE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE,CAehF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG/E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAQhF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,CAS9E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,UAAU,GAAG,UAAU,EAAE,CAYnE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAS1E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAGjE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CASlE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAGnE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,EAAE,CAwBpE"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ruby Parser using web-tree-sitter
|
|
3
|
+
* web-tree-sitterを使用したRubyパーサー
|
|
4
|
+
*/
|
|
5
|
+
import { Parser, Tree, Language } from 'web-tree-sitter';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
9
|
+
export { Tree };
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
let parserInitialized = false;
|
|
13
|
+
let rubyLanguage = null;
|
|
14
|
+
let parser = null;
|
|
15
|
+
/**
|
|
16
|
+
* Initialize the Ruby parser
|
|
17
|
+
*/
|
|
18
|
+
export async function initRubyParser() {
|
|
19
|
+
if (parser && rubyLanguage) {
|
|
20
|
+
return parser;
|
|
21
|
+
}
|
|
22
|
+
if (!parserInitialized) {
|
|
23
|
+
await Parser.init();
|
|
24
|
+
parserInitialized = true;
|
|
25
|
+
}
|
|
26
|
+
parser = new Parser();
|
|
27
|
+
// Find WASM file - try multiple locations
|
|
28
|
+
const possiblePaths = [
|
|
29
|
+
// When running from source
|
|
30
|
+
path.join(process.cwd(), 'node_modules/tree-sitter-wasms/out/tree-sitter-ruby.wasm'),
|
|
31
|
+
// When installed as dependency
|
|
32
|
+
path.join(__dirname, '../../../node_modules/tree-sitter-wasms/out/tree-sitter-ruby.wasm'),
|
|
33
|
+
path.join(__dirname, '../../../../tree-sitter-wasms/out/tree-sitter-ruby.wasm'),
|
|
34
|
+
];
|
|
35
|
+
let wasmPath = null;
|
|
36
|
+
for (const p of possiblePaths) {
|
|
37
|
+
if (fs.existsSync(p)) {
|
|
38
|
+
wasmPath = p;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (!wasmPath) {
|
|
43
|
+
throw new Error('tree-sitter-ruby.wasm not found. Please install tree-sitter-wasms package.');
|
|
44
|
+
}
|
|
45
|
+
rubyLanguage = await Language.load(wasmPath);
|
|
46
|
+
parser.setLanguage(rubyLanguage);
|
|
47
|
+
return parser;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Parse Ruby code
|
|
51
|
+
*/
|
|
52
|
+
export async function parseRuby(code) {
|
|
53
|
+
const p = await initRubyParser();
|
|
54
|
+
const tree = p.parse(code);
|
|
55
|
+
if (!tree) {
|
|
56
|
+
throw new Error('Failed to parse Ruby code');
|
|
57
|
+
}
|
|
58
|
+
return tree;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Parse Ruby file
|
|
62
|
+
*/
|
|
63
|
+
export async function parseRubyFile(filePath) {
|
|
64
|
+
const code = fs.readFileSync(filePath, 'utf-8');
|
|
65
|
+
return parseRuby(code);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Find all nodes of a specific type
|
|
69
|
+
*/
|
|
70
|
+
export function findNodes(node, type) {
|
|
71
|
+
const results = [];
|
|
72
|
+
if (node.type === type) {
|
|
73
|
+
results.push(node);
|
|
74
|
+
}
|
|
75
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
76
|
+
const child = node.child(i);
|
|
77
|
+
if (child) {
|
|
78
|
+
results.push(...findNodes(child, type));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return results;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Find all nodes matching multiple types
|
|
85
|
+
*/
|
|
86
|
+
export function findNodesByTypes(node, types) {
|
|
87
|
+
const results = [];
|
|
88
|
+
if (types.includes(node.type)) {
|
|
89
|
+
results.push(node);
|
|
90
|
+
}
|
|
91
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
92
|
+
const child = node.child(i);
|
|
93
|
+
if (child) {
|
|
94
|
+
results.push(...findNodesByTypes(child, types));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return results;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get the text of a named child
|
|
101
|
+
*/
|
|
102
|
+
export function getChildText(node, fieldName) {
|
|
103
|
+
const child = node.childForFieldName(fieldName);
|
|
104
|
+
return child ? child.text : null;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get the first child of a specific type
|
|
108
|
+
*/
|
|
109
|
+
export function getChildByType(node, type) {
|
|
110
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
111
|
+
const child = node.child(i);
|
|
112
|
+
if (child && child.type === type) {
|
|
113
|
+
return child;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get all children of a specific type
|
|
120
|
+
*/
|
|
121
|
+
export function getChildrenByType(node, type) {
|
|
122
|
+
const results = [];
|
|
123
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
124
|
+
const child = node.child(i);
|
|
125
|
+
if (child && child.type === type) {
|
|
126
|
+
results.push(child);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return results;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Extract method call arguments
|
|
133
|
+
*/
|
|
134
|
+
export function getCallArguments(callNode) {
|
|
135
|
+
const args = callNode.childForFieldName('arguments');
|
|
136
|
+
if (!args)
|
|
137
|
+
return [];
|
|
138
|
+
const results = [];
|
|
139
|
+
for (let i = 0; i < args.childCount; i++) {
|
|
140
|
+
const child = args.child(i);
|
|
141
|
+
if (child && child.type !== '(' && child.type !== ')' && child.type !== ',') {
|
|
142
|
+
results.push(child);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return results;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Check if node is inside a specific block type
|
|
149
|
+
*/
|
|
150
|
+
export function isInsideBlock(node, blockType) {
|
|
151
|
+
let current = node.parent;
|
|
152
|
+
while (current) {
|
|
153
|
+
if (current.type === blockType) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
current = current.parent;
|
|
157
|
+
}
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get the class name from a class node
|
|
162
|
+
*/
|
|
163
|
+
export function getClassName(classNode) {
|
|
164
|
+
const nameNode = classNode.childForFieldName('name');
|
|
165
|
+
return nameNode ? nameNode.text : null;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Get the superclass from a class node
|
|
169
|
+
*/
|
|
170
|
+
export function getSuperclass(classNode) {
|
|
171
|
+
const superclassNode = classNode.childForFieldName('superclass');
|
|
172
|
+
if (!superclassNode)
|
|
173
|
+
return null;
|
|
174
|
+
// superclass node contains "< ClassName", extract just the class name
|
|
175
|
+
const constantNode = getChildByType(superclassNode, 'constant') ||
|
|
176
|
+
getChildByType(superclassNode, 'scope_resolution');
|
|
177
|
+
return constantNode ? constantNode.text : null;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Get method name from a method node
|
|
181
|
+
*/
|
|
182
|
+
export function getMethodName(methodNode) {
|
|
183
|
+
const nameNode = methodNode.childForFieldName('name');
|
|
184
|
+
return nameNode ? nameNode.text : null;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Get method parameters
|
|
188
|
+
*/
|
|
189
|
+
export function getMethodParameters(methodNode) {
|
|
190
|
+
const paramsNode = methodNode.childForFieldName('parameters');
|
|
191
|
+
if (!paramsNode)
|
|
192
|
+
return [];
|
|
193
|
+
const params = [];
|
|
194
|
+
for (let i = 0; i < paramsNode.childCount; i++) {
|
|
195
|
+
const child = paramsNode.child(i);
|
|
196
|
+
if (child &&
|
|
197
|
+
(child.type === 'identifier' ||
|
|
198
|
+
child.type === 'keyword_parameter' ||
|
|
199
|
+
child.type === 'optional_parameter' ||
|
|
200
|
+
child.type === 'splat_parameter')) {
|
|
201
|
+
// Extract the parameter name
|
|
202
|
+
const nameNode = child.childForFieldName('name') || child;
|
|
203
|
+
if (nameNode.type === 'identifier') {
|
|
204
|
+
params.push(nameNode.text);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
params.push(child.text);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return params;
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=ruby-parser.js.map
|