@justmpm/ai-tool 3.24.0 → 4.0.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.
@@ -1,2189 +0,0 @@
1
- import {
2
- addSourceFile,
3
- detectFileAreas,
4
- expandMuiOverrideType,
5
- extractExports,
6
- extractFunctions,
7
- extractTypes,
8
- findSimilar,
9
- formatDepsApiText,
10
- formatDepsInfoText,
11
- formatDepsSearchText,
12
- formatOutput,
13
- getProjectIndexArtifact,
14
- getWorkspaceFiles,
15
- hint,
16
- isFileIgnored,
17
- logger,
18
- nextSteps,
19
- parseCommandOptions,
20
- readConfig,
21
- recoveryHint,
22
- simplifyType
23
- } from "./chunk-LKP6Z3JC.js";
24
-
25
- // src/commands/describe.ts
26
- var STOPWORDS = /* @__PURE__ */ new Set([
27
- // PT-BR
28
- "de",
29
- "da",
30
- "do",
31
- "das",
32
- "dos",
33
- "para",
34
- "com",
35
- "em",
36
- "uma",
37
- "um",
38
- "o",
39
- "a",
40
- "os",
41
- "as",
42
- "no",
43
- "na",
44
- "nos",
45
- "nas",
46
- "pelo",
47
- "pela",
48
- "que",
49
- "e",
50
- "ou",
51
- "se",
52
- "ao",
53
- "aos",
54
- // EN
55
- "the",
56
- "of",
57
- "in",
58
- "for",
59
- "with",
60
- "on",
61
- "at",
62
- "to",
63
- "and",
64
- "or",
65
- "is",
66
- "are",
67
- "was",
68
- "by",
69
- "an"
70
- ]);
71
- function removeStopwords(words) {
72
- const filtered = words.filter((w) => !STOPWORDS.has(w) && w.length > 1);
73
- return filtered.length > 0 ? filtered : words;
74
- }
75
- function calculatePartialScore(queryWords, searchableText) {
76
- if (queryWords.length === 0) return 1;
77
- const fullQuery = queryWords.join(" ");
78
- if (searchableText.includes(fullQuery)) return 0;
79
- let found = 0;
80
- for (const word of queryWords) {
81
- if (searchableText.includes(word)) {
82
- found++;
83
- }
84
- }
85
- return 1 - found / queryWords.length;
86
- }
87
- function buildAreaFileMap(allFiles, config) {
88
- const map = /* @__PURE__ */ new Map();
89
- for (const filePath of allFiles) {
90
- if (isFileIgnored(filePath, config)) continue;
91
- const fileAreas = detectFileAreas(filePath, config);
92
- for (const areaId of fileAreas) {
93
- if (!map.has(areaId)) map.set(areaId, []);
94
- map.get(areaId).push(filePath);
95
- }
96
- }
97
- return map;
98
- }
99
- var GENERIC_PARAMS = /* @__PURE__ */ new Set([
100
- "id",
101
- "data",
102
- "item",
103
- "row",
104
- "key",
105
- "val",
106
- "value",
107
- "obj",
108
- "obj",
109
- "arr",
110
- "list",
111
- "map",
112
- "set",
113
- "x",
114
- "y",
115
- "z",
116
- "a",
117
- "b",
118
- "c",
119
- "n",
120
- "i",
121
- "j",
122
- "k",
123
- "err",
124
- "e",
125
- "res",
126
- "req",
127
- "next"
128
- ]);
129
- function buildSearchableTextAndMatches(candidate, config, areaFileMap, index, queryWords) {
130
- const symbolMatches = [];
131
- const metadata = `${candidate.id} ${candidate.name} ${candidate.description}`;
132
- const keywords = config.areas[candidate.id]?.keywords?.join(" ") ?? "";
133
- const areaFiles = areaFileMap.get(candidate.id) ?? [];
134
- const fileNames = areaFiles.map((f) => {
135
- const name = f.split("/").pop() ?? "";
136
- return name.replace(/\.(tsx?|jsx?|mjs|cjs)$/, "");
137
- }).join(" ");
138
- const symbolNames = [];
139
- const symbolSignatures = [];
140
- const symbolParams = [];
141
- const symbolReturnTypes = [];
142
- for (const filePath of areaFiles) {
143
- const fileData = index.files[filePath];
144
- if (fileData?.symbols) {
145
- for (const symbol of fileData.symbols) {
146
- if (!symbol.isExported) continue;
147
- symbolNames.push(symbol.name);
148
- const MAX_SIGNATURE_CHARS = 200;
149
- const sig = symbol.signature.length > MAX_SIGNATURE_CHARS ? symbol.signature.slice(0, MAX_SIGNATURE_CHARS) + "..." : symbol.signature;
150
- symbolSignatures.push(sig);
151
- if (symbol.params && symbol.params.length > 0) {
152
- const filteredParams = symbol.params.filter((p) => !GENERIC_PARAMS.has(p));
153
- const paramsText = filteredParams.slice(0, 10).join(" ");
154
- if (paramsText) {
155
- symbolParams.push(paramsText);
156
- }
157
- }
158
- if (symbol.returnType) {
159
- symbolReturnTypes.push(symbol.returnType);
160
- }
161
- for (const word of queryWords) {
162
- if (symbol.signature.toLowerCase().includes(word)) {
163
- const cleanSig = symbol.signature.replace(/export\s+/g, "").replace(/\s+/g, " ");
164
- symbolMatches.push({
165
- name: symbol.name,
166
- file: filePath,
167
- signature: cleanSig,
168
- matchType: "signature",
169
- matchedText: word
170
- });
171
- } else if (symbol.params?.some((p) => p.toLowerCase().includes(word))) {
172
- const cleanSig = symbol.signature.replace(/export\s+/g, "").replace(/\s+/g, " ");
173
- symbolMatches.push({
174
- name: symbol.name,
175
- file: filePath,
176
- signature: cleanSig,
177
- matchType: "params",
178
- matchedText: word
179
- });
180
- } else if (symbol.returnType?.toLowerCase().includes(word)) {
181
- const cleanSig = symbol.signature.replace(/export\s+/g, "").replace(/\s+/g, " ");
182
- symbolMatches.push({
183
- name: symbol.name,
184
- file: filePath,
185
- signature: cleanSig,
186
- matchType: "returnType",
187
- matchedText: word
188
- });
189
- }
190
- }
191
- }
192
- }
193
- }
194
- const searchableText = [
195
- metadata,
196
- keywords,
197
- fileNames,
198
- symbolNames.join(" "),
199
- symbolSignatures.join(" "),
200
- symbolParams.join(" "),
201
- symbolReturnTypes.join(" ")
202
- ].join(" ").toLowerCase();
203
- return { searchableText, symbolMatches };
204
- }
205
- async function findAreaMatches(normalizedQuery, candidates, config, cwd) {
206
- const allFiles = await getWorkspaceFiles(cwd);
207
- const artifact = await getProjectIndexArtifact(cwd, { useCache: true });
208
- const index = artifact.index;
209
- const areaFileMap = buildAreaFileMap(allFiles, config);
210
- const queryWords = removeStopwords(normalizedQuery.split(/\s+/));
211
- const matches = [];
212
- for (const candidate of candidates) {
213
- const { searchableText, symbolMatches } = buildSearchableTextAndMatches(
214
- candidate,
215
- config,
216
- areaFileMap,
217
- index,
218
- queryWords
219
- );
220
- const score = calculatePartialScore(queryWords, searchableText);
221
- if (score < 0.6) {
222
- const areaFiles = areaFileMap.get(candidate.id) ?? [];
223
- const seen = /* @__PURE__ */ new Set();
224
- const uniqueSymbolMatches = symbolMatches.filter((m) => {
225
- const key = `${m.file}:${m.signature}`;
226
- if (seen.has(key)) return false;
227
- seen.add(key);
228
- return true;
229
- });
230
- matches.push({
231
- id: candidate.id,
232
- name: candidate.name,
233
- description: candidate.description || "Sem descricao",
234
- files: areaFiles,
235
- fileCount: areaFiles.length,
236
- score,
237
- symbolMatches: uniqueSymbolMatches.length > 0 ? uniqueSymbolMatches : void 0
238
- });
239
- }
240
- }
241
- return matches.sort((a, b) => a.score - b.score);
242
- }
243
- async function describe(query, options = {}) {
244
- const { cwd, format } = parseCommandOptions(options);
245
- const ctx = options.ctx || "cli";
246
- if (!query || query.trim().length === 0) {
247
- throw new Error("Query \xE9 obrigat\xF3ria. Exemplo: ai-tool describe 'autentica\xE7\xE3o'");
248
- }
249
- try {
250
- const config = readConfig(cwd);
251
- const hasAreas = Object.keys(config.areas).length > 0;
252
- if (!hasAreas) {
253
- let out = `\u26A0\uFE0F Nenhuma area configurada neste projeto.
254
-
255
- `;
256
- out += `O comando describe busca em areas configuradas.
257
- `;
258
- out += `Para configurar areas:
259
- `;
260
- out += ` 1. ${hint("areas_init", ctx)} - gerar arquivo de configuracao
261
- `;
262
- out += ` 2. Edite .analyze/areas.config.json com as areas do projeto
263
-
264
- `;
265
- out += `Enquanto isso, use:
266
- `;
267
- out += ` \u2192 ${hint("find", ctx)} - buscar simbolos no codigo
268
- `;
269
- out += ` \u2192 ${hint("map", ctx)} - ver estrutura do projeto
270
- `;
271
- return out;
272
- }
273
- const normalizedQuery = query.toLowerCase().trim();
274
- const candidates = Object.entries(config.areas).map(([id, area]) => ({
275
- id,
276
- name: area.name,
277
- description: area.description || ""
278
- }));
279
- const matches = await findAreaMatches(normalizedQuery, candidates, config, cwd);
280
- const suggestions = [];
281
- if (matches.length === 0) {
282
- const similarAreaIds = findSimilar(
283
- normalizedQuery,
284
- candidates.map((c) => c.id),
285
- { maxDistance: 2, limit: 3 }
286
- );
287
- const similarNames = findSimilar(
288
- normalizedQuery,
289
- candidates.map((c) => c.name),
290
- { maxDistance: 2, limit: 3 }
291
- );
292
- suggestions.push(
293
- ...similarAreaIds.map((id) => `\u2192 ${hint("describe", ctx, { "<termo>": id })}`),
294
- ...similarNames.map((name) => `\u2192 ${hint("describe", ctx, { "<termo>": `"${name}"` })}`)
295
- );
296
- }
297
- const result = {
298
- version: "1.0.0",
299
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
300
- query,
301
- areas: matches,
302
- suggestions: suggestions.length > 0 ? suggestions : void 0
303
- };
304
- return formatOutput(result, format, (r) => formatDescribeText(r, ctx));
305
- } catch (error) {
306
- const message = error instanceof Error ? error.message : String(error);
307
- throw new Error(`Erro ao executar describe: ${message}`);
308
- }
309
- }
310
- function formatDescribeText(result, ctx = "cli") {
311
- let out = "";
312
- if (result.areas.length === 0) {
313
- out += `\u274C Nenhuma area encontrada para: "${result.query}"
314
-
315
- `;
316
- if (result.suggestions && result.suggestions.length > 0) {
317
- out += `\u{1F4A1} Voce quis dizer?
318
- `;
319
- for (const suggestion of result.suggestions) {
320
- out += ` ${suggestion}
321
- `;
322
- }
323
- out += `
324
- `;
325
- }
326
- out += `\u{1F4D6} Dicas:
327
- `;
328
- out += ` \u2192 ${hint("areas", ctx)} - listar todas as areas disponiveis
329
- `;
330
- out += ` \u2192 ${hint("find", ctx)} - buscar simbolos por nome
331
- `;
332
- return out;
333
- }
334
- out += `\u{1F50D} Busca: "${result.query}"
335
-
336
- `;
337
- for (const area of result.areas) {
338
- out += `## ${area.name} (${area.id})
339
- `;
340
- out += `${area.description}
341
- `;
342
- out += `\u{1F4C1} ${area.fileCount} arquivo(s)
343
- `;
344
- if (area.symbolMatches && area.symbolMatches.length > 0) {
345
- out += `
346
- \u{1F517} Simbolos que correspondem a busca:
347
- `;
348
- const byFile = /* @__PURE__ */ new Map();
349
- for (const match of area.symbolMatches) {
350
- if (!byFile.has(match.file)) byFile.set(match.file, []);
351
- byFile.get(match.file).push(match);
352
- }
353
- const MAX_SYMBOLS = 5;
354
- let count = 0;
355
- for (const [file, matches] of byFile) {
356
- for (const match of matches) {
357
- if (count >= MAX_SYMBOLS) break;
358
- const matchLabel = match.matchType === "signature" ? "\u21B3" : match.matchType === "params" ? "\u2192 (param)" : "\u2192 (return)";
359
- out += ` ${matchLabel} ${file}
360
- `;
361
- out += ` ${match.signature}
362
- `;
363
- count++;
364
- }
365
- if (count >= MAX_SYMBOLS) break;
366
- }
367
- if (area.symbolMatches.length > MAX_SYMBOLS) {
368
- out += ` ... e mais ${area.symbolMatches.length - MAX_SYMBOLS} simbolo(s)
369
- `;
370
- }
371
- }
372
- out += "\n";
373
- if (area.files.length > 0) {
374
- const MAX_FILES = 5;
375
- const filesToShow = area.files.slice(0, MAX_FILES);
376
- const remaining = area.files.length - filesToShow.length;
377
- out += `Arquivos:
378
- `;
379
- for (const file of filesToShow) {
380
- out += ` \u2022 ${file}
381
- `;
382
- }
383
- if (remaining > 0) {
384
- out += ` ... e mais ${remaining} arquivo(s)
385
- `;
386
- out += ` \u2192 ${hint("area", ctx, { "<nome>": area.id })} - ver todos
387
- `;
388
- }
389
- out += "\n";
390
- }
391
- }
392
- out += nextSteps("describe", ctx);
393
- return out;
394
- }
395
-
396
- // src/commands/deps.ts
397
- import { readFileSync as readFileSync3, existsSync as existsSync3 } from "fs";
398
- import { join as join3 } from "path";
399
-
400
- // src/ts/package-reader.ts
401
- import { readFileSync, existsSync, readdirSync, statSync } from "fs";
402
- import { join, resolve } from "path";
403
- function resolvePackagePath(packageName, cwd) {
404
- const nmDir = join(cwd, "node_modules", packageName);
405
- if (existsSync(nmDir)) {
406
- logger.debug(`Pacote "${packageName}" resolvido em: ${nmDir}`);
407
- return resolve(nmDir);
408
- }
409
- throw new Error(
410
- `Pacote "${packageName}" nao encontrado em node_modules.
411
- \u2022 Verifique se o pacote esta instalado no projeto
412
- \u2022 Verifique se voce esta no diretorio correto: ${cwd}`
413
- );
414
- }
415
- function readPackageJson(packageName, cwd) {
416
- const pkgPath = resolvePackagePath(packageName, cwd);
417
- const pkgJsonPath = join(pkgPath, "package.json");
418
- if (!existsSync(pkgJsonPath)) {
419
- throw new Error(
420
- `package.json nao encontrado em: ${pkgJsonPath}
421
- \u2022 O pacote "${packageName}" pode estar corrompido.`
422
- );
423
- }
424
- const raw = readFileSync(pkgJsonPath, "utf-8");
425
- const pkg = JSON.parse(raw);
426
- const name = getStringField(pkg, "name") ?? packageName;
427
- const version = getStringField(pkg, "version") ?? "0.0.0";
428
- const description = getStringField(pkg, "description");
429
- const main = getStringField(pkg, "main");
430
- const types = getStringField(pkg, "types");
431
- const typings = getStringField(pkg, "typings");
432
- const exportsField = pkg.exports;
433
- const module = getStringField(pkg, "module");
434
- const repository = extractRepository(pkg);
435
- const homepage = getStringField(pkg, "homepage");
436
- const license = getStringField(pkg, "license");
437
- const author = extractAuthor(pkg);
438
- const dependencies = pkg.dependencies ?? {};
439
- const peerDependencies = pkg.peerDependencies ?? {};
440
- const hasTypes = !!(types || typings || exportsField);
441
- const typesSource = hasTypes ? "builtin" : void 0;
442
- const entryPoints = resolveEntryPoints(pkgPath, {
443
- main,
444
- types,
445
- typings,
446
- exportsField,
447
- module
448
- });
449
- return {
450
- version,
451
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
452
- package: packageName,
453
- resolvedPath: pkgPath,
454
- info: {
455
- name,
456
- version,
457
- description,
458
- main,
459
- types,
460
- typings,
461
- exports: exportsField,
462
- module,
463
- repository,
464
- homepage,
465
- license,
466
- author,
467
- dependencies,
468
- peerDependencies,
469
- hasTypes,
470
- typesSource
471
- },
472
- entryPoints
473
- };
474
- }
475
- function resolveTypeFilesWithSource(packageName, cwd) {
476
- const pkgPath = resolvePackagePath(packageName, cwd);
477
- const pkgJsonPath = join(pkgPath, "package.json");
478
- if (!existsSync(pkgJsonPath)) {
479
- throw new Error(`package.json nao encontrado em: ${pkgJsonPath}`);
480
- }
481
- const raw = readFileSync(pkgJsonPath, "utf-8");
482
- const pkg = JSON.parse(raw);
483
- const candidates = [];
484
- const types = getStringField(pkg, "types");
485
- if (types) {
486
- candidates.push(join(pkgPath, types));
487
- }
488
- const typings = getStringField(pkg, "typings");
489
- if (typings && !candidates.includes(join(pkgPath, typings))) {
490
- candidates.push(join(pkgPath, typings));
491
- }
492
- const exportsField = pkg.exports;
493
- if (exportsField && typeof exportsField === "object" && exportsField !== null) {
494
- const exportsEntries = resolveExportsTypes(pkgPath, exportsField);
495
- for (const entry of exportsEntries) {
496
- if (!candidates.includes(entry)) {
497
- candidates.push(entry);
498
- }
499
- }
500
- }
501
- const module = getStringField(pkg, "module");
502
- if (module && !candidates.length) {
503
- const dts = convertToDts(join(pkgPath, module));
504
- if (dts) candidates.push(dts);
505
- }
506
- const main = getStringField(pkg, "main");
507
- if (main && !candidates.length) {
508
- const dts = convertToDts(join(pkgPath, main));
509
- if (dts) candidates.push(dts);
510
- }
511
- if (!candidates.length) {
512
- const fallback = join(pkgPath, "index.d.ts");
513
- candidates.push(fallback);
514
- }
515
- const hasCtsMtsOnly = candidates.some(
516
- (c) => (c.endsWith(".d.cts") || c.endsWith(".d.mts")) && !c.endsWith(".d.ts")
517
- );
518
- if (hasCtsMtsOnly) {
519
- const dtsEquivalent = join(pkgPath, "index.d.ts");
520
- if (!candidates.includes(dtsEquivalent)) {
521
- candidates.push(dtsEquivalent);
522
- }
523
- }
524
- const existing = candidates.filter((f) => existsSync(f));
525
- const allCtsOrMts = existing.length > 0 && existing.every(
526
- (f) => f.endsWith(".d.cts") || f.endsWith(".d.mts")
527
- );
528
- const hasReExports = existing.length > 0 && existing.length <= 8;
529
- const shouldScan = allCtsOrMts || hasReExports;
530
- if (shouldScan) {
531
- const candidatesSet = new Set(existing.map((f) => f.toLowerCase()));
532
- const scanned2 = scanForDeclarationFiles(pkgPath, new Set(candidatesSet));
533
- for (const file of scanned2) {
534
- if (!candidatesSet.has(file.toLowerCase())) {
535
- candidates.push(file);
536
- }
537
- }
538
- const allExisting = candidates.filter((f) => existsSync(f));
539
- existing.length = 0;
540
- existing.push(...allExisting);
541
- }
542
- if (existing.length > 0) {
543
- logger.debug(`Type files para "${packageName}":`, existing);
544
- return { files: existing, source: "builtin" };
545
- }
546
- if (!packageName.startsWith("@types/")) {
547
- const typesPackageName = `@types/${packageName}`;
548
- try {
549
- const typesPkgPath = resolvePackagePath(typesPackageName, cwd);
550
- const typesPkgJsonPath = join(typesPkgPath, "package.json");
551
- if (existsSync(typesPkgJsonPath)) {
552
- const typesRaw = readFileSync(typesPkgJsonPath, "utf-8");
553
- const typesPkg = JSON.parse(typesRaw);
554
- const typesCandidates = [];
555
- const typesField = getStringField(typesPkg, "types");
556
- if (typesField) {
557
- typesCandidates.push(join(typesPkgPath, typesField));
558
- }
559
- const typingsField = getStringField(typesPkg, "typings");
560
- if (typingsField && !typesCandidates.length) {
561
- typesCandidates.push(join(typesPkgPath, typingsField));
562
- }
563
- if (!typesCandidates.length) {
564
- typesCandidates.push(join(typesPkgPath, "index.d.ts"));
565
- }
566
- const typesExisting = typesCandidates.filter((f) => existsSync(f));
567
- if (typesExisting.length > 0) {
568
- logger.debug(
569
- `Type files para "${packageName}" via @types:`,
570
- typesExisting
571
- );
572
- return {
573
- files: typesExisting,
574
- source: "@types",
575
- typesPackage: typesPackageName
576
- };
577
- }
578
- }
579
- } catch {
580
- logger.debug(
581
- `@types/${packageName} n\xE3o encontrado, tentando JS fallback`
582
- );
583
- }
584
- }
585
- const scanned = scanForDeclarationFiles(pkgPath, /* @__PURE__ */ new Set(), true);
586
- for (const file of scanned) {
587
- candidates.push(file);
588
- }
589
- if (scanned.length === 0) {
590
- const jsCandidates = resolveJsFiles(pkgPath, pkg);
591
- candidates.push(...jsCandidates);
592
- }
593
- const jsExisting = candidates.filter((f) => existsSync(f));
594
- if (jsExisting.length === 0) {
595
- throw new Error(
596
- `O pacote "${packageName}" nao possui TypeScript declarations.
597
- \u2022 Verifique se o pacote tem um campo "types" ou "typings" no package.json
598
- \u2022 Alguns pacotes distribuem tipos separados (ex: @types/nome-do-pacote)
599
- \u2022 Pacote resolvido em: ${pkgPath}`
600
- );
601
- }
602
- logger.debug(`Type files para "${packageName}" (JS fallback):`, jsExisting);
603
- return { files: jsExisting, source: "js-fallback" };
604
- }
605
- function resolveEntryPointFile(packageName, entry, cwd) {
606
- const pkgPath = resolvePackagePath(packageName, cwd);
607
- const pkgJsonPath = join(pkgPath, "package.json");
608
- if (!existsSync(pkgJsonPath)) {
609
- throw new Error(`package.json nao encontrado em: ${pkgJsonPath}`);
610
- }
611
- const raw = readFileSync(pkgJsonPath, "utf-8");
612
- const pkg = JSON.parse(raw);
613
- const exportsField = pkg.exports;
614
- if (!exportsField || typeof exportsField !== "object" || exportsField === null) {
615
- throw new Error(
616
- `Pacote "${packageName}" nao possui campo "exports" no package.json`
617
- );
618
- }
619
- const exports = exportsField;
620
- const exportKey = `./${entry}`;
621
- const exportValue = exports[exportKey];
622
- if (!exportValue || typeof exportValue !== "object" || exportValue === null) {
623
- throw new Error(
624
- `Sub-export "./${entry}" nao encontrado em "${packageName}". Exports disponiveis: ${Object.keys(exports).filter((k) => k.startsWith("./")).join(", ")}`
625
- );
626
- }
627
- const nested = exportValue;
628
- const conditions = ["types", "typings", "import", "default"];
629
- for (const condition of conditions) {
630
- const value = nested[condition];
631
- if (typeof value === "string") {
632
- const candidate = join(pkgPath, value);
633
- if (value.endsWith(".js") || value.endsWith(".mjs") || value.endsWith(".cjs")) {
634
- const dts = convertToDts(candidate);
635
- if (dts && existsSync(dts)) return dts;
636
- }
637
- if (existsSync(candidate)) return candidate;
638
- }
639
- }
640
- throw new Error(
641
- `Nao foi possivel resolver o arquivo de tipos para "${packageName}/${entry}". Tente usar "deps api ${packageName}" para ver todos os exports disponiveis.`
642
- );
643
- }
644
- function getSubExportPaths(packageName, cwd) {
645
- try {
646
- const pkgPath = resolvePackagePath(packageName, cwd);
647
- const pkgJsonPath = join(pkgPath, "package.json");
648
- if (!existsSync(pkgJsonPath)) return [];
649
- const raw = readFileSync(pkgJsonPath, "utf-8");
650
- const pkg = JSON.parse(raw);
651
- const exportsField = pkg.exports;
652
- if (!exportsField || typeof exportsField !== "object" || exportsField === null) {
653
- return [];
654
- }
655
- const exports = exportsField;
656
- return Object.keys(exports).filter((k) => k.startsWith("./")).map((k) => k.slice(2));
657
- } catch {
658
- return [];
659
- }
660
- }
661
- function resolveEntryPoints(pkgPath, fields) {
662
- const raw = [];
663
- if (fields.types) {
664
- raw.push({ condition: "types", path: join(pkgPath, fields.types), type: "types" });
665
- }
666
- if (fields.typings) {
667
- raw.push({ condition: "typings", path: join(pkgPath, fields.typings), type: "types" });
668
- }
669
- if (fields.main) {
670
- raw.push({ condition: "main", path: join(pkgPath, fields.main), type: "main" });
671
- }
672
- if (fields.module) {
673
- raw.push({ condition: "module", path: join(pkgPath, fields.module), type: "module" });
674
- }
675
- if (fields.exportsField) {
676
- for (const [condition, value] of Object.entries(fields.exportsField)) {
677
- if (typeof value === "string") {
678
- raw.push({ condition, path: join(pkgPath, value), type: classifyExportCondition(condition) });
679
- } else if (typeof value === "object" && value !== null) {
680
- const nested = value;
681
- for (const [nestedCondition, nestedValue] of Object.entries(nested)) {
682
- if (typeof nestedValue === "string") {
683
- const fullCondition = condition === "." ? nestedCondition : `${condition}/${nestedCondition}`;
684
- raw.push({
685
- condition: fullCondition,
686
- path: join(pkgPath, nestedValue),
687
- type: classifyExportCondition(nestedCondition)
688
- });
689
- }
690
- }
691
- }
692
- }
693
- }
694
- return deduplicateEntryPoints(raw);
695
- }
696
- function deduplicateEntryPoints(points) {
697
- const seen = /* @__PURE__ */ new Map();
698
- for (const point of points) {
699
- const normalizedPath = point.path.toLowerCase();
700
- const existing = seen.get(normalizedPath);
701
- if (existing) {
702
- const existingConditions = new Set(existing.condition.split(", "));
703
- const newConditions = point.condition.split(", ");
704
- for (const c of newConditions) {
705
- existingConditions.add(c);
706
- }
707
- existing.condition = Array.from(existingConditions).join(", ");
708
- } else {
709
- seen.set(normalizedPath, { ...point });
710
- }
711
- }
712
- return Array.from(seen.values());
713
- }
714
- function classifyExportCondition(condition) {
715
- if (condition === "types" || condition === "typings") return "types";
716
- if (condition === "import") return "import";
717
- if (condition === "require") return "require";
718
- if (condition === "default" || condition === ".") return "default";
719
- if (condition === "module") return "module";
720
- return "default";
721
- }
722
- function resolveExportsTypes(pkgPath, exportsField) {
723
- const results = [];
724
- for (const [, value] of Object.entries(exportsField)) {
725
- if (typeof value === "string") {
726
- if (value.endsWith(".d.ts") || value.endsWith(".d.mts") || value.endsWith(".d.cts")) {
727
- results.push(join(pkgPath, value));
728
- }
729
- } else if (typeof value === "object" && value !== null) {
730
- const nested = value;
731
- if (typeof nested.types === "string") {
732
- results.push(join(pkgPath, nested.types));
733
- }
734
- if (typeof nested.typings === "string") {
735
- results.push(join(pkgPath, nested.typings));
736
- }
737
- }
738
- }
739
- return results;
740
- }
741
- function convertToDts(filePath) {
742
- if (filePath.endsWith(".mjs")) return filePath.replace(/\.mjs$/, ".d.mts");
743
- if (filePath.endsWith(".cjs")) return filePath.replace(/\.cjs$/, ".d.cts");
744
- if (filePath.endsWith(".js")) return filePath.replace(/\.js$/, ".d.ts");
745
- return void 0;
746
- }
747
- function getStringField(obj, field, fallback) {
748
- const value = obj[field];
749
- if (typeof value === "string") return value;
750
- return fallback;
751
- }
752
- function extractRepository(pkg) {
753
- const repo = pkg.repository;
754
- if (typeof repo === "string") return repo;
755
- if (typeof repo === "object" && repo !== null) {
756
- const url = repo.url;
757
- if (typeof url === "string") return url;
758
- }
759
- return void 0;
760
- }
761
- function extractAuthor(pkg) {
762
- const author = pkg.author;
763
- if (typeof author === "string") return author;
764
- if (typeof author === "object" && author !== null) {
765
- const name = author.name;
766
- if (typeof name === "string") return name;
767
- }
768
- return void 0;
769
- }
770
- function resolveJsFiles(pkgPath, pkg) {
771
- const results = [];
772
- const main = getStringField(pkg, "main");
773
- if (main) {
774
- const mainPath = join(pkgPath, main);
775
- if (existsSync(mainPath)) {
776
- results.push(mainPath);
777
- }
778
- }
779
- const module = getStringField(pkg, "module");
780
- if (module && results.length === 0) {
781
- const modulePath = join(pkgPath, module);
782
- if (existsSync(modulePath)) {
783
- results.push(modulePath);
784
- }
785
- }
786
- const exportsField = pkg.exports;
787
- if (exportsField && typeof exportsField === "object" && exportsField !== null && results.length === 0) {
788
- const exports = exportsField;
789
- const dotExport = exports["."];
790
- if (typeof dotExport === "object" && dotExport !== null) {
791
- const nested = dotExport;
792
- for (const condition of ["import", "default"]) {
793
- const path = nested[condition];
794
- if (typeof path === "string") {
795
- const fullPath = join(pkgPath, path);
796
- if (existsSync(fullPath)) {
797
- results.push(fullPath);
798
- break;
799
- }
800
- }
801
- }
802
- }
803
- if (typeof dotExport === "string" && results.length === 0) {
804
- const fullPath = join(pkgPath, dotExport);
805
- if (existsSync(fullPath)) {
806
- results.push(fullPath);
807
- }
808
- }
809
- }
810
- if (results.length === 0) {
811
- const indexPath = join(pkgPath, "index.js");
812
- if (existsSync(indexPath)) {
813
- results.push(indexPath);
814
- }
815
- }
816
- return results;
817
- }
818
- function scanForDeclarationFiles(packagePath, existingFiles, allowJs = false) {
819
- const MAX_FILES = 300;
820
- const MAX_DEPTH = 3;
821
- const MAX_JS_SIZE = 50 * 1024;
822
- const MAX_INDEX_EXTRA = 200;
823
- const results = [];
824
- const pendingIndexDirs = [];
825
- function scan(dir, depth) {
826
- if (depth > MAX_DEPTH || results.length >= MAX_FILES) return;
827
- try {
828
- const entries = readdirSync(dir);
829
- for (const entry of entries) {
830
- if (results.length >= MAX_FILES) break;
831
- if (entry === "node_modules" || entry.startsWith(".")) continue;
832
- const fullPath = join(dir, entry);
833
- try {
834
- const stat = statSync(fullPath);
835
- if (stat.isDirectory()) {
836
- const subIndexPath = join(fullPath, "index.d.ts");
837
- const hasSubIndex = existsSync(subIndexPath) && !existingFiles.has(subIndexPath.toLowerCase());
838
- scan(fullPath, depth + 1);
839
- if (results.length >= MAX_FILES && hasSubIndex) {
840
- pendingIndexDirs.push(subIndexPath);
841
- }
842
- } else {
843
- const isJsFile = allowJs && (entry.endsWith(".js") || entry.endsWith(".mjs") || entry.endsWith(".cjs"));
844
- const isDtFile = entry.endsWith(".d.ts") || entry.endsWith(".d.mts") || entry.endsWith(".d.cts");
845
- if ((isDtFile || isJsFile) && !existingFiles.has(fullPath.toLowerCase())) {
846
- try {
847
- const content = readFileSync(fullPath, "utf-8");
848
- if (isJsFile) {
849
- if (content.length > MAX_JS_SIZE) continue;
850
- }
851
- results.push(fullPath);
852
- existingFiles.add(fullPath.toLowerCase());
853
- } catch {
854
- }
855
- }
856
- }
857
- } catch {
858
- }
859
- }
860
- } catch {
861
- }
862
- }
863
- scan(packagePath, 0);
864
- for (const indexPath of pendingIndexDirs) {
865
- if (results.length >= MAX_FILES + MAX_INDEX_EXTRA) break;
866
- if (!existingFiles.has(indexPath.toLowerCase())) {
867
- results.push(indexPath);
868
- existingFiles.add(indexPath.toLowerCase());
869
- }
870
- }
871
- collectRemainingIndexFiles(packagePath, existingFiles, results, MAX_FILES + MAX_INDEX_EXTRA);
872
- return deduplicateCjsEsmPairs(results);
873
- }
874
- function deduplicateCjsEsmPairs(typeFiles) {
875
- if (typeFiles.length <= 1) return typeFiles;
876
- const moduleSegments = /* @__PURE__ */ new Set(["esm", "cjs", "lib", "es", "dist"]);
877
- const groups = /* @__PURE__ */ new Map();
878
- for (const filePath of typeFiles) {
879
- const baseName = computeBaseName(filePath, moduleSegments);
880
- const existing = groups.get(baseName);
881
- if (existing) {
882
- existing.push(filePath);
883
- } else {
884
- groups.set(baseName, [filePath]);
885
- }
886
- }
887
- const deduplicated = [];
888
- let removedCount = 0;
889
- for (const [, group] of groups) {
890
- if (group.length === 1) {
891
- deduplicated.push(group[0]);
892
- continue;
893
- }
894
- const esmFile = pickEsmVariant(group);
895
- deduplicated.push(esmFile);
896
- removedCount += group.length - 1;
897
- }
898
- if (removedCount > 0) {
899
- logger.debug(
900
- `Deduplica\xE7\xE3o CJS/ESM: ${typeFiles.length} \u2192 ${deduplicated.length} type files (removidos ${removedCount} duplicatas)`
901
- );
902
- }
903
- return deduplicated;
904
- }
905
- function computeBaseName(filePath, moduleSegments) {
906
- const parts = filePath.replace(/\\/g, "/").split("/");
907
- const filtered = [];
908
- for (const part of parts) {
909
- if (moduleSegments.has(part)) continue;
910
- filtered.push(part);
911
- }
912
- return filtered.join("/");
913
- }
914
- function pickEsmVariant(group) {
915
- const mtsFile = group.find((f) => f.endsWith(".d.mts"));
916
- if (mtsFile) return mtsFile;
917
- const normalizedPath = group.find((f) => {
918
- const lower = f.replace(/\\/g, "/").toLowerCase();
919
- return lower.includes("/esm/") || lower.endsWith("/es") || lower.includes("/es/");
920
- });
921
- if (normalizedPath) return normalizedPath;
922
- return group[0];
923
- }
924
- function collectRemainingIndexFiles(packagePath, existingFiles, results, maxFiles) {
925
- try {
926
- const entries = readdirSync(packagePath);
927
- for (const entry of entries) {
928
- if (results.length >= maxFiles) break;
929
- if (entry === "node_modules" || entry.startsWith(".")) continue;
930
- const fullPath = join(packagePath, entry);
931
- try {
932
- const stat = statSync(fullPath);
933
- if (!stat.isDirectory()) continue;
934
- const indexPath = join(fullPath, "index.d.ts");
935
- if (existsSync(indexPath) && !existingFiles.has(indexPath.toLowerCase())) {
936
- results.push(indexPath);
937
- existingFiles.add(indexPath.toLowerCase());
938
- }
939
- } catch {
940
- }
941
- }
942
- } catch {
943
- }
944
- }
945
-
946
- // src/ts/package-extractor.ts
947
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
948
- import { dirname, join as join2, resolve as resolve2 } from "path";
949
- import { Project } from "ts-morph";
950
-
951
- // src/ts/kind-resolvers.ts
952
- var REACT_COMPONENT_FACTORIES = /* @__PURE__ */ new Set([
953
- // React API principal
954
- "memo",
955
- "forwardRef",
956
- "lazy",
957
- "createContext",
958
- "createElement",
959
- "cloneElement",
960
- "createFactory",
961
- // Hooks que retornam componentes
962
- "useCallback",
963
- "useMemo",
964
- // Suspense e ErrorBoundary
965
- "Suspense",
966
- "ErrorBoundary",
967
- // Factory patterns
968
- "createComponent",
969
- "forwardRefLazy"
970
- ]);
971
- function isReactComponentFactory(name) {
972
- const cleanName = stripModulePrefix(name);
973
- return REACT_COMPONENT_FACTORIES.has(cleanName);
974
- }
975
- function stripModulePrefix(name) {
976
- const dotIdx = name.indexOf(".");
977
- if (dotIdx === -1) return name;
978
- const prefix = name.slice(0, dotIdx);
979
- if (prefix.startsWith('"') || prefix.startsWith("'")) {
980
- return name.slice(dotIdx + 1);
981
- }
982
- if (/^[A-Za-z]+$/.test(prefix) && /^[A-Z]/.test(prefix)) {
983
- return name.slice(dotIdx + 1);
984
- }
985
- return name;
986
- }
987
- var defaultResolver = {
988
- canHandle: () => true,
989
- // Fallback - sempre se aplica
990
- classifyFunction(name, returnType) {
991
- const cleanName = stripModulePrefix(name);
992
- if (cleanName.startsWith("use") && cleanName.length > 3 && cleanName[3] === cleanName[3].toUpperCase()) {
993
- return "hook";
994
- }
995
- if (isReactComponentFactory(name)) {
996
- return "component";
997
- }
998
- if (/^[A-Z]/.test(cleanName)) {
999
- if (returnType) {
1000
- const rt = returnType.toLowerCase();
1001
- if (rt.includes("jsx.element") || rt.includes("reactelement") || rt.includes("reactnode") || rt.includes("react.fc") || rt.includes("elementtype") || rt.includes("react.componenttype") || rt.includes("fc<") || rt.includes(".element")) {
1002
- return "component";
1003
- }
1004
- }
1005
- return "function";
1006
- }
1007
- return "function";
1008
- },
1009
- classifyType(_name, kind) {
1010
- return kind;
1011
- }
1012
- };
1013
- var reactResolver = {
1014
- canHandle(packageName) {
1015
- return packageName === "react" || packageName === "@types/react" || packageName === "react-dom" || packageName === "@types/react-dom";
1016
- },
1017
- classifyFunction(name, returnType) {
1018
- const cleanName = stripModulePrefix(name);
1019
- const reactHooks = /* @__PURE__ */ new Set([
1020
- // Hooks basicos
1021
- "useState",
1022
- "useEffect",
1023
- "useContext",
1024
- "useReducer",
1025
- "useCallback",
1026
- "useMemo",
1027
- "useRef",
1028
- "useImperativeHandle",
1029
- "useLayoutEffect",
1030
- "useDebugValue",
1031
- "useId",
1032
- // Hooks adicionais
1033
- "useTransition",
1034
- "useDeferredValue",
1035
- "useSyncExternalStore",
1036
- "useInsertionEffect",
1037
- "useFormStatus",
1038
- "useActionState",
1039
- "useOptimistic",
1040
- "use"
1041
- ]);
1042
- if (reactHooks.has(cleanName)) {
1043
- return "hook";
1044
- }
1045
- if (isReactComponentFactory(name)) {
1046
- return "component";
1047
- }
1048
- if (cleanName.startsWith("use") && cleanName.length > 3 && cleanName[3] === cleanName[3].toUpperCase()) {
1049
- return "hook";
1050
- }
1051
- if (/^[A-Z]/.test(cleanName)) {
1052
- if (returnType) {
1053
- const rt = returnType.toLowerCase();
1054
- if (rt.includes("jsx.element") || rt.includes("reactelement") || rt.includes("reactnode") || rt.includes("react.fc") || rt.includes("elementtype") || rt.includes("react.componenttype") || rt.includes("fc<") || rt.includes(".element")) {
1055
- return "component";
1056
- }
1057
- }
1058
- return "function";
1059
- }
1060
- return "function";
1061
- },
1062
- classifyType(name, kind) {
1063
- const cleanName = stripModulePrefix(name);
1064
- const reactComponentInterfaces = /* @__PURE__ */ new Set([
1065
- "FC",
1066
- "FunctionComponent",
1067
- "ComponentType",
1068
- "ElementType",
1069
- "Element",
1070
- "ReactElement",
1071
- "ReactNode",
1072
- "Component",
1073
- "PureComponent",
1074
- "ForwardRefExoticComponent",
1075
- "ExoticComponent"
1076
- ]);
1077
- if (reactComponentInterfaces.has(cleanName)) {
1078
- return "component";
1079
- }
1080
- return kind;
1081
- }
1082
- };
1083
- var resolvers = [
1084
- reactResolver,
1085
- defaultResolver
1086
- // Fallback - deve ser o ultimo
1087
- ];
1088
- function getResolver(packageName) {
1089
- for (const resolver of resolvers) {
1090
- if (resolver.canHandle(packageName)) {
1091
- return resolver;
1092
- }
1093
- }
1094
- return defaultResolver;
1095
- }
1096
- function classifyFunctionKind(name, returnType, packageName) {
1097
- const resolver = packageName ? getResolver(packageName) : defaultResolver;
1098
- return resolver.classifyFunction(name, returnType);
1099
- }
1100
- function classifyTypeKind(name, kind, packageName) {
1101
- const resolver = packageName ? getResolver(packageName) : defaultResolver;
1102
- return resolver.classifyType(name, kind);
1103
- }
1104
- function classifySymbol(symbolKind, name, returnType, packageName) {
1105
- if (symbolKind === "function") {
1106
- return classifyFunctionKind(name, returnType, packageName);
1107
- }
1108
- if (symbolKind === "type" || symbolKind === "interface" || symbolKind === "enum") {
1109
- return classifyTypeKind(name, symbolKind, packageName);
1110
- }
1111
- return "const";
1112
- }
1113
- function isSemanticKindMatch(actualKind, requestedKind) {
1114
- if (actualKind === requestedKind) return true;
1115
- if (requestedKind === "type") {
1116
- return actualKind === "interface" || actualKind === "enum" || actualKind === "const";
1117
- }
1118
- if (requestedKind === "function") {
1119
- return actualKind === "component" || actualKind === "hook";
1120
- }
1121
- return false;
1122
- }
1123
-
1124
- // src/ts/package-extractor.ts
1125
- var MAX_REEXPORT_DEPTH = 3;
1126
- var MAX_TOTAL_FILES = 1200;
1127
- var TYPE_DECLARATION_EXTENSIONS = [".d.ts", ".d.cts", ".d.mts", ".d.tsx"];
1128
- var JS_EXTENSIONS = [".js", ".cjs", ".mjs", ".ts", ".cts", ".mts"];
1129
- function findNodeModulesDir(packagePath) {
1130
- const normalizedPath = packagePath.replace(/\\/g, "/");
1131
- const idx = normalizedPath.lastIndexOf("node_modules");
1132
- if (idx === -1) return dirname(packagePath);
1133
- return resolve2(packagePath.substring(0, idx + "node_modules".length));
1134
- }
1135
- function resolveModuleSpecifier(specifier, fromFilePath, nodeModulesDir) {
1136
- if (specifier.startsWith("./") || specifier.startsWith("../")) {
1137
- return resolveRelativePath(specifier, fromFilePath);
1138
- }
1139
- return resolveBareModule(specifier, nodeModulesDir);
1140
- }
1141
- function stripJsExtension(specifier) {
1142
- for (const ext of JS_EXTENSIONS) {
1143
- if (specifier.endsWith(ext)) {
1144
- return specifier.slice(0, -ext.length);
1145
- }
1146
- }
1147
- return specifier;
1148
- }
1149
- function resolveRelativePath(specifier, fromFilePath) {
1150
- const dir = dirname(fromFilePath);
1151
- const cleanSpecifier = stripJsExtension(specifier);
1152
- for (const ext of TYPE_DECLARATION_EXTENSIONS) {
1153
- const candidate = resolve2(dir, cleanSpecifier + ext);
1154
- if (existsSync2(candidate)) return candidate;
1155
- }
1156
- const asIs = resolve2(dir, specifier);
1157
- if (existsSync2(asIs)) return asIs;
1158
- for (const ext of TYPE_DECLARATION_EXTENSIONS) {
1159
- const indexCandidate = resolve2(dir, cleanSpecifier, "index" + ext);
1160
- if (existsSync2(indexCandidate)) return indexCandidate;
1161
- }
1162
- return void 0;
1163
- }
1164
- function convertToDts2(filePath) {
1165
- if (filePath.endsWith(".mjs")) return filePath.replace(/\.mjs$/, ".d.mts");
1166
- if (filePath.endsWith(".cjs")) return filePath.replace(/\.cjs$/, ".d.cts");
1167
- if (filePath.endsWith(".js")) return filePath.replace(/\.js$/, ".d.ts");
1168
- return void 0;
1169
- }
1170
- function resolveBareModule(specifier, nodeModulesDir) {
1171
- const pkgDir = resolve2(nodeModulesDir, specifier);
1172
- const pkgJsonPath = join2(pkgDir, "package.json");
1173
- if (!existsSync2(pkgJsonPath)) return void 0;
1174
- try {
1175
- const raw = readFileSync2(pkgJsonPath, "utf-8");
1176
- const pkg = JSON.parse(raw);
1177
- const exportsField = pkg.exports;
1178
- if (exportsField && typeof exportsField === "object" && exportsField !== null) {
1179
- const exports = exportsField;
1180
- const dotExport = exports["."];
1181
- if (typeof dotExport === "object" && dotExport !== null) {
1182
- const nested = dotExport;
1183
- for (const condition of ["types", "typings", "import", "default"]) {
1184
- const value = nested[condition];
1185
- if (typeof value === "string") {
1186
- const candidate = join2(pkgDir, value);
1187
- if (existsSync2(candidate)) return candidate;
1188
- const dts = convertToDts2(candidate);
1189
- if (dts && existsSync2(dts)) return dts;
1190
- }
1191
- }
1192
- }
1193
- if (typeof dotExport === "string") {
1194
- const candidate = join2(pkgDir, dotExport);
1195
- if (existsSync2(candidate)) return candidate;
1196
- const dts = convertToDts2(candidate);
1197
- if (dts && existsSync2(dts)) return dts;
1198
- }
1199
- }
1200
- const typesField = pkg.types;
1201
- if (typeof typesField === "string") {
1202
- const candidate = join2(pkgDir, typesField);
1203
- if (existsSync2(candidate)) return candidate;
1204
- }
1205
- const typingsField = pkg.typings;
1206
- if (typeof typingsField === "string") {
1207
- const candidate = join2(pkgDir, typingsField);
1208
- if (existsSync2(candidate)) return candidate;
1209
- }
1210
- const mainField = pkg.main;
1211
- if (typeof mainField === "string") {
1212
- const candidate = join2(pkgDir, mainField);
1213
- const dts = convertToDts2(candidate);
1214
- if (dts && existsSync2(dts)) return dts;
1215
- }
1216
- const indexDts = join2(pkgDir, "index.d.ts");
1217
- if (existsSync2(indexDts)) return indexDts;
1218
- } catch {
1219
- logger.debug(`Falha ao ler package.json em: ${pkgJsonPath}`);
1220
- }
1221
- return void 0;
1222
- }
1223
- function followReExports(project, sourceFiles, visited, nodeModulesDir, depth) {
1224
- if (depth >= MAX_REEXPORT_DEPTH || visited.size >= MAX_TOTAL_FILES) return [];
1225
- const newFiles = [];
1226
- const namedReExportFiles = [];
1227
- let followedCount = 0;
1228
- let failedCount = 0;
1229
- let skippedCount = 0;
1230
- for (const sourceFile of sourceFiles) {
1231
- if (visited.size >= MAX_TOTAL_FILES) break;
1232
- for (const exportDecl of sourceFile.getExportDeclarations()) {
1233
- if (visited.size >= MAX_TOTAL_FILES) break;
1234
- const specifier = exportDecl.getModuleSpecifierValue();
1235
- if (!specifier) continue;
1236
- const filePath = sourceFile.getFilePath();
1237
- let resolvedPath;
1238
- try {
1239
- const resolvedFile = exportDecl.getModuleSpecifierSourceFile();
1240
- if (resolvedFile) {
1241
- resolvedPath = resolvedFile.getFilePath();
1242
- if (resolvedPath.endsWith(".js") || resolvedPath.endsWith(".mjs") || resolvedPath.endsWith(".cjs")) {
1243
- const dtsPath = convertToDts2(resolvedPath);
1244
- if (dtsPath && existsSync2(dtsPath)) {
1245
- resolvedPath = dtsPath;
1246
- }
1247
- }
1248
- }
1249
- } catch {
1250
- }
1251
- if (!resolvedPath) {
1252
- resolvedPath = resolveModuleSpecifier(specifier, filePath, nodeModulesDir);
1253
- }
1254
- if (!resolvedPath || visited.has(resolvedPath)) {
1255
- if (resolvedPath && visited.has(resolvedPath)) skippedCount++;
1256
- if (!resolvedPath) failedCount++;
1257
- continue;
1258
- }
1259
- visited.add(resolvedPath);
1260
- try {
1261
- if (!existsSync2(resolvedPath)) {
1262
- failedCount++;
1263
- continue;
1264
- }
1265
- const isNamespace = exportDecl.isNamespaceExport();
1266
- const isNamedReExport = !isNamespace && exportDecl.getNamedExports().length > 0;
1267
- logger.debug(
1268
- `${isNamespace ? "Namespace re-export" : "Named re-export"} (depth ${depth}): ${specifier} -> ${resolvedPath}`
1269
- );
1270
- const newSourceFile = addSourceFile(project, resolvedPath);
1271
- followedCount++;
1272
- if (isNamespace) {
1273
- newFiles.push(newSourceFile);
1274
- } else if (isNamedReExport) {
1275
- namedReExportFiles.push(newSourceFile);
1276
- }
1277
- } catch (err) {
1278
- failedCount++;
1279
- logger.debug(`Falha ao seguir re-export "${specifier}":`, err);
1280
- }
1281
- }
1282
- }
1283
- if (followedCount > 0 || failedCount > 0) {
1284
- logger.debug(
1285
- `Re-export stats (depth ${depth}): ${followedCount} followed, ${failedCount} failed, ${skippedCount} skipped (visited: ${visited.size}/${MAX_TOTAL_FILES})`
1286
- );
1287
- }
1288
- if (newFiles.length > 0) {
1289
- const deeperFiles = followReExports(
1290
- project,
1291
- newFiles,
1292
- visited,
1293
- nodeModulesDir,
1294
- depth + 1
1295
- );
1296
- newFiles.push(...deeperFiles);
1297
- }
1298
- return [...newFiles, ...namedReExportFiles];
1299
- }
1300
- function resolveDefaultReExportNames(originalFiles, allSourceFiles, publicApiNames) {
1301
- const fileMap = /* @__PURE__ */ new Map();
1302
- for (const sf of allSourceFiles) {
1303
- fileMap.set(sf.getFilePath().replace(/\\/g, "/"), sf);
1304
- }
1305
- for (const sf of originalFiles) {
1306
- for (const exportDecl of sf.getExportDeclarations()) {
1307
- const hasDefaultExport = exportDecl.getNamedExports().some(
1308
- (ne) => ne.getName() === "default"
1309
- );
1310
- if (!hasDefaultExport) continue;
1311
- const specifier = exportDecl.getModuleSpecifierValue();
1312
- if (!specifier) continue;
1313
- let defaultName;
1314
- try {
1315
- const resolved = exportDecl.getModuleSpecifierSourceFile();
1316
- if (resolved) {
1317
- defaultName = resolveDefaultExportName(resolved);
1318
- }
1319
- } catch {
1320
- }
1321
- if (!defaultName && specifier.startsWith("./")) {
1322
- const dir = sf.getFilePath().replace(/\\/g, "/");
1323
- const parentDir = dir.substring(0, dir.lastIndexOf("/"));
1324
- const candidatePath = resolve2(parentDir, stripJsExtension(specifier) + ".d.ts").replace(/\\/g, "/");
1325
- const target = fileMap.get(candidatePath);
1326
- if (target) {
1327
- defaultName = resolveDefaultExportName(target);
1328
- }
1329
- }
1330
- if (defaultName) {
1331
- publicApiNames.add(defaultName);
1332
- }
1333
- }
1334
- }
1335
- }
1336
- function resolveDefaultExportName(sourceFile) {
1337
- for (const exportAssign of sourceFile.getExportAssignments()) {
1338
- const expr = exportAssign.getExpression();
1339
- if (!expr) continue;
1340
- const name = expr.getText();
1341
- if (name) return name;
1342
- }
1343
- return void 0;
1344
- }
1345
- function extractPackageApi(typeFiles, packagePath, options) {
1346
- const limit = options?.limit ?? 50;
1347
- logger.debug(`Extraindo API do pacote: ${packagePath}`);
1348
- logger.debug(`Type files (${typeFiles.length}):`, typeFiles);
1349
- const jsFallback = typeFiles.length > 0 && typeFiles.every(
1350
- (f) => f.endsWith(".js") || f.endsWith(".mjs") || f.endsWith(".cjs")
1351
- );
1352
- if (jsFallback) {
1353
- logger.debug("Modo JS fallback ativado - incluindo todas as funcoes nomeadas");
1354
- }
1355
- const nodeModulesDir = findNodeModulesDir(packagePath);
1356
- const project = new Project({
1357
- skipAddingFilesFromTsConfig: true,
1358
- compilerOptions: {
1359
- allowJs: true,
1360
- checkJs: false,
1361
- declaration: true,
1362
- // Permite resolucao de types dentro do node_modules
1363
- moduleResolution: 100,
1364
- // Bundler
1365
- target: 2,
1366
- // ES2020
1367
- module: 200
1368
- // ESNext
1369
- }
1370
- });
1371
- try {
1372
- return extractPackageApiImpl(project, typeFiles, packagePath, limit, jsFallback, nodeModulesDir);
1373
- } finally {
1374
- project.getLanguageService().compilerObject.dispose();
1375
- }
1376
- }
1377
- function extractPackageApiImpl(project, typeFiles, packagePath, limit, jsFallback, nodeModulesDir) {
1378
- const visited = /* @__PURE__ */ new Set();
1379
- const sourceFiles = [];
1380
- for (const filePath of typeFiles) {
1381
- if (visited.size >= MAX_TOTAL_FILES) break;
1382
- if (visited.has(filePath)) continue;
1383
- visited.add(filePath);
1384
- try {
1385
- if (!existsSync2(filePath)) {
1386
- logger.debug(`Arquivo nao encontrado, ignorando: ${filePath}`);
1387
- continue;
1388
- }
1389
- const sourceFile = addSourceFile(project, filePath);
1390
- sourceFiles.push(sourceFile);
1391
- } catch (err) {
1392
- logger.debug(`Falha ao adicionar arquivo ${filePath}:`, err);
1393
- }
1394
- }
1395
- if (sourceFiles.length === 0) {
1396
- logger.debug("Nenhum source file adicionado ao projeto");
1397
- return { functions: [], types: [], constants: [], truncated: { functions: false, types: false, totalFunctions: 0, totalTypes: 0, shown: 0 } };
1398
- }
1399
- const originalFileCount = sourceFiles.length;
1400
- if (!jsFallback && nodeModulesDir) {
1401
- const reExportedFiles = followReExports(
1402
- project,
1403
- sourceFiles,
1404
- visited,
1405
- nodeModulesDir,
1406
- 0
1407
- );
1408
- if (reExportedFiles.length > 0) {
1409
- sourceFiles.push(...reExportedFiles);
1410
- logger.debug(
1411
- `Seguiu ${reExportedFiles.length} re-exports (${visited.size} arquivos total)`
1412
- );
1413
- }
1414
- }
1415
- const originalFiles = sourceFiles.slice(0, originalFileCount);
1416
- const publicApiNames = /* @__PURE__ */ new Set();
1417
- for (const sf of originalFiles) {
1418
- const names = extractExports(sf);
1419
- for (const name of names) {
1420
- publicApiNames.add(name);
1421
- }
1422
- }
1423
- resolveDefaultReExportNames(originalFiles, sourceFiles, publicApiNames);
1424
- const allFunctions = [];
1425
- const allTypes = [];
1426
- const allConstants = [];
1427
- for (const sourceFile of sourceFiles) {
1428
- const functions = extractFunctions(sourceFile);
1429
- const types = extractTypes(sourceFile);
1430
- const exportNames = new Set(extractExports(sourceFile));
1431
- const sourceFilePath = sourceFile.getFilePath().replace(/\\/g, "/");
1432
- const pkgPathNormalized = packagePath.replace(/\\/g, "/");
1433
- let relativeSource;
1434
- if (sourceFilePath.startsWith(pkgPathNormalized)) {
1435
- relativeSource = sourceFilePath.slice(pkgPathNormalized.length).replace(/^\//, "");
1436
- } else {
1437
- const nmIdx = sourceFilePath.indexOf("node_modules/");
1438
- if (nmIdx !== -1) {
1439
- relativeSource = sourceFilePath.slice(nmIdx + "node_modules/".length);
1440
- } else {
1441
- relativeSource = sourceFilePath;
1442
- }
1443
- }
1444
- for (const fn of functions) {
1445
- if (fn.name.startsWith("_")) continue;
1446
- if (isLikelyMinified(fn.name)) continue;
1447
- if (fn.isExported || exportNames.has(fn.name) || publicApiNames.has(fn.name) || jsFallback) {
1448
- allFunctions.push({
1449
- ...fn,
1450
- sourceFile: relativeSource,
1451
- kind: classifySymbol("function", fn.name, fn.returnType)
1452
- });
1453
- }
1454
- }
1455
- for (const type of types) {
1456
- if (type.name.startsWith("_")) continue;
1457
- if (isLikelyMinified(type.name)) continue;
1458
- if (type.isExported || exportNames.has(type.name) || publicApiNames.has(type.name) || jsFallback) {
1459
- allTypes.push({ ...type, sourceFile: relativeSource });
1460
- }
1461
- }
1462
- const constants = extractConstants(sourceFile, jsFallback);
1463
- for (const constant of constants) {
1464
- if (constant.name.startsWith("_")) continue;
1465
- if (isLikelyMinified(constant.name)) continue;
1466
- if (constant.isExported || exportNames.has(constant.name) || publicApiNames.has(constant.name) || jsFallback) {
1467
- allConstants.push({ ...constant, sourceFile: relativeSource });
1468
- }
1469
- }
1470
- }
1471
- const uniqueFunctions = deduplicateByName(allFunctions);
1472
- const uniqueTypes = deduplicateByName(allTypes);
1473
- const uniqueConstants = deduplicateByName(allConstants);
1474
- const sortedFunctions = sortByRelevance(uniqueFunctions, publicApiNames);
1475
- const sortedTypes = sortByRelevance(uniqueTypes, publicApiNames);
1476
- const truncatedFunctions = uniqueFunctions.length > limit;
1477
- const truncatedTypes = uniqueTypes.length > limit;
1478
- return {
1479
- functions: sortedFunctions.slice(0, limit),
1480
- types: sortedTypes.slice(0, limit),
1481
- constants: uniqueConstants.slice(0, limit),
1482
- truncated: {
1483
- functions: truncatedFunctions,
1484
- types: truncatedTypes,
1485
- totalFunctions: uniqueFunctions.length,
1486
- totalTypes: uniqueTypes.length,
1487
- shown: limit
1488
- }
1489
- };
1490
- }
1491
- function extractConstants(sourceFile, includeAll = false) {
1492
- const constants = [];
1493
- for (const varStatement of sourceFile.getVariableStatements()) {
1494
- if (!varStatement.isExported() && !includeAll) continue;
1495
- for (const decl of varStatement.getDeclarations()) {
1496
- const init = decl.getInitializer();
1497
- if (init) {
1498
- const kind = init.getKind();
1499
- if (kind === 210 || kind === 208) continue;
1500
- }
1501
- const declType = decl.getType();
1502
- if (declType.getCallSignatures().length > 0) continue;
1503
- const name = decl.getName();
1504
- const type = expandMuiOverrideType(declType, simplifyType(declType.getText()));
1505
- constants.push({
1506
- name,
1507
- type,
1508
- isExported: true
1509
- });
1510
- }
1511
- }
1512
- return constants;
1513
- }
1514
- function isLikelyMinified(name) {
1515
- return name.length === 1;
1516
- }
1517
- function deduplicateByName(items) {
1518
- const seen = /* @__PURE__ */ new Map();
1519
- for (const item of items) {
1520
- const existing = seen.get(item.name);
1521
- if (!existing) {
1522
- seen.set(item.name, item);
1523
- } else if (symbolInfoScore(item) > symbolInfoScore(existing)) {
1524
- seen.set(item.name, item);
1525
- }
1526
- }
1527
- return [...seen.values()];
1528
- }
1529
- function symbolInfoScore(item) {
1530
- const record = item;
1531
- let score = 0;
1532
- if (typeof record.jsdoc === "string" && record.jsdoc.length > 0) score += 10;
1533
- if (Array.isArray(record.jsdocParams) && record.jsdocParams.length > 0) score += 5;
1534
- if (Array.isArray(record.params) && record.params.length > 0) score += 3;
1535
- if (typeof record.definition === "string" && record.definition.length > 10) score += 2;
1536
- return score;
1537
- }
1538
- function sortByRelevance(items, publicApiNames) {
1539
- return [...items].sort((a, b) => {
1540
- const aPublic = publicApiNames.has(a.name) ? 0 : 1;
1541
- const bPublic = publicApiNames.has(b.name) ? 0 : 1;
1542
- if (aPublic !== bPublic) return aPublic - bPublic;
1543
- const recordA = a;
1544
- const recordB = b;
1545
- const aJSDoc = typeof recordA.jsdoc === "string" && recordA.jsdoc.length > 0 ? 0 : 1;
1546
- const bJSDoc = typeof recordB.jsdoc === "string" && recordB.jsdoc.length > 0 ? 0 : 1;
1547
- if (aJSDoc !== bJSDoc) return aJSDoc - bJSDoc;
1548
- if (a.name.length !== b.name.length) return a.name.length - b.name.length;
1549
- return a.name.localeCompare(b.name);
1550
- });
1551
- }
1552
-
1553
- // src/ts/symbol-aliases.ts
1554
- var ZUSTAND_ALIASES = {
1555
- package: "zustand",
1556
- aliases: {
1557
- middleware: ["StateCreator", "persist", "combine", "devtools", "subscribeWithSelector", "Immer", "devtools"],
1558
- store: ["create", "useStore", "createStore"],
1559
- state: ["State", "PartialState", "SetState", "GetState", "StoreState"],
1560
- subscribe: ["subscribe", "subscribeWithSelector"],
1561
- immer: ["Immer", "createWithImmer"],
1562
- devtools: ["devtools", "redux"],
1563
- persist: ["persist", "createPersist", "PersistStorage"]
1564
- }
1565
- };
1566
- var MUI_ALIASES = {
1567
- package: "@mui/material",
1568
- aliases: {
1569
- styled: ["styled", "sx", "SxProps", "Theme"],
1570
- theme: ["Theme", "ThemeOptions", "createTheme", "useTheme", "ThemeProvider"],
1571
- props: ["Props", "PropsWithRef", "SxProps", "HTMLProps", "ComponentProps"],
1572
- slot: ["Slot", "Slots", "SlotProps"],
1573
- component: ["ComponentType", "ElementType", "FC", "ForwardRefExoticComponent"]
1574
- }
1575
- };
1576
- var REACT_ALIASES = {
1577
- package: "react",
1578
- aliases: {
1579
- hook: ["useState", "useEffect", "useContext", "useReducer", "useCallback", "useMemo", "useRef", "useImperativeHandle", "useLayoutEffect", "useDebugValue", "useId", "useTransition", "useDeferredValue", "useSyncExternalStore", "useInsertionEffect", "useFormStatus", "useActionState", "useOptimistic", "use"],
1580
- component: ["Component", "PureComponent", "FC", "FunctionComponent", "forwardRef", "lazy", "memo", "createContext", "createElement", "cloneElement"],
1581
- context: ["createContext", "useContext"],
1582
- element: ["createElement", "cloneElement", "isValidElement"]
1583
- }
1584
- };
1585
- var FIREBASE_ALIASES = {
1586
- package: "firebase",
1587
- aliases: {
1588
- auth: ["getAuth", "signInWithPopup", "signInWithEmailAndPassword", "createUserWithEmailAndPassword", "signOut", "onAuthStateChanged"],
1589
- firestore: ["getFirestore", "collection", "doc", "getDoc", "getDocs", "setDoc", "addDoc", "updateDoc", "deleteDoc", "onSnapshot", "query", "where", "orderBy"],
1590
- storage: ["getStorage", "ref", "uploadBytes", "uploadString", "getDownloadURL", "deleteObject"],
1591
- messaging: ["getMessaging", "getToken", "onMessage"]
1592
- }
1593
- };
1594
- var ALIAS_REGISTRY = [
1595
- ZUSTAND_ALIASES,
1596
- MUI_ALIASES,
1597
- REACT_ALIASES,
1598
- FIREBASE_ALIASES
1599
- ];
1600
- function getAliasesForPackage(packageName) {
1601
- return ALIAS_REGISTRY.find((a) => a.package === packageName);
1602
- }
1603
- function resolveConceptualQuery(query, packageName, extracted) {
1604
- const aliases = getAliasesForPackage(packageName);
1605
- if (!aliases) return [];
1606
- const aliasList = aliases.aliases[query.toLowerCase()];
1607
- if (!aliasList) return [];
1608
- const results = [];
1609
- for (const fn of extracted.functions) {
1610
- if (aliasList.includes(fn.name)) {
1611
- results.push({ name: fn.name, kind: "function", file: fn.sourceFile ?? "" });
1612
- }
1613
- }
1614
- for (const t of extracted.types) {
1615
- if (aliasList.includes(t.name)) {
1616
- results.push({ name: t.name, kind: t.kind, file: t.sourceFile ?? "" });
1617
- }
1618
- }
1619
- return results;
1620
- }
1621
- function isConceptualQuery(query, packageName) {
1622
- const aliases = getAliasesForPackage(packageName);
1623
- if (!aliases) return false;
1624
- return query.toLowerCase() in aliases.aliases;
1625
- }
1626
-
1627
- // src/commands/deps.ts
1628
- function normalizeKind(kind) {
1629
- if (kind === "interface" || kind === "enum") return "type";
1630
- return kind;
1631
- }
1632
- function normalizePath(p) {
1633
- return p.replace(/\\/g, "/");
1634
- }
1635
- function computeAvailableKinds(extracted, requestedKind) {
1636
- const kindCounts = /* @__PURE__ */ new Map();
1637
- for (const fn of extracted.functions) {
1638
- const kind = normalizeKind(classifySymbol("function", fn.name, fn.returnType));
1639
- if (isSemanticKindMatch(kind, requestedKind)) {
1640
- kindCounts.set(kind, (kindCounts.get(kind) ?? 0) + 1);
1641
- }
1642
- }
1643
- for (const t of extracted.types) {
1644
- const kind = normalizeKind(classifySymbol("type", t.name));
1645
- if (isSemanticKindMatch(kind, requestedKind)) {
1646
- kindCounts.set(kind, (kindCounts.get(kind) ?? 0) + 1);
1647
- }
1648
- }
1649
- for (const c of extracted.constants) {
1650
- const kind = normalizeKind(classifySymbol("const", c.name));
1651
- if (isSemanticKindMatch(kind, requestedKind)) {
1652
- kindCounts.set(kind, (kindCounts.get(kind) ?? 0) + 1);
1653
- }
1654
- }
1655
- return Array.from(kindCounts.entries()).map(([kind, count]) => ({ kind, count })).sort((a, b) => b.count - a.count);
1656
- }
1657
- function relativeTypeFile(typeFiles, normalizedPkgPath, packageName, sourceFile) {
1658
- if (sourceFile) {
1659
- return `${packageName}/${sourceFile}`;
1660
- }
1661
- if (typeFiles.length === 0) {
1662
- return packageName;
1663
- }
1664
- return normalizePath(typeFiles[0]).replace(normalizedPkgPath, packageName);
1665
- }
1666
- var TYPE_FILES_COMPACT_THRESHOLD = 10;
1667
- var TYPE_FILES_PREVIEW_COUNT = 5;
1668
- function buildTypeFilesMeta(typeFiles, pkgPath) {
1669
- if (typeFiles.length <= TYPE_FILES_COMPACT_THRESHOLD) {
1670
- return {};
1671
- }
1672
- const normalizedPkgPath = normalizePath(pkgPath.endsWith("/") ? pkgPath : pkgPath + "/");
1673
- const subdirs = /* @__PURE__ */ new Set();
1674
- for (const tf of typeFiles) {
1675
- const normalized = normalizePath(tf);
1676
- const relative = normalized.replace(normalizedPkgPath, "").replace(/^\//, "");
1677
- const firstSegment = relative.split("/")[0];
1678
- if (firstSegment) {
1679
- subdirs.add(firstSegment);
1680
- }
1681
- }
1682
- const subdirCount = subdirs.size;
1683
- const summary = `${typeFiles.length} type files em ${subdirCount} subdiret\xF3rio${subdirCount === 1 ? "" : "s"}`;
1684
- const preview = typeFiles.slice(0, TYPE_FILES_PREVIEW_COUNT).map((tf) => {
1685
- const normalized = normalizePath(tf);
1686
- return normalized.replace(normalizedPkgPath, "").replace(/^\//, "") || tf;
1687
- });
1688
- return { summary, preview };
1689
- }
1690
- async function depsInfo(packageName, options = {}) {
1691
- const { cwd, format } = parseCommandOptions(options);
1692
- const ctx = options.ctx || "cli";
1693
- if (!packageName) {
1694
- throw new Error("Nome do pacote e obrigatorio. Exemplo: ai-tool deps info @mui/material");
1695
- }
1696
- try {
1697
- const result = readPackageJson(packageName, cwd);
1698
- if (result.version === "0.0.0" && !packageName.startsWith("@") && packageName.includes("/")) {
1699
- const basePkg = packageName.slice(0, packageName.indexOf("/"));
1700
- try {
1701
- const baseResult = readPackageJson(basePkg, cwd);
1702
- result.version = baseResult.version;
1703
- result.info.version = baseResult.version;
1704
- } catch {
1705
- }
1706
- }
1707
- const projectPkgPath = join3(cwd, "package.json");
1708
- if (existsSync3(projectPkgPath)) {
1709
- try {
1710
- const projectRaw = readFileSync3(projectPkgPath, "utf-8");
1711
- const projectPkg = JSON.parse(projectRaw);
1712
- const deps = projectPkg.dependencies ?? {};
1713
- const devDeps = projectPkg.devDependencies ?? {};
1714
- const declared = deps[packageName] ?? devDeps[packageName];
1715
- if (declared) {
1716
- result.declaredVersion = declared;
1717
- }
1718
- } catch {
1719
- }
1720
- }
1721
- if (!result.info.types && !result.info.typings) {
1722
- try {
1723
- resolvePackagePath(`@types/${packageName}`, cwd);
1724
- result.info.hasTypes = true;
1725
- result.info.typesSource = "@types";
1726
- result.info.typesPackage = `@types/${packageName}`;
1727
- } catch {
1728
- }
1729
- }
1730
- return formatOutput(result, format, (r) => formatDepsInfoText(r, ctx));
1731
- } catch (error) {
1732
- const message = error instanceof Error ? error.message : String(error);
1733
- if (format === "json") {
1734
- return JSON.stringify({ error: message, package: packageName });
1735
- }
1736
- const lines = [
1737
- `Erro ao executar deps info: ${message}`,
1738
- "",
1739
- recoveryHint("package_not_found", ctx)
1740
- ];
1741
- return lines.join("\n");
1742
- }
1743
- }
1744
- async function depsApi(packageName, options = {}) {
1745
- const { cwd, format } = parseCommandOptions(options);
1746
- const ctx = options.ctx || "cli";
1747
- if (!packageName) {
1748
- throw new Error("Nome do pacote e obrigatorio. Exemplo: ai-tool deps api zustand");
1749
- }
1750
- try {
1751
- const pkgPath = resolvePackagePath(packageName, cwd);
1752
- let typeFiles;
1753
- let typesSource;
1754
- let typesPackage;
1755
- if (options.entry) {
1756
- const entryFile = resolveEntryPointFile(packageName, options.entry, cwd);
1757
- typeFiles = [entryFile];
1758
- typesSource = "builtin";
1759
- } else {
1760
- const resolved = resolveTypeFilesWithSource(packageName, cwd);
1761
- typeFiles = resolved.files;
1762
- typesSource = resolved.source;
1763
- typesPackage = resolved.typesPackage;
1764
- }
1765
- const effectiveLimit = options.kind ? Math.max((options.limit ?? 50) * 5, 200) : options.limit ?? 50;
1766
- const extracted = extractPackageApi(typeFiles, pkgPath, { limit: effectiveLimit });
1767
- let filteredFunctions = extracted.functions;
1768
- let filteredTypes = extracted.types;
1769
- let filteredConstants = extracted.constants;
1770
- if (options.kind) {
1771
- const kind = options.kind;
1772
- filteredFunctions = extracted.functions.filter((fn) => classifySymbol("function", fn.name, fn.returnType) === kind);
1773
- filteredTypes = extracted.types.filter((t) => {
1774
- const resolvedKind = classifySymbol("type", t.name) === "hook" ? "hook" : t.kind;
1775
- return resolvedKind === kind;
1776
- });
1777
- filteredConstants = extracted.constants.filter(() => kind === "const");
1778
- const realLimit = options.limit ?? 50;
1779
- const realOffset = options.offset ?? 0;
1780
- filteredFunctions = filteredFunctions.slice(realOffset, realOffset + realLimit);
1781
- filteredTypes = filteredTypes.slice(realOffset, realOffset + realLimit);
1782
- filteredConstants = filteredConstants.slice(realOffset, realOffset + realLimit);
1783
- } else {
1784
- const realOffset = options.offset ?? 0;
1785
- const realLimit = options.limit ?? 50;
1786
- filteredFunctions = filteredFunctions.slice(realOffset, realOffset + realLimit);
1787
- filteredTypes = filteredTypes.slice(realOffset, realOffset + realLimit);
1788
- filteredConstants = filteredConstants.slice(realOffset, realOffset + realLimit);
1789
- }
1790
- const availableKindsWhenFilteredEmpty = options.kind && filteredFunctions.length === 0 && filteredTypes.length === 0 ? computeAvailableKinds(extracted, options.kind) : void 0;
1791
- const jsFallback = typeFiles.length > 0 && typeFiles.every(
1792
- (f) => f.endsWith(".js") || f.endsWith(".mjs") || f.endsWith(".cjs")
1793
- );
1794
- const pkgVersion = readPackageJson(packageName, cwd).version;
1795
- const typeFilesMeta = buildTypeFilesMeta(typeFiles, pkgPath);
1796
- const byKind = options.kind ? computeAvailableKinds(extracted, options.kind) : void 0;
1797
- const result = {
1798
- version: pkgVersion,
1799
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1800
- package: packageName,
1801
- resolvedPath: pkgPath,
1802
- typeFiles,
1803
- functions: filteredFunctions,
1804
- types: filteredTypes,
1805
- constants: filteredConstants.length > 0 ? filteredConstants : void 0,
1806
- truncated: options.kind ? {
1807
- functions: filteredFunctions.length >= (options.limit ?? 50),
1808
- types: filteredTypes.length >= (options.limit ?? 50),
1809
- totalFunctions: filteredFunctions.length,
1810
- totalTypes: filteredTypes.length,
1811
- shown: Math.min(filteredFunctions.length, options.limit ?? 50),
1812
- functionsOffset: options.offset,
1813
- typesOffset: options.offset,
1814
- byKind
1815
- } : {
1816
- ...extracted.truncated,
1817
- functionsOffset: options.offset,
1818
- typesOffset: options.offset
1819
- },
1820
- availableKindsWhenFilteredEmpty,
1821
- typeFilesSummary: typeFilesMeta.summary,
1822
- typeFilesPreview: typeFilesMeta.preview,
1823
- jsFallback: jsFallback || void 0,
1824
- typesSource,
1825
- typesPackage
1826
- };
1827
- return formatOutput(result, format, (r) => formatDepsApiText(r, ctx));
1828
- } catch (error) {
1829
- const message = error instanceof Error ? error.message : String(error);
1830
- if (message.includes("nao possui TypeScript declarations")) {
1831
- if (format === "json") {
1832
- return JSON.stringify({ error: message, package: packageName });
1833
- }
1834
- const lines = [
1835
- `${packageName} - Sem TypeScript declarations`,
1836
- ``,
1837
- `Este pacote nao possui tipos TypeScript embutidos.`,
1838
- ``,
1839
- `Opcoes:`,
1840
- ` 1. Instale os tipos separados: <package_manager> install -D @types/${packageName}`,
1841
- ` 2. ${hint("deps_info", ctx, { "<pacote>": packageName })} - ver metadados do pacote`
1842
- ];
1843
- return lines.join("\n");
1844
- }
1845
- throw new Error(`Erro ao executar deps api: ${message}`);
1846
- }
1847
- }
1848
- var DEFAULT_SEARCH_LIMIT = 15;
1849
- var MAX_SEARCH_LIMIT = 200;
1850
- var AUXILIARY_TYPE_SUFFIXES = [
1851
- "Props",
1852
- "PropsWithRef",
1853
- "Overrides",
1854
- "ClassKey",
1855
- "DefaultComponent",
1856
- "TypeMap",
1857
- "Options",
1858
- "Config",
1859
- "Settings",
1860
- "Fn",
1861
- "Token",
1862
- "Locale",
1863
- "Width",
1864
- "Part"
1865
- ];
1866
- function hasWildcard(query) {
1867
- return query.includes("*");
1868
- }
1869
- function matchWithWildcard(name, query) {
1870
- if (!query.includes("*")) {
1871
- return name.toLowerCase() === query.toLowerCase();
1872
- }
1873
- const q = query.toLowerCase();
1874
- const n = name.toLowerCase();
1875
- if (q.startsWith("*") && q.endsWith("*") && q.length >= 2) {
1876
- const inner = q.slice(1, -1);
1877
- return inner.length > 0 && n.includes(inner);
1878
- }
1879
- if (q.endsWith("*") && !q.startsWith("*")) {
1880
- const prefix = q.slice(0, -1);
1881
- return prefix.length > 0 && n.startsWith(prefix);
1882
- }
1883
- if (q.startsWith("*") && !q.endsWith("*")) {
1884
- const suffix = q.slice(1);
1885
- return suffix.length > 0 && n.endsWith(suffix);
1886
- }
1887
- return n.includes(q.replace(/\*/g, ""));
1888
- }
1889
- function calculateWildcardMatchScore(name, query, kind, isExported) {
1890
- let score = 0;
1891
- const n = name.toLowerCase();
1892
- const q = query.toLowerCase();
1893
- if (q.endsWith("*") && !q.startsWith("*")) {
1894
- const prefix = q.slice(0, -1);
1895
- if (n === prefix) {
1896
- score += 100;
1897
- } else if (n.startsWith(prefix)) {
1898
- score += 80;
1899
- }
1900
- } else if (q.startsWith("*") && !q.endsWith("*")) {
1901
- const suffix = q.slice(1);
1902
- if (n === suffix) {
1903
- score += 100;
1904
- } else if (n.endsWith(suffix)) {
1905
- score += 80;
1906
- }
1907
- } else if (q.startsWith("*") && q.endsWith("*") && q.length >= 2) {
1908
- const inner = q.slice(1, -1);
1909
- if (n === inner) {
1910
- score += 100;
1911
- } else if (n.includes(inner)) {
1912
- score += 50;
1913
- }
1914
- } else {
1915
- if (n.includes(q.replace(/\*/g, ""))) {
1916
- score += 50;
1917
- }
1918
- }
1919
- if (kind === "function" || kind === "component" || kind === "hook") {
1920
- score += 15;
1921
- }
1922
- if (isExported) {
1923
- score += 10;
1924
- }
1925
- for (const suffix of AUXILIARY_TYPE_SUFFIXES) {
1926
- if (name.endsWith(suffix)) {
1927
- score -= 20;
1928
- break;
1929
- }
1930
- }
1931
- return score;
1932
- }
1933
- function calculateMatchScore(name, queryLower, kind, isExported) {
1934
- const nameLower = name.toLowerCase();
1935
- let score = 0;
1936
- if (nameLower === queryLower) {
1937
- score += 100;
1938
- } else if (nameLower.startsWith(queryLower)) {
1939
- score += 80;
1940
- } else {
1941
- score += 50;
1942
- }
1943
- if (nameLower.length <= queryLower.length + 5) {
1944
- score += 10;
1945
- }
1946
- if (kind === "function" || kind === "component" || kind === "hook") {
1947
- score += 15;
1948
- }
1949
- if (isExported) {
1950
- score += 10;
1951
- }
1952
- for (const suffix of AUXILIARY_TYPE_SUFFIXES) {
1953
- if (name.endsWith(suffix)) {
1954
- score -= 20;
1955
- break;
1956
- }
1957
- }
1958
- return score;
1959
- }
1960
- async function depsSearch(packageName, query, options = {}) {
1961
- const { cwd, format } = parseCommandOptions(options);
1962
- const ctx = options.ctx || "cli";
1963
- if (!packageName) {
1964
- throw new Error(
1965
- "Nome do pacote e obrigatorio. Exemplo: ai-tool deps search @mui/material Button"
1966
- );
1967
- }
1968
- if (!query) {
1969
- throw new Error(
1970
- "Termo de busca e obrigatorio. Exemplo: ai-tool deps search zustand create"
1971
- );
1972
- }
1973
- try {
1974
- const pkgPath = resolvePackagePath(packageName, cwd);
1975
- const resolved = resolveTypeFilesWithSource(packageName, cwd);
1976
- const typeFiles = resolved.files;
1977
- const extracted = extractPackageApi(typeFiles, pkgPath, { limit: 200 });
1978
- const jsFallback = typeFiles.length > 0 && typeFiles.every(
1979
- (f) => f.endsWith(".js") || f.endsWith(".mjs") || f.endsWith(".cjs")
1980
- );
1981
- const queryLower = query.toLowerCase();
1982
- const scored = [];
1983
- const filesSet = /* @__PURE__ */ new Set();
1984
- const normalizedPkgPath = normalizePath(pkgPath);
1985
- const useWildcard = hasWildcard(query);
1986
- const matchFn = useWildcard ? (name) => matchWithWildcard(name, query) || matchWithWildcard(stripModulePrefix(name), query) : (name) => {
1987
- const n = name.toLowerCase();
1988
- const s = stripModulePrefix(name).toLowerCase();
1989
- return n === queryLower || s === queryLower;
1990
- };
1991
- const scoreFn = useWildcard ? (name, kind, isExported) => calculateWildcardMatchScore(name, query, kind, isExported) : (name, kind, isExported) => calculateMatchScore(name, queryLower, kind, isExported);
1992
- const fuzzyMatchFn = (name) => {
1993
- const n = name.toLowerCase();
1994
- const s = stripModulePrefix(name).toLowerCase();
1995
- return (n.includes(queryLower) || s.includes(queryLower)) && n !== queryLower && s !== queryLower;
1996
- };
1997
- for (const fn of extracted.functions) {
1998
- if (matchFn(fn.name)) {
1999
- const kind = classifySymbol("function", fn.name, fn.returnType, packageName);
2000
- const score = scoreFn(fn.name, kind, fn.isExported);
2001
- const params = fn.params.map((p) => `${p.name}: ${p.type}`).join(", ");
2002
- const signature = `${fn.name}(${params}): ${fn.returnType}`;
2003
- const file = relativeTypeFile(typeFiles, normalizedPkgPath, packageName, fn.sourceFile);
2004
- scored.push({ name: fn.name, kind, file, signature, _score: score });
2005
- filesSet.add(file);
2006
- }
2007
- }
2008
- for (const t of extracted.types) {
2009
- if (matchFn(t.name)) {
2010
- const kind = classifySymbol("type", t.name, void 0, packageName) === "hook" ? "hook" : t.kind;
2011
- const score = scoreFn(t.name, kind, t.isExported);
2012
- const file = relativeTypeFile(typeFiles, normalizedPkgPath, packageName, t.sourceFile);
2013
- scored.push({ name: t.name, kind, file, signature: t.definition, _score: score });
2014
- filesSet.add(file);
2015
- }
2016
- }
2017
- for (const c of extracted.constants) {
2018
- if (matchFn(c.name)) {
2019
- const score = scoreFn(c.name, "const", c.isExported);
2020
- const file = relativeTypeFile(typeFiles, normalizedPkgPath, packageName, c.sourceFile);
2021
- scored.push({ name: c.name, kind: "const", file, signature: c.type, _score: score });
2022
- filesSet.add(file);
2023
- }
2024
- }
2025
- if (!useWildcard && scored.length > 0) {
2026
- const exactKinds = new Set(scored.map((m) => m.kind));
2027
- const matchedNames = new Set(scored.map((m) => m.name));
2028
- for (const fn of extracted.functions) {
2029
- if (matchedNames.has(fn.name)) continue;
2030
- const kind = classifySymbol("function", fn.name, fn.returnType, packageName);
2031
- if (exactKinds.has(kind)) continue;
2032
- if (!fuzzyMatchFn(fn.name)) continue;
2033
- const score = scoreFn(fn.name, kind, fn.isExported);
2034
- if (score < 90) continue;
2035
- const params = fn.params.map((p) => `${p.name}: ${p.type}`).join(", ");
2036
- const signature = `${fn.name}(${params}): ${fn.returnType}`;
2037
- const file = relativeTypeFile(typeFiles, normalizedPkgPath, packageName, fn.sourceFile);
2038
- scored.push({ name: fn.name, kind, file, signature, _score: score });
2039
- filesSet.add(file);
2040
- matchedNames.add(fn.name);
2041
- }
2042
- for (const t of extracted.types) {
2043
- if (matchedNames.has(t.name)) continue;
2044
- const kind = classifySymbol("type", t.name, void 0, packageName) === "hook" ? "hook" : t.kind;
2045
- if (exactKinds.has(kind)) continue;
2046
- if (!fuzzyMatchFn(t.name)) continue;
2047
- const score = scoreFn(t.name, kind, t.isExported);
2048
- if (score < 90) continue;
2049
- const file = relativeTypeFile(typeFiles, normalizedPkgPath, packageName, t.sourceFile);
2050
- scored.push({ name: t.name, kind, file, signature: t.definition, _score: score });
2051
- filesSet.add(file);
2052
- matchedNames.add(t.name);
2053
- }
2054
- for (const c of extracted.constants) {
2055
- if (matchedNames.has(c.name)) continue;
2056
- if (exactKinds.has("const")) continue;
2057
- if (!fuzzyMatchFn(c.name)) continue;
2058
- const score = scoreFn(c.name, "const", c.isExported);
2059
- if (score < 90) continue;
2060
- const file = relativeTypeFile(typeFiles, normalizedPkgPath, packageName, c.sourceFile);
2061
- scored.push({ name: c.name, kind: "const", file, signature: c.type, _score: score });
2062
- filesSet.add(file);
2063
- matchedNames.add(c.name);
2064
- }
2065
- }
2066
- scored.sort((a, b) => b._score - a._score);
2067
- const effectiveOffset = options.offset ?? 0;
2068
- const effectiveLimit = Math.min(options.limit ?? DEFAULT_SEARCH_LIMIT, MAX_SEARCH_LIMIT);
2069
- const kindCountMap = /* @__PURE__ */ new Map();
2070
- for (const m of scored) {
2071
- const key = m.kind;
2072
- const existing = kindCountMap.get(key);
2073
- if (existing) {
2074
- existing.total++;
2075
- } else {
2076
- kindCountMap.set(key, { total: 1, shown: 0 });
2077
- }
2078
- }
2079
- const fileCountMap = /* @__PURE__ */ new Map();
2080
- for (const m of scored) {
2081
- fileCountMap.set(m.file, (fileCountMap.get(m.file) ?? 0) + 1);
2082
- }
2083
- const filtered = options.kind ? scored.filter((m) => isSemanticKindMatch(m.kind, options.kind)) : scored;
2084
- const pageMatches = filtered.slice(effectiveOffset, effectiveOffset + effectiveLimit);
2085
- for (const m of pageMatches) {
2086
- const k = kindCountMap.get(m.kind);
2087
- if (k) k.shown++;
2088
- }
2089
- const byKind = [];
2090
- for (const [kind, counts] of kindCountMap.entries()) {
2091
- byKind.push({ kind, total: counts.total, shown: counts.shown });
2092
- }
2093
- byKind.sort((a, b) => b.total - a.total);
2094
- const byFile = Array.from(fileCountMap.entries()).map(([file, count]) => ({ file, count })).sort((a, b) => b.count - a.count).slice(0, 10);
2095
- const availableKindsWhenEmpty = options.kind && filtered.length === 0 && scored.length > 0 ? [...new Set(scored.map((m) => m.kind))] : void 0;
2096
- const allMatches = pageMatches.map(({ _score: _, ...match }) => match);
2097
- if (allMatches.length > 0 && allMatches.length < 3 && !useWildcard) {
2098
- const isConcept = isConceptualQuery(query, packageName);
2099
- if (!isConcept) {
2100
- const aliasResults = resolveConceptualQuery(query, packageName, {
2101
- functions: extracted.functions,
2102
- types: extracted.types
2103
- });
2104
- for (const r of aliasResults) {
2105
- if (!allMatches.some((m) => m.name === r.name)) {
2106
- const fn = extracted.functions.find((f) => f.name === r.name);
2107
- const t = extracted.types.find((t2) => t2.name === r.name);
2108
- const signature = fn ? `${fn.name}(${fn.params.map((p) => `${p.name}: ${p.type}`).join(", ")}): ${fn.returnType}` : t?.definition ?? r.name;
2109
- allMatches.push({ name: r.name, kind: r.kind, file: r.file, signature, fromConcept: query });
2110
- }
2111
- }
2112
- }
2113
- }
2114
- if (allMatches.length > 0 && allMatches.length < 3) {
2115
- const subPaths = getSubExportPaths(packageName, cwd);
2116
- for (const subPath of subPaths) {
2117
- try {
2118
- const subEntryFile = resolveEntryPointFile(packageName, subPath, cwd);
2119
- const subExtracted = extractPackageApi([subEntryFile], pkgPath, { limit: 200 });
2120
- const subMatchFn = useWildcard ? (name) => matchWithWildcard(name, query) || matchWithWildcard(stripModulePrefix(name), query) : (name) => {
2121
- const n = name.toLowerCase();
2122
- const s = stripModulePrefix(name).toLowerCase();
2123
- return n === queryLower || s === queryLower;
2124
- };
2125
- for (const fn of subExtracted.functions) {
2126
- if (subMatchFn(fn.name) && !allMatches.some((m) => m.name === fn.name)) {
2127
- const kind = classifySymbol("function", fn.name, fn.returnType, packageName);
2128
- const params = fn.params.map((p) => `${p.name}: ${p.type}`).join(", ");
2129
- const signature = `${fn.name}(${params}): ${fn.returnType}`;
2130
- const file = relativeTypeFile([subEntryFile], normalizePath(subEntryFile), `${packageName}/${subPath}`, fn.sourceFile);
2131
- allMatches.push({ name: fn.name, kind, file, signature });
2132
- }
2133
- }
2134
- for (const t of subExtracted.types) {
2135
- if (subMatchFn(t.name) && !allMatches.some((m) => m.name === t.name)) {
2136
- const kind = classifySymbol("type", t.name, void 0, packageName) === "hook" ? "hook" : t.kind;
2137
- const file = relativeTypeFile([subEntryFile], normalizePath(subEntryFile), `${packageName}/${subPath}`, t.sourceFile);
2138
- allMatches.push({ name: t.name, kind, file, signature: t.definition });
2139
- }
2140
- }
2141
- } catch {
2142
- }
2143
- if (allMatches.length >= 10) break;
2144
- }
2145
- }
2146
- const pkgVersion = readPackageJson(packageName, cwd).version;
2147
- const result = {
2148
- version: pkgVersion,
2149
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2150
- package: packageName,
2151
- query,
2152
- matches: allMatches,
2153
- summary: {
2154
- total: scored.length,
2155
- files: filesSet.size,
2156
- shown: allMatches.length,
2157
- hidden: Math.max(0, filtered.length - effectiveOffset - effectiveLimit),
2158
- byKind: byKind.length > 1 ? byKind : void 0,
2159
- byFile: byFile.length > 1 ? byFile : void 0
2160
- },
2161
- availableKindsWhenEmpty,
2162
- jsFallback: jsFallback || void 0,
2163
- typesSource: resolved.source,
2164
- typesPackage: resolved.typesPackage
2165
- };
2166
- return formatOutput(result, format, (r) => formatDepsSearchText(r, ctx));
2167
- } catch (error) {
2168
- const message = error instanceof Error ? error.message : String(error);
2169
- if (message.includes("nao encontrado") || message.includes("not found") || message.includes("Cannot find")) {
2170
- if (format === "json") {
2171
- return JSON.stringify({ error: message, package: packageName, query });
2172
- }
2173
- const lines = [
2174
- `Erro ao executar deps search: ${message}`,
2175
- "",
2176
- recoveryHint("package_not_found", ctx)
2177
- ];
2178
- return lines.join("\n");
2179
- }
2180
- throw new Error(`Erro ao executar deps search: ${message}`);
2181
- }
2182
- }
2183
-
2184
- export {
2185
- describe,
2186
- depsInfo,
2187
- depsApi,
2188
- depsSearch
2189
- };