@wtdlee/repomap 0.3.0 → 0.3.1
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/dist/analyzers/index.d.ts +69 -5
- package/dist/analyzers/index.js +1 -5
- package/dist/chunk-3PWXDB7B.js +153 -0
- package/dist/{generators/page-map-generator.js → chunk-3YFXZAP7.js} +322 -358
- package/dist/chunk-6F4PWJZI.js +1 -0
- package/dist/{generators/rails-map-generator.js → chunk-E4WRODSI.js} +86 -94
- package/dist/chunk-GNBMJMET.js +2519 -0
- package/dist/{server/doc-server.js → chunk-M6YNU536.js} +702 -303
- package/dist/chunk-OWM6WNLE.js +2610 -0
- package/dist/chunk-SSU6QFTX.js +1058 -0
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +348 -452
- package/dist/dataflow-analyzer-BfAiqVUp.d.ts +180 -0
- package/dist/env-detector-EEMVUEIA.js +1 -0
- package/dist/generators/index.d.ts +431 -3
- package/dist/generators/index.js +2 -3
- package/dist/index.d.ts +53 -10
- package/dist/index.js +8 -11
- package/dist/page-map-generator-6MJGPBVA.js +1 -0
- package/dist/rails-UWSDRS33.js +1 -0
- package/dist/rails-map-generator-D2URLMVJ.js +2 -0
- package/dist/server/index.d.ts +33 -1
- package/dist/server/index.js +7 -1
- package/dist/types.d.ts +39 -37
- package/dist/types.js +1 -5
- package/package.json +4 -2
- package/dist/analyzers/base-analyzer.d.ts +0 -45
- package/dist/analyzers/base-analyzer.js +0 -47
- package/dist/analyzers/dataflow-analyzer.d.ts +0 -29
- package/dist/analyzers/dataflow-analyzer.js +0 -425
- package/dist/analyzers/graphql-analyzer.d.ts +0 -22
- package/dist/analyzers/graphql-analyzer.js +0 -386
- package/dist/analyzers/pages-analyzer.d.ts +0 -84
- package/dist/analyzers/pages-analyzer.js +0 -1695
- package/dist/analyzers/rails/index.d.ts +0 -46
- package/dist/analyzers/rails/index.js +0 -145
- package/dist/analyzers/rails/rails-controller-analyzer.d.ts +0 -82
- package/dist/analyzers/rails/rails-controller-analyzer.js +0 -478
- package/dist/analyzers/rails/rails-grpc-analyzer.d.ts +0 -44
- package/dist/analyzers/rails/rails-grpc-analyzer.js +0 -262
- package/dist/analyzers/rails/rails-model-analyzer.d.ts +0 -88
- package/dist/analyzers/rails/rails-model-analyzer.js +0 -493
- package/dist/analyzers/rails/rails-react-analyzer.d.ts +0 -41
- package/dist/analyzers/rails/rails-react-analyzer.js +0 -529
- package/dist/analyzers/rails/rails-routes-analyzer.d.ts +0 -62
- package/dist/analyzers/rails/rails-routes-analyzer.js +0 -540
- package/dist/analyzers/rails/rails-view-analyzer.d.ts +0 -49
- package/dist/analyzers/rails/rails-view-analyzer.js +0 -386
- package/dist/analyzers/rails/ruby-parser.d.ts +0 -63
- package/dist/analyzers/rails/ruby-parser.js +0 -212
- package/dist/analyzers/rest-api-analyzer.d.ts +0 -65
- package/dist/analyzers/rest-api-analyzer.js +0 -479
- package/dist/core/cache.d.ts +0 -47
- package/dist/core/cache.js +0 -151
- package/dist/core/engine.d.ts +0 -46
- package/dist/core/engine.js +0 -319
- package/dist/core/index.d.ts +0 -2
- package/dist/core/index.js +0 -2
- package/dist/generators/markdown-generator.d.ts +0 -25
- package/dist/generators/markdown-generator.js +0 -782
- package/dist/generators/mermaid-generator.d.ts +0 -35
- package/dist/generators/mermaid-generator.js +0 -364
- package/dist/generators/page-map-generator.d.ts +0 -22
- package/dist/generators/rails-map-generator.d.ts +0 -21
- package/dist/server/doc-server.d.ts +0 -30
- package/dist/utils/env-detector.d.ts +0 -31
- package/dist/utils/env-detector.js +0 -188
- package/dist/utils/parallel.d.ts +0 -23
- package/dist/utils/parallel.js +0 -70
- package/dist/utils/port.d.ts +0 -15
- package/dist/utils/port.js +0 -41
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rails gRPC Service Analyzer using tree-sitter
|
|
3
|
-
* tree-sitterを使用してgRPCサービスを解析する
|
|
4
|
-
*/
|
|
5
|
-
import * as fs from 'fs';
|
|
6
|
-
import * as path from 'path';
|
|
7
|
-
import { glob } from 'glob';
|
|
8
|
-
import { parseRubyFile, findNodes, getClassName, getSuperclass, getMethodName, getMethodParameters, } from './ruby-parser.js';
|
|
9
|
-
export class RailsGrpcAnalyzer {
|
|
10
|
-
rootPath;
|
|
11
|
-
grpcDir;
|
|
12
|
-
services = [];
|
|
13
|
-
errors = [];
|
|
14
|
-
constructor(rootPath) {
|
|
15
|
-
this.rootPath = rootPath;
|
|
16
|
-
this.grpcDir = path.join(rootPath, 'app', 'grpc_services');
|
|
17
|
-
}
|
|
18
|
-
async analyze() {
|
|
19
|
-
if (!fs.existsSync(this.grpcDir)) {
|
|
20
|
-
return {
|
|
21
|
-
services: [],
|
|
22
|
-
totalRpcs: 0,
|
|
23
|
-
namespaces: [],
|
|
24
|
-
errors: [`gRPC services directory not found at ${this.grpcDir}`],
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
const serviceFiles = await glob('**/*_grpc_service.rb', {
|
|
28
|
-
cwd: this.grpcDir,
|
|
29
|
-
});
|
|
30
|
-
for (const file of serviceFiles) {
|
|
31
|
-
const fullPath = path.join(this.grpcDir, file);
|
|
32
|
-
try {
|
|
33
|
-
const service = await this.parseServiceFile(fullPath, file);
|
|
34
|
-
if (service) {
|
|
35
|
-
this.services.push(service);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
catch (error) {
|
|
39
|
-
this.errors.push(`Error parsing ${file}: ${error}`);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
const namespaces = [
|
|
43
|
-
...new Set(this.services.filter((s) => s.namespace).map((s) => s.namespace)),
|
|
44
|
-
];
|
|
45
|
-
const totalRpcs = this.services.reduce((sum, s) => sum + s.rpcs.length, 0);
|
|
46
|
-
return {
|
|
47
|
-
services: this.services,
|
|
48
|
-
totalRpcs,
|
|
49
|
-
namespaces,
|
|
50
|
-
errors: this.errors,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
async parseServiceFile(filePath, relativePath) {
|
|
54
|
-
const tree = await parseRubyFile(filePath);
|
|
55
|
-
const rootNode = tree.rootNode;
|
|
56
|
-
// Extract namespace from path
|
|
57
|
-
const pathParts = relativePath.replace(/_grpc_service\.rb$/, '').split('/');
|
|
58
|
-
const namespace = pathParts.length > 1 ? pathParts.slice(0, -1).join('/') : undefined;
|
|
59
|
-
const serviceName = pathParts[pathParts.length - 1];
|
|
60
|
-
// Find class definition
|
|
61
|
-
const classNodes = findNodes(rootNode, 'class');
|
|
62
|
-
if (classNodes.length === 0)
|
|
63
|
-
return null;
|
|
64
|
-
const classNode = classNodes[0];
|
|
65
|
-
const className = getClassName(classNode);
|
|
66
|
-
const parentClass = getSuperclass(classNode);
|
|
67
|
-
if (!className)
|
|
68
|
-
return null;
|
|
69
|
-
const service = {
|
|
70
|
-
name: serviceName,
|
|
71
|
-
filePath: relativePath,
|
|
72
|
-
className,
|
|
73
|
-
parentClass: parentClass || 'Unknown',
|
|
74
|
-
namespace,
|
|
75
|
-
rpcs: [],
|
|
76
|
-
policies: [],
|
|
77
|
-
serializers: [],
|
|
78
|
-
concerns: [],
|
|
79
|
-
line: classNode.startPosition.row + 1,
|
|
80
|
-
};
|
|
81
|
-
// Extract proto service from parent class
|
|
82
|
-
if (parentClass) {
|
|
83
|
-
// e.g., Visit::ConversationPb::ConversationService::Service
|
|
84
|
-
const protoMatch = parentClass.match(/(\w+)::Service$/);
|
|
85
|
-
if (protoMatch) {
|
|
86
|
-
service.protoService = parentClass.replace('::Service', '');
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
// Find include statements (concerns)
|
|
90
|
-
const calls = findNodes(classNode, 'call');
|
|
91
|
-
for (const call of calls) {
|
|
92
|
-
const methodNode = call.childForFieldName('method');
|
|
93
|
-
if (methodNode?.text === 'include') {
|
|
94
|
-
const args = this.getCallArguments(call);
|
|
95
|
-
for (const arg of args) {
|
|
96
|
-
if (arg.type === 'constant' || arg.type === 'scope_resolution') {
|
|
97
|
-
service.concerns.push(arg.text);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
// Find method definitions (RPC methods)
|
|
103
|
-
const _methods = findNodes(classNode, 'method');
|
|
104
|
-
let currentVisibility = 'public';
|
|
105
|
-
const bodyStatement = classNode.childForFieldName('body');
|
|
106
|
-
if (bodyStatement) {
|
|
107
|
-
for (let i = 0; i < bodyStatement.childCount; i++) {
|
|
108
|
-
const child = bodyStatement.child(i);
|
|
109
|
-
if (!child)
|
|
110
|
-
continue;
|
|
111
|
-
if (child.type === 'identifier') {
|
|
112
|
-
const text = child.text;
|
|
113
|
-
if (text === 'private')
|
|
114
|
-
currentVisibility = 'private';
|
|
115
|
-
else if (text === 'protected')
|
|
116
|
-
currentVisibility = 'protected';
|
|
117
|
-
else if (text === 'public')
|
|
118
|
-
currentVisibility = 'public';
|
|
119
|
-
}
|
|
120
|
-
else if (child.type === 'method' && currentVisibility === 'public') {
|
|
121
|
-
const rpc = this.parseRpcMethod(child);
|
|
122
|
-
if (rpc) {
|
|
123
|
-
// Extract policies and serializers from method body
|
|
124
|
-
const methodCalls = findNodes(child, 'call');
|
|
125
|
-
for (const mc of methodCalls) {
|
|
126
|
-
const methodName = mc.childForFieldName('method')?.text;
|
|
127
|
-
const receiver = mc.childForFieldName('receiver')?.text;
|
|
128
|
-
// Policy patterns
|
|
129
|
-
if (methodName === 'authorize!' || methodName === 'new') {
|
|
130
|
-
if (receiver?.includes('Policy')) {
|
|
131
|
-
if (!service.policies.includes(receiver)) {
|
|
132
|
-
service.policies.push(receiver);
|
|
133
|
-
}
|
|
134
|
-
rpc.policyMethod = 'authorize!';
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
// Serializer patterns
|
|
138
|
-
if (receiver?.includes('Serializer') && methodName === 'new') {
|
|
139
|
-
if (!service.serializers.includes(receiver)) {
|
|
140
|
-
service.serializers.push(receiver);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
service.rpcs.push(rpc);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
return service;
|
|
150
|
-
}
|
|
151
|
-
parseRpcMethod(methodNode) {
|
|
152
|
-
const name = getMethodName(methodNode);
|
|
153
|
-
if (!name)
|
|
154
|
-
return null;
|
|
155
|
-
// Skip common non-RPC methods
|
|
156
|
-
const skipMethods = ['initialize', 'to_s', 'inspect', 'call', 'perform', 'execute'];
|
|
157
|
-
if (skipMethods.includes(name))
|
|
158
|
-
return null;
|
|
159
|
-
const _params = getMethodParameters(methodNode);
|
|
160
|
-
const methodBody = methodNode.text;
|
|
161
|
-
const rpc = {
|
|
162
|
-
name,
|
|
163
|
-
line: methodNode.startPosition.row + 1,
|
|
164
|
-
streaming: 'none',
|
|
165
|
-
modelsUsed: [],
|
|
166
|
-
servicesUsed: [],
|
|
167
|
-
};
|
|
168
|
-
// Try to extract request/response types from comments or code
|
|
169
|
-
// @param [Visit::ConversationPb::GetConversationRequest] req
|
|
170
|
-
const requestMatch = methodBody.match(/@param\s+\[([^\]]+)\]\s+req/);
|
|
171
|
-
if (requestMatch) {
|
|
172
|
-
rpc.requestType = requestMatch[1];
|
|
173
|
-
}
|
|
174
|
-
// @return [Visit::ConversationPb::Conversation]
|
|
175
|
-
const responseMatch = methodBody.match(/@return\s+\[([^\]]+)\]/);
|
|
176
|
-
if (responseMatch) {
|
|
177
|
-
rpc.responseType = responseMatch[1];
|
|
178
|
-
}
|
|
179
|
-
// Extract models used (ActiveRecord patterns)
|
|
180
|
-
const modelMatches = methodBody.matchAll(/\b([A-Z][a-zA-Z]+)\.(find|find_by|where|all|first|last|create|joins|includes)\b/g);
|
|
181
|
-
for (const match of modelMatches) {
|
|
182
|
-
const modelName = match[1];
|
|
183
|
-
if (!['Rails', 'ActiveRecord', 'GRPC', 'Visit', 'Google'].includes(modelName) &&
|
|
184
|
-
!rpc.modelsUsed.includes(modelName)) {
|
|
185
|
-
rpc.modelsUsed.push(modelName);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
// Extract services used
|
|
189
|
-
const serviceMatches = methodBody.matchAll(/\b(\w+Service)\.(call|new|perform)\b/g);
|
|
190
|
-
for (const match of serviceMatches) {
|
|
191
|
-
const serviceName = match[1];
|
|
192
|
-
if (!rpc.servicesUsed.includes(serviceName)) {
|
|
193
|
-
rpc.servicesUsed.push(serviceName);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return rpc;
|
|
197
|
-
}
|
|
198
|
-
getCallArguments(call) {
|
|
199
|
-
const args = call.childForFieldName('arguments');
|
|
200
|
-
if (!args) {
|
|
201
|
-
const results = [];
|
|
202
|
-
for (let i = 0; i < call.childCount; i++) {
|
|
203
|
-
const child = call.child(i);
|
|
204
|
-
if (child && !['identifier', '(', ')', ',', 'call'].includes(child.type)) {
|
|
205
|
-
if (child !== call.childForFieldName('method') &&
|
|
206
|
-
child !== call.childForFieldName('receiver')) {
|
|
207
|
-
results.push(child);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
return results;
|
|
212
|
-
}
|
|
213
|
-
const results = [];
|
|
214
|
-
for (let i = 0; i < args.childCount; i++) {
|
|
215
|
-
const child = args.child(i);
|
|
216
|
-
if (child && child.type !== '(' && child.type !== ')' && child.type !== ',') {
|
|
217
|
-
results.push(child);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
return results;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
// Standalone execution for testing
|
|
224
|
-
async function main() {
|
|
225
|
-
const targetPath = process.argv[2] || process.cwd();
|
|
226
|
-
console.log(`Analyzing gRPC services in: ${targetPath}`);
|
|
227
|
-
const analyzer = new RailsGrpcAnalyzer(targetPath);
|
|
228
|
-
const result = await analyzer.analyze();
|
|
229
|
-
console.log('\n=== Rails gRPC Services Analysis ===\n');
|
|
230
|
-
console.log(`Total services: ${result.services.length}`);
|
|
231
|
-
console.log(`Total RPCs: ${result.totalRpcs}`);
|
|
232
|
-
console.log(`Namespaces: ${result.namespaces.join(', ') || '(none)'}`);
|
|
233
|
-
if (result.errors.length > 0) {
|
|
234
|
-
console.log(`\n--- Errors (${result.errors.length}) ---`);
|
|
235
|
-
for (const error of result.errors.slice(0, 5)) {
|
|
236
|
-
console.log(` ❌ ${error}`);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
console.log('\n--- Sample Services (first 15) ---');
|
|
240
|
-
for (const service of result.services.slice(0, 15)) {
|
|
241
|
-
console.log(`\n 📡 ${service.className} (${service.filePath})`);
|
|
242
|
-
console.log(` Proto: ${service.protoService || 'unknown'}`);
|
|
243
|
-
console.log(` RPCs (${service.rpcs.length}): ${service.rpcs.map((r) => r.name).join(', ')}`);
|
|
244
|
-
if (service.policies.length > 0) {
|
|
245
|
-
console.log(` Policies: ${service.policies.join(', ')}`);
|
|
246
|
-
}
|
|
247
|
-
if (service.serializers.length > 0) {
|
|
248
|
-
console.log(` Serializers: ${service.serializers.join(', ')}`);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
// RPC summary
|
|
252
|
-
const allRpcs = result.services.flatMap((s) => s.rpcs);
|
|
253
|
-
const rpcsWithModels = allRpcs.filter((r) => r.modelsUsed.length > 0);
|
|
254
|
-
console.log('\n--- RPC Summary ---');
|
|
255
|
-
console.log(` Total RPCs: ${allRpcs.length}`);
|
|
256
|
-
console.log(` RPCs using models: ${rpcsWithModels.length}`);
|
|
257
|
-
}
|
|
258
|
-
// Run if executed directly
|
|
259
|
-
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
260
|
-
if (isMainModule) {
|
|
261
|
-
main().catch(console.error);
|
|
262
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rails Model Analyzer using tree-sitter
|
|
3
|
-
* tree-sitterを使用してモデルファイルを解析する
|
|
4
|
-
*/
|
|
5
|
-
export interface ModelInfo {
|
|
6
|
-
name: string;
|
|
7
|
-
filePath: string;
|
|
8
|
-
className: string;
|
|
9
|
-
parentClass: string;
|
|
10
|
-
tableName?: string;
|
|
11
|
-
associations: AssociationInfo[];
|
|
12
|
-
validations: ValidationInfo[];
|
|
13
|
-
callbacks: CallbackInfo[];
|
|
14
|
-
scopes: ScopeInfo[];
|
|
15
|
-
concerns: string[];
|
|
16
|
-
enums: EnumInfo[];
|
|
17
|
-
attributes: AttributeInfo[];
|
|
18
|
-
classMethodsCount: number;
|
|
19
|
-
instanceMethodsCount: number;
|
|
20
|
-
line: number;
|
|
21
|
-
}
|
|
22
|
-
export interface AssociationInfo {
|
|
23
|
-
type: 'belongs_to' | 'has_one' | 'has_many' | 'has_and_belongs_to_many';
|
|
24
|
-
name: string;
|
|
25
|
-
className?: string;
|
|
26
|
-
foreignKey?: string;
|
|
27
|
-
through?: string;
|
|
28
|
-
polymorphic?: boolean;
|
|
29
|
-
dependent?: string;
|
|
30
|
-
optional?: boolean;
|
|
31
|
-
line: number;
|
|
32
|
-
}
|
|
33
|
-
export interface ValidationInfo {
|
|
34
|
-
type: string;
|
|
35
|
-
attributes: string[];
|
|
36
|
-
options?: Record<string, string>;
|
|
37
|
-
line: number;
|
|
38
|
-
}
|
|
39
|
-
export interface CallbackInfo {
|
|
40
|
-
type: string;
|
|
41
|
-
method: string;
|
|
42
|
-
conditions?: string;
|
|
43
|
-
line: number;
|
|
44
|
-
}
|
|
45
|
-
export interface ScopeInfo {
|
|
46
|
-
name: string;
|
|
47
|
-
lambda: boolean;
|
|
48
|
-
line: number;
|
|
49
|
-
}
|
|
50
|
-
export interface EnumInfo {
|
|
51
|
-
name: string;
|
|
52
|
-
values: string[];
|
|
53
|
-
line: number;
|
|
54
|
-
}
|
|
55
|
-
export interface AttributeInfo {
|
|
56
|
-
name: string;
|
|
57
|
-
type?: string;
|
|
58
|
-
default?: string;
|
|
59
|
-
line: number;
|
|
60
|
-
}
|
|
61
|
-
export interface RailsModelsResult {
|
|
62
|
-
models: ModelInfo[];
|
|
63
|
-
totalAssociations: number;
|
|
64
|
-
totalValidations: number;
|
|
65
|
-
concerns: string[];
|
|
66
|
-
namespaces: string[];
|
|
67
|
-
errors: string[];
|
|
68
|
-
}
|
|
69
|
-
export declare class RailsModelAnalyzer {
|
|
70
|
-
private rootPath;
|
|
71
|
-
private modelsDir;
|
|
72
|
-
private models;
|
|
73
|
-
private errors;
|
|
74
|
-
constructor(rootPath: string);
|
|
75
|
-
analyze(): Promise<RailsModelsResult>;
|
|
76
|
-
private parseModelFile;
|
|
77
|
-
private isActiveRecordModel;
|
|
78
|
-
private parseTableName;
|
|
79
|
-
private parseAssociation;
|
|
80
|
-
private parseValidation;
|
|
81
|
-
private isCallback;
|
|
82
|
-
private parseCallback;
|
|
83
|
-
private parseScope;
|
|
84
|
-
private parseInclude;
|
|
85
|
-
private parseEnum;
|
|
86
|
-
private parseAttribute;
|
|
87
|
-
private getCallArguments;
|
|
88
|
-
}
|