@justmpm/ai-tool 0.3.2 → 0.4.2
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/README.md +56 -1
- package/dist/{chunk-EONUMGCN.js → chunk-WN7FTU6M.js} +1281 -10
- package/dist/cli.js +42 -8
- package/dist/index.d.ts +203 -2
- package/dist/index.js +39 -3
- package/dist/{server-K55EXKYX.js → server-SPVMWDEO.js} +246 -1
- package/package.json +2 -1
|
@@ -5,8 +5,8 @@ import skott from "skott";
|
|
|
5
5
|
function detectCategory(filePath) {
|
|
6
6
|
const normalized = filePath.replace(/\\/g, "/").toLowerCase();
|
|
7
7
|
const fileName = normalized.split("/").pop() || "";
|
|
8
|
-
const fileNameNoExt = fileName.replace(/\.(tsx?|jsx?|mjs|cjs)$/, "");
|
|
9
|
-
if (fileName.includes(".test.") || fileName.includes(".spec.") || normalized.includes("/__tests__/") || normalized.includes("/test/")) {
|
|
8
|
+
const fileNameNoExt = fileName.replace(/\.(tsx?|jsx?|mjs|cjs|vue|svelte|astro)$/, "");
|
|
9
|
+
if (fileName.includes(".test.") || fileName.includes(".spec.") || normalized.includes("/__tests__/") || normalized.includes("/test/") || normalized.includes("/tests/")) {
|
|
10
10
|
return "test";
|
|
11
11
|
}
|
|
12
12
|
if (isConfigFile(fileName)) {
|
|
@@ -20,23 +20,55 @@ function detectCategory(filePath) {
|
|
|
20
20
|
)) {
|
|
21
21
|
return "page";
|
|
22
22
|
}
|
|
23
|
-
if (normalized.includes("/
|
|
24
|
-
|
|
23
|
+
if (normalized.includes("/pages/") && !normalized.includes("/pages/api/")) {
|
|
24
|
+
return "page";
|
|
25
|
+
}
|
|
26
|
+
if (normalized.includes("/pages/") || normalized.includes("/views/") || normalized.includes("/screens/")) {
|
|
27
|
+
if (!normalized.includes("/components/")) {
|
|
28
|
+
return "page";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (fileNameNoExt.endsWith("page") || fileNameNoExt.endsWith("view") || fileNameNoExt.endsWith("screen")) {
|
|
32
|
+
return "page";
|
|
33
|
+
}
|
|
34
|
+
if (normalized.includes("/routes/") && normalized.includes("/app/")) {
|
|
35
|
+
return "page";
|
|
36
|
+
}
|
|
37
|
+
if (normalized.includes("/layouts/")) {
|
|
38
|
+
return "layout";
|
|
39
|
+
}
|
|
40
|
+
if (fileNameNoExt === "+page" || fileNameNoExt === "+page.server") return "page";
|
|
41
|
+
if (fileNameNoExt === "+layout" || fileNameNoExt === "+layout.server") return "layout";
|
|
42
|
+
if (fileNameNoExt === "+server") return "route";
|
|
43
|
+
if (fileNameNoExt === "+error") return "page";
|
|
44
|
+
if (fileName.endsWith(".astro") && normalized.includes("/pages/")) {
|
|
45
|
+
return "page";
|
|
46
|
+
}
|
|
47
|
+
if (fileName.endsWith(".astro") && normalized.includes("/layouts/")) {
|
|
48
|
+
return "layout";
|
|
49
|
+
}
|
|
50
|
+
if (normalized.includes("/api/") || normalized.includes("/server/") || fileNameNoExt.endsWith(".server") || fileNameNoExt === "+server") {
|
|
51
|
+
return "route";
|
|
52
|
+
}
|
|
25
53
|
if (fileNameNoExt.startsWith("use") && fileNameNoExt.length > 3) return "hook";
|
|
26
54
|
if (normalized.includes("/hooks/")) return "hook";
|
|
27
|
-
if (normalized.includes("/
|
|
55
|
+
if (normalized.includes("/composables/")) return "hook";
|
|
56
|
+
if (normalized.includes("/stores/") && fileName.endsWith(".ts")) return "hook";
|
|
57
|
+
if (normalized.includes("/types/") || normalized.includes("/interfaces/") || fileName.endsWith(".d.ts") || fileNameNoExt === "types" || fileNameNoExt === "interfaces") {
|
|
28
58
|
return "type";
|
|
29
59
|
}
|
|
30
|
-
if (normalized.includes("/services/") || fileNameNoExt.endsWith("service")) {
|
|
60
|
+
if (normalized.includes("/services/") || normalized.includes("/api-client/") || fileNameNoExt.endsWith("service") || fileNameNoExt.endsWith("api")) {
|
|
31
61
|
return "service";
|
|
32
62
|
}
|
|
33
|
-
if (normalized.includes("/store/") || normalized.includes("/stores/") || normalized.includes("/context/") || normalized.includes("/contexts/") || normalized.includes("/providers/"))
|
|
63
|
+
if (normalized.includes("/store/") || normalized.includes("/stores/") || normalized.includes("/context/") || normalized.includes("/contexts/") || normalized.includes("/providers/") || normalized.includes("/state/") || // Zustand, Redux, Pinia, etc
|
|
64
|
+
fileNameNoExt.endsWith("store") || fileNameNoExt.endsWith("slice") || fileNameNoExt.endsWith("reducer")) {
|
|
34
65
|
return "store";
|
|
35
66
|
}
|
|
36
|
-
if (normalized.includes("/utils/") || normalized.includes("/lib/") || normalized.includes("/helpers/") || normalized.includes("/common/")) {
|
|
67
|
+
if (normalized.includes("/utils/") || normalized.includes("/lib/") || normalized.includes("/helpers/") || normalized.includes("/common/") || normalized.includes("/shared/") || fileNameNoExt.endsWith("utils") || fileNameNoExt.endsWith("helpers")) {
|
|
37
68
|
return "util";
|
|
38
69
|
}
|
|
39
|
-
if (normalized.includes("/components/") || normalized.includes("/ui/") || normalized.includes("/features/"))
|
|
70
|
+
if (normalized.includes("/components/") || normalized.includes("/ui/") || normalized.includes("/features/") || normalized.includes("/modules/") || // Vue/Svelte single file components
|
|
71
|
+
fileName.endsWith(".vue") || fileName.endsWith(".svelte")) {
|
|
40
72
|
return "component";
|
|
41
73
|
}
|
|
42
74
|
return "other";
|
|
@@ -597,6 +629,177 @@ function formatContextText(result) {
|
|
|
597
629
|
`;
|
|
598
630
|
return out;
|
|
599
631
|
}
|
|
632
|
+
function formatAreasText(result) {
|
|
633
|
+
let out = "";
|
|
634
|
+
out += `
|
|
635
|
+
`;
|
|
636
|
+
out += `\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
637
|
+
`;
|
|
638
|
+
out += `\u2551 \u{1F4E6} PROJECT AREAS \u2551
|
|
639
|
+
`;
|
|
640
|
+
out += `\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
641
|
+
|
|
642
|
+
`;
|
|
643
|
+
out += `\u{1F4CA} RESUMO
|
|
644
|
+
`;
|
|
645
|
+
out += ` \xC1reas: ${result.summary.totalAreas}
|
|
646
|
+
`;
|
|
647
|
+
out += ` Arquivos: ${result.summary.totalFiles}
|
|
648
|
+
`;
|
|
649
|
+
if (result.summary.unmappedCount > 0) {
|
|
650
|
+
out += ` \u26A0\uFE0F Sem \xE1rea: ${result.summary.unmappedCount}
|
|
651
|
+
`;
|
|
652
|
+
}
|
|
653
|
+
out += `
|
|
654
|
+
`;
|
|
655
|
+
out += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
656
|
+
|
|
657
|
+
`;
|
|
658
|
+
out += `\u{1F4E6} \xC1REAS DETECTADAS
|
|
659
|
+
|
|
660
|
+
`;
|
|
661
|
+
for (const area2 of result.areas) {
|
|
662
|
+
const autoTag = area2.isAutoDetected ? " (auto)" : "";
|
|
663
|
+
out += ` ${area2.name.padEnd(25)} ${String(area2.fileCount).padStart(4)} arquivos${autoTag}
|
|
664
|
+
`;
|
|
665
|
+
const catSummary = Object.entries(area2.categories).sort((a, b) => b[1] - a[1]).slice(0, 4).map(([cat, count]) => `${categoryIcons[cat]}${count}`).join(" ");
|
|
666
|
+
if (catSummary) {
|
|
667
|
+
out += ` ${catSummary}
|
|
668
|
+
`;
|
|
669
|
+
}
|
|
670
|
+
if (area2.description) {
|
|
671
|
+
out += ` ${area2.description}
|
|
672
|
+
`;
|
|
673
|
+
}
|
|
674
|
+
out += `
|
|
675
|
+
`;
|
|
676
|
+
}
|
|
677
|
+
if (result.unmapped.length > 0) {
|
|
678
|
+
out += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
679
|
+
|
|
680
|
+
`;
|
|
681
|
+
out += `\u26A0\uFE0F ARQUIVOS SEM \xC1REA (${result.unmapped.length})
|
|
682
|
+
|
|
683
|
+
`;
|
|
684
|
+
for (const file of result.unmapped.slice(0, 10)) {
|
|
685
|
+
const icon = categoryIcons[file.category];
|
|
686
|
+
out += ` ${icon} ${file.path}
|
|
687
|
+
`;
|
|
688
|
+
}
|
|
689
|
+
if (result.unmapped.length > 10) {
|
|
690
|
+
out += ` ... e mais ${result.unmapped.length - 10}
|
|
691
|
+
`;
|
|
692
|
+
}
|
|
693
|
+
out += `
|
|
694
|
+
\u{1F4A1} Adicione padr\xF5es em .analyze/areas.config.json
|
|
695
|
+
`;
|
|
696
|
+
out += ` ou execute 'ai-tool areas init' para gerar configura\xE7\xE3o
|
|
697
|
+
`;
|
|
698
|
+
}
|
|
699
|
+
out += `
|
|
700
|
+
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
701
|
+
|
|
702
|
+
`;
|
|
703
|
+
out += `\u{1F4A1} Use 'ai-tool area <nome>' para ver detalhes de uma \xE1rea
|
|
704
|
+
`;
|
|
705
|
+
out += ` Exemplo: ai-tool area meus-pets
|
|
706
|
+
`;
|
|
707
|
+
return out;
|
|
708
|
+
}
|
|
709
|
+
function formatAreaDetailText(result, options = {}) {
|
|
710
|
+
const { full = false, filterType } = options;
|
|
711
|
+
const { area: area2, byCategory } = result;
|
|
712
|
+
let out = "";
|
|
713
|
+
out += `
|
|
714
|
+
`;
|
|
715
|
+
out += `\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
716
|
+
`;
|
|
717
|
+
out += `\u2551 \u{1F4E6} AREA DETAIL \u2551
|
|
718
|
+
`;
|
|
719
|
+
out += `\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
720
|
+
|
|
721
|
+
`;
|
|
722
|
+
out += `\u{1F4E6} ${area2.name}
|
|
723
|
+
`;
|
|
724
|
+
if (area2.description) {
|
|
725
|
+
out += ` ${area2.description}
|
|
726
|
+
`;
|
|
727
|
+
}
|
|
728
|
+
out += `
|
|
729
|
+
`;
|
|
730
|
+
out += `\u{1F4CA} Resumo: ${area2.fileCount} arquivos
|
|
731
|
+
`;
|
|
732
|
+
const catOrder = [
|
|
733
|
+
"page",
|
|
734
|
+
"layout",
|
|
735
|
+
"route",
|
|
736
|
+
"component",
|
|
737
|
+
"hook",
|
|
738
|
+
"service",
|
|
739
|
+
"store",
|
|
740
|
+
"util",
|
|
741
|
+
"type",
|
|
742
|
+
"config",
|
|
743
|
+
"test",
|
|
744
|
+
"other"
|
|
745
|
+
];
|
|
746
|
+
const catParts = [];
|
|
747
|
+
for (const cat of catOrder) {
|
|
748
|
+
const count = area2.categories[cat];
|
|
749
|
+
if (count) {
|
|
750
|
+
catParts.push(`${categoryIcons[cat]} ${cat}: ${count}`);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
out += catParts.join(" ");
|
|
754
|
+
out += `
|
|
755
|
+
|
|
756
|
+
`;
|
|
757
|
+
out += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
758
|
+
|
|
759
|
+
`;
|
|
760
|
+
if (filterType) {
|
|
761
|
+
const files = byCategory[filterType] || [];
|
|
762
|
+
out += `${categoryIcons[filterType]} ${filterType.toUpperCase()} (${files.length})
|
|
763
|
+
|
|
764
|
+
`;
|
|
765
|
+
for (const file of files) {
|
|
766
|
+
const desc = file.description ? ` ${file.description}` : "";
|
|
767
|
+
out += ` ${file.path}${desc}
|
|
768
|
+
`;
|
|
769
|
+
}
|
|
770
|
+
return out;
|
|
771
|
+
}
|
|
772
|
+
const maxFilesPerCategory = full ? 100 : 8;
|
|
773
|
+
for (const cat of catOrder) {
|
|
774
|
+
const files = byCategory[cat];
|
|
775
|
+
if (!files || files.length === 0) continue;
|
|
776
|
+
out += `${categoryIcons[cat]} ${cat.toUpperCase()} (${files.length})
|
|
777
|
+
`;
|
|
778
|
+
const filesToShow = files.slice(0, maxFilesPerCategory);
|
|
779
|
+
const remaining = files.length - filesToShow.length;
|
|
780
|
+
for (const file of filesToShow) {
|
|
781
|
+
const maxPathLen = 50;
|
|
782
|
+
let displayPath = file.path;
|
|
783
|
+
if (displayPath.length > maxPathLen) {
|
|
784
|
+
displayPath = "..." + displayPath.slice(-maxPathLen + 3);
|
|
785
|
+
}
|
|
786
|
+
const desc = file.description || "";
|
|
787
|
+
out += ` ${displayPath.padEnd(maxPathLen + 2)} ${desc}
|
|
788
|
+
`;
|
|
789
|
+
}
|
|
790
|
+
if (remaining > 0) {
|
|
791
|
+
out += ` ... e mais ${remaining}
|
|
792
|
+
`;
|
|
793
|
+
}
|
|
794
|
+
out += `
|
|
795
|
+
`;
|
|
796
|
+
}
|
|
797
|
+
if (!full && area2.fileCount > 20) {
|
|
798
|
+
out += `\u{1F4A1} Use --full para ver todos os arquivos
|
|
799
|
+
`;
|
|
800
|
+
}
|
|
801
|
+
return out;
|
|
802
|
+
}
|
|
600
803
|
|
|
601
804
|
// src/cache/index.ts
|
|
602
805
|
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync, statSync, readdirSync } from "fs";
|
|
@@ -1943,8 +2146,1058 @@ function levenshteinDistance3(a, b) {
|
|
|
1943
2146
|
return matrix[b.length][a.length];
|
|
1944
2147
|
}
|
|
1945
2148
|
|
|
2149
|
+
// src/commands/areas.ts
|
|
2150
|
+
import { readdirSync as readdirSync3, statSync as statSync3 } from "fs";
|
|
2151
|
+
import { join as join5, extname as extname3 } from "path";
|
|
2152
|
+
|
|
2153
|
+
// src/areas/config.ts
|
|
2154
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
2155
|
+
import { join as join4 } from "path";
|
|
2156
|
+
var CONFIG_FILE = "areas.config.json";
|
|
2157
|
+
var DEFAULT_CONFIG = {
|
|
2158
|
+
$schema: "./areas.schema.json",
|
|
2159
|
+
version: "1.0.0",
|
|
2160
|
+
areas: {},
|
|
2161
|
+
descriptions: {},
|
|
2162
|
+
settings: {
|
|
2163
|
+
autoDetect: true,
|
|
2164
|
+
inferDescriptions: true,
|
|
2165
|
+
groupByCategory: true
|
|
2166
|
+
}
|
|
2167
|
+
};
|
|
2168
|
+
function getConfigPath(cwd) {
|
|
2169
|
+
return join4(cwd, CACHE_DIR, CONFIG_FILE);
|
|
2170
|
+
}
|
|
2171
|
+
function configExists(cwd) {
|
|
2172
|
+
return existsSync4(getConfigPath(cwd));
|
|
2173
|
+
}
|
|
2174
|
+
function readConfig(cwd) {
|
|
2175
|
+
const configPath = getConfigPath(cwd);
|
|
2176
|
+
if (!existsSync4(configPath)) {
|
|
2177
|
+
return DEFAULT_CONFIG;
|
|
2178
|
+
}
|
|
2179
|
+
try {
|
|
2180
|
+
const content = readFileSync3(configPath, "utf-8");
|
|
2181
|
+
const config = JSON.parse(content);
|
|
2182
|
+
return {
|
|
2183
|
+
...DEFAULT_CONFIG,
|
|
2184
|
+
...config,
|
|
2185
|
+
settings: {
|
|
2186
|
+
...DEFAULT_CONFIG.settings,
|
|
2187
|
+
...config.settings
|
|
2188
|
+
}
|
|
2189
|
+
};
|
|
2190
|
+
} catch {
|
|
2191
|
+
return DEFAULT_CONFIG;
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
function writeConfig(cwd, config) {
|
|
2195
|
+
const cacheDir = join4(cwd, CACHE_DIR);
|
|
2196
|
+
if (!existsSync4(cacheDir)) {
|
|
2197
|
+
mkdirSync2(cacheDir, { recursive: true });
|
|
2198
|
+
}
|
|
2199
|
+
const configPath = getConfigPath(cwd);
|
|
2200
|
+
writeFileSync2(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
2201
|
+
}
|
|
2202
|
+
function setArea(cwd, id, area2) {
|
|
2203
|
+
const config = readConfig(cwd);
|
|
2204
|
+
config.areas[id] = area2;
|
|
2205
|
+
writeConfig(cwd, config);
|
|
2206
|
+
}
|
|
2207
|
+
function removeArea(cwd, id) {
|
|
2208
|
+
const config = readConfig(cwd);
|
|
2209
|
+
delete config.areas[id];
|
|
2210
|
+
writeConfig(cwd, config);
|
|
2211
|
+
}
|
|
2212
|
+
function setFileDescription(cwd, filePath, description) {
|
|
2213
|
+
const config = readConfig(cwd);
|
|
2214
|
+
if (!config.descriptions) {
|
|
2215
|
+
config.descriptions = {};
|
|
2216
|
+
}
|
|
2217
|
+
config.descriptions[filePath] = description;
|
|
2218
|
+
writeConfig(cwd, config);
|
|
2219
|
+
}
|
|
2220
|
+
function getFileDescription(cwd, filePath) {
|
|
2221
|
+
const config = readConfig(cwd);
|
|
2222
|
+
return config.descriptions?.[filePath];
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
// src/areas/detector.ts
|
|
2226
|
+
import { minimatch } from "minimatch";
|
|
2227
|
+
|
|
2228
|
+
// src/areas/patterns.ts
|
|
2229
|
+
var FOLDER_PATTERNS = [
|
|
2230
|
+
// ============================================================================
|
|
2231
|
+
// NEXT.JS APP ROUTER - Rotas específicas (alta prioridade)
|
|
2232
|
+
// ============================================================================
|
|
2233
|
+
{ pattern: /app\/.*\/meus-pets\//, area: "meus-pets", priority: 100 },
|
|
2234
|
+
{ pattern: /app\/.*\/pets\//, area: "meus-pets", priority: 100 },
|
|
2235
|
+
{ pattern: /app\/.*\/consultas\//, area: "consultas-ia", priority: 100 },
|
|
2236
|
+
{ pattern: /app\/.*\/dashboard\//, area: "dashboard", priority: 100 },
|
|
2237
|
+
{ pattern: /app\/.*\/admin\//, area: "admin", priority: 100 },
|
|
2238
|
+
{ pattern: /app\/.*\/assinatura\//, area: "stripe", priority: 100 },
|
|
2239
|
+
{ pattern: /app\/.*\/guias\//, area: "training", priority: 100 },
|
|
2240
|
+
{ pattern: /app\/.*\/treino\//, area: "training", priority: 100 },
|
|
2241
|
+
{ pattern: /app\/.*\/login\//, area: "auth", priority: 100 },
|
|
2242
|
+
{ pattern: /app\/.*\/cadastro\//, area: "auth", priority: 100 },
|
|
2243
|
+
{ pattern: /app\/.*\/auth\//, area: "auth", priority: 100 },
|
|
2244
|
+
{ pattern: /app\/.*\/perfil\//, area: "profile", priority: 100 },
|
|
2245
|
+
{ pattern: /app\/.*\/configuracoes\//, area: "settings", priority: 100 },
|
|
2246
|
+
{ pattern: /app\/.*\/settings\//, area: "settings", priority: 100 },
|
|
2247
|
+
{ pattern: /app\/.*\/onboarding/, area: "onboarding", priority: 100 },
|
|
2248
|
+
{ pattern: /app\/.*\/beta\//, area: "beta", priority: 100 },
|
|
2249
|
+
{ pattern: /app\/.*\/precos\//, area: "pricing", priority: 100 },
|
|
2250
|
+
{ pattern: /app\/.*\/pricing\//, area: "pricing", priority: 100 },
|
|
2251
|
+
{ pattern: /app\/.*\/checkout\//, area: "checkout", priority: 100 },
|
|
2252
|
+
{ pattern: /app\/.*\/cart\//, area: "cart", priority: 100 },
|
|
2253
|
+
{ pattern: /app\/.*\/shop\//, area: "shop", priority: 100 },
|
|
2254
|
+
{ pattern: /app\/.*\/products\//, area: "products", priority: 100 },
|
|
2255
|
+
{ pattern: /app\/.*\/orders\//, area: "orders", priority: 100 },
|
|
2256
|
+
{ pattern: /app\/.*\/blog\//, area: "blog", priority: 100 },
|
|
2257
|
+
{ pattern: /app\/.*\/docs\//, area: "docs", priority: 100 },
|
|
2258
|
+
{ pattern: /app\/.*\/legal\//, area: "legal", priority: 100 },
|
|
2259
|
+
{ pattern: /app\/.*\/privacy\//, area: "legal", priority: 100 },
|
|
2260
|
+
{ pattern: /app\/.*\/terms\//, area: "legal", priority: 100 },
|
|
2261
|
+
{ pattern: /app\/.*\/about\//, area: "about", priority: 100 },
|
|
2262
|
+
{ pattern: /app\/.*\/contact\//, area: "contact", priority: 100 },
|
|
2263
|
+
{ pattern: /app\/.*\/faq\//, area: "faq", priority: 100 },
|
|
2264
|
+
{ pattern: /app\/.*\/help\//, area: "help", priority: 100 },
|
|
2265
|
+
{ pattern: /app\/.*\/support\//, area: "support", priority: 100 },
|
|
2266
|
+
{ pattern: /app\/.*\/feedback\//, area: "feedback", priority: 100 },
|
|
2267
|
+
// ============================================================================
|
|
2268
|
+
// VITE / CRA - src/pages/ ou src/views/ (alta prioridade)
|
|
2269
|
+
// ============================================================================
|
|
2270
|
+
{ pattern: /src\/pages\/[Dd]ashboard/, area: "dashboard", priority: 100 },
|
|
2271
|
+
{ pattern: /src\/pages\/[Aa]dmin/, area: "admin", priority: 100 },
|
|
2272
|
+
{ pattern: /src\/pages\/[Aa]uth/, area: "auth", priority: 100 },
|
|
2273
|
+
{ pattern: /src\/pages\/[Ll]ogin/, area: "auth", priority: 100 },
|
|
2274
|
+
{ pattern: /src\/pages\/[Rr]egister/, area: "auth", priority: 100 },
|
|
2275
|
+
{ pattern: /src\/pages\/[Ss]ignup/, area: "auth", priority: 100 },
|
|
2276
|
+
{ pattern: /src\/pages\/[Pp]rofile/, area: "profile", priority: 100 },
|
|
2277
|
+
{ pattern: /src\/pages\/[Ss]ettings/, area: "settings", priority: 100 },
|
|
2278
|
+
{ pattern: /src\/pages\/[Pp]ricing/, area: "pricing", priority: 100 },
|
|
2279
|
+
{ pattern: /src\/pages\/[Cc]heckout/, area: "checkout", priority: 100 },
|
|
2280
|
+
{ pattern: /src\/pages\/[Cc]art/, area: "cart", priority: 100 },
|
|
2281
|
+
{ pattern: /src\/pages\/[Ss]hop/, area: "shop", priority: 100 },
|
|
2282
|
+
{ pattern: /src\/pages\/[Pp]roducts?/, area: "products", priority: 100 },
|
|
2283
|
+
{ pattern: /src\/pages\/[Oo]rders?/, area: "orders", priority: 100 },
|
|
2284
|
+
{ pattern: /src\/pages\/[Bb]log/, area: "blog", priority: 100 },
|
|
2285
|
+
{ pattern: /src\/views\/[Dd]ashboard/, area: "dashboard", priority: 100 },
|
|
2286
|
+
{ pattern: /src\/views\/[Aa]dmin/, area: "admin", priority: 100 },
|
|
2287
|
+
{ pattern: /src\/views\/[Aa]uth/, area: "auth", priority: 100 },
|
|
2288
|
+
// ============================================================================
|
|
2289
|
+
// REMIX - app/routes/
|
|
2290
|
+
// ============================================================================
|
|
2291
|
+
{ pattern: /app\/routes\/dashboard/, area: "dashboard", priority: 100 },
|
|
2292
|
+
{ pattern: /app\/routes\/admin/, area: "admin", priority: 100 },
|
|
2293
|
+
{ pattern: /app\/routes\/auth/, area: "auth", priority: 100 },
|
|
2294
|
+
{ pattern: /app\/routes\/login/, area: "auth", priority: 100 },
|
|
2295
|
+
{ pattern: /app\/routes\/_auth/, area: "auth", priority: 100 },
|
|
2296
|
+
// ============================================================================
|
|
2297
|
+
// NUXT - pages/ (sem src/)
|
|
2298
|
+
// ============================================================================
|
|
2299
|
+
{ pattern: /^pages\/dashboard/, area: "dashboard", priority: 100 },
|
|
2300
|
+
{ pattern: /^pages\/admin/, area: "admin", priority: 100 },
|
|
2301
|
+
{ pattern: /^pages\/auth/, area: "auth", priority: 100 },
|
|
2302
|
+
// ============================================================================
|
|
2303
|
+
// SVELTEKIT - src/routes/
|
|
2304
|
+
// ============================================================================
|
|
2305
|
+
{ pattern: /src\/routes\/dashboard/, area: "dashboard", priority: 100 },
|
|
2306
|
+
{ pattern: /src\/routes\/admin/, area: "admin", priority: 100 },
|
|
2307
|
+
{ pattern: /src\/routes\/auth/, area: "auth", priority: 100 },
|
|
2308
|
+
{ pattern: /src\/routes\/\(auth\)/, area: "auth", priority: 100 },
|
|
2309
|
+
{ pattern: /src\/routes\/\(app\)/, area: "app", priority: 90 },
|
|
2310
|
+
// ============================================================================
|
|
2311
|
+
// ASTRO - src/pages/
|
|
2312
|
+
// ============================================================================
|
|
2313
|
+
{ pattern: /src\/pages\/blog/, area: "blog", priority: 100 },
|
|
2314
|
+
{ pattern: /src\/pages\/docs/, area: "docs", priority: 100 },
|
|
2315
|
+
// ============================================================================
|
|
2316
|
+
// COMPONENTS - Por subpasta (alta prioridade)
|
|
2317
|
+
// Funciona em qualquer framework (com ou sem src/)
|
|
2318
|
+
// ============================================================================
|
|
2319
|
+
{ pattern: /components\/pets\//, area: "meus-pets", priority: 90 },
|
|
2320
|
+
{ pattern: /components\/pet\//, area: "meus-pets", priority: 90 },
|
|
2321
|
+
{ pattern: /components\/consultation\//, area: "consultas-ia", priority: 90 },
|
|
2322
|
+
{ pattern: /components\/chat\//, area: "chat", priority: 90 },
|
|
2323
|
+
{ pattern: /components\/training\//, area: "training", priority: 90 },
|
|
2324
|
+
{ pattern: /components\/health\//, area: "health-tracking", priority: 90 },
|
|
2325
|
+
{ pattern: /components\/auth\//, area: "auth", priority: 90 },
|
|
2326
|
+
{ pattern: /components\/admin\//, area: "admin", priority: 90 },
|
|
2327
|
+
{ pattern: /components\/landing\//, area: "landing", priority: 90 },
|
|
2328
|
+
{ pattern: /components\/marketing\//, area: "landing", priority: 90 },
|
|
2329
|
+
{ pattern: /components\/dashboard\//, area: "dashboard", priority: 90 },
|
|
2330
|
+
{ pattern: /components\/subscription\//, area: "stripe", priority: 90 },
|
|
2331
|
+
{ pattern: /components\/stripe\//, area: "stripe", priority: 90 },
|
|
2332
|
+
{ pattern: /components\/payment\//, area: "payments", priority: 90 },
|
|
2333
|
+
{ pattern: /components\/checkout\//, area: "checkout", priority: 90 },
|
|
2334
|
+
{ pattern: /components\/cart\//, area: "cart", priority: 90 },
|
|
2335
|
+
{ pattern: /components\/notification\//, area: "notifications", priority: 90 },
|
|
2336
|
+
{ pattern: /components\/pdf\//, area: "pdf", priority: 90 },
|
|
2337
|
+
{ pattern: /components\/seo\//, area: "seo", priority: 90 },
|
|
2338
|
+
{ pattern: /components\/blog\//, area: "blog", priority: 90 },
|
|
2339
|
+
{ pattern: /components\/docs\//, area: "docs", priority: 90 },
|
|
2340
|
+
{ pattern: /components\/legal\//, area: "legal", priority: 90 },
|
|
2341
|
+
{ pattern: /components\/feedback\//, area: "feedback", priority: 90 },
|
|
2342
|
+
{ pattern: /components\/beta\//, area: "beta", priority: 90 },
|
|
2343
|
+
{ pattern: /components\/onboarding\//, area: "onboarding", priority: 90 },
|
|
2344
|
+
{ pattern: /components\/settings\//, area: "settings", priority: 90 },
|
|
2345
|
+
{ pattern: /components\/profile\//, area: "profile", priority: 90 },
|
|
2346
|
+
{ pattern: /components\/user\//, area: "user", priority: 90 },
|
|
2347
|
+
{ pattern: /components\/products?\//, area: "products", priority: 90 },
|
|
2348
|
+
{ pattern: /components\/orders?\//, area: "orders", priority: 90 },
|
|
2349
|
+
{ pattern: /components\/shop\//, area: "shop", priority: 90 },
|
|
2350
|
+
{ pattern: /components\/forms?\//, area: "forms", priority: 85 },
|
|
2351
|
+
{ pattern: /components\/tables?\//, area: "tables", priority: 85 },
|
|
2352
|
+
{ pattern: /components\/modals?\//, area: "modals", priority: 85 },
|
|
2353
|
+
{ pattern: /components\/dialogs?\//, area: "modals", priority: 85 },
|
|
2354
|
+
// Componentes compartilhados (baixa prioridade)
|
|
2355
|
+
{ pattern: /components\/ui\//, area: "shared-ui", priority: 30 },
|
|
2356
|
+
{ pattern: /components\/common\//, area: "shared-ui", priority: 30 },
|
|
2357
|
+
{ pattern: /components\/shared\//, area: "shared-ui", priority: 30 },
|
|
2358
|
+
{ pattern: /components\/base\//, area: "shared-ui", priority: 30 },
|
|
2359
|
+
{ pattern: /components\/core\//, area: "shared-ui", priority: 30 },
|
|
2360
|
+
{ pattern: /components\/primitives\//, area: "shared-ui", priority: 30 },
|
|
2361
|
+
{ pattern: /components\/providers\//, area: "core", priority: 40 },
|
|
2362
|
+
{ pattern: /components\/layout\//, area: "core", priority: 40 },
|
|
2363
|
+
{ pattern: /components\/layouts\//, area: "core", priority: 40 },
|
|
2364
|
+
// ============================================================================
|
|
2365
|
+
// FEATURES (padrão comum em projetos maiores)
|
|
2366
|
+
// ============================================================================
|
|
2367
|
+
{ pattern: /features\/auth\//, area: "auth", priority: 95 },
|
|
2368
|
+
{ pattern: /features\/dashboard\//, area: "dashboard", priority: 95 },
|
|
2369
|
+
{ pattern: /features\/admin\//, area: "admin", priority: 95 },
|
|
2370
|
+
{ pattern: /features\/checkout\//, area: "checkout", priority: 95 },
|
|
2371
|
+
{ pattern: /features\/cart\//, area: "cart", priority: 95 },
|
|
2372
|
+
{ pattern: /features\/products?\//, area: "products", priority: 95 },
|
|
2373
|
+
{ pattern: /features\/orders?\//, area: "orders", priority: 95 },
|
|
2374
|
+
{ pattern: /features\/user\//, area: "user", priority: 95 },
|
|
2375
|
+
{ pattern: /features\/settings\//, area: "settings", priority: 95 },
|
|
2376
|
+
{ pattern: /features\/notifications?\//, area: "notifications", priority: 95 },
|
|
2377
|
+
{ pattern: /features\/blog\//, area: "blog", priority: 95 },
|
|
2378
|
+
// ============================================================================
|
|
2379
|
+
// MODULES (outro padrão comum)
|
|
2380
|
+
// ============================================================================
|
|
2381
|
+
{ pattern: /modules\/auth\//, area: "auth", priority: 95 },
|
|
2382
|
+
{ pattern: /modules\/dashboard\//, area: "dashboard", priority: 95 },
|
|
2383
|
+
{ pattern: /modules\/admin\//, area: "admin", priority: 95 },
|
|
2384
|
+
{ pattern: /modules\/checkout\//, area: "checkout", priority: 95 },
|
|
2385
|
+
{ pattern: /modules\/products?\//, area: "products", priority: 95 },
|
|
2386
|
+
// ============================================================================
|
|
2387
|
+
// LIB - Módulos específicos
|
|
2388
|
+
// ============================================================================
|
|
2389
|
+
{ pattern: /lib\/firebase\/ai\//, area: "firebase-ai", priority: 85 },
|
|
2390
|
+
{ pattern: /lib\/firebase\/aiExtraction\//, area: "firebase-ai", priority: 85 },
|
|
2391
|
+
{ pattern: /lib\/firebase\/firestore\//, area: "firebase-firestore", priority: 85 },
|
|
2392
|
+
{ pattern: /lib\/firebase\/prompts\//, area: "firebase-ai", priority: 85 },
|
|
2393
|
+
{ pattern: /lib\/firebase\/analytics\//, area: "analytics", priority: 85 },
|
|
2394
|
+
{ pattern: /lib\/firebase\//, area: "firebase-core", priority: 80 },
|
|
2395
|
+
{ pattern: /lib\/stripe\//, area: "stripe", priority: 80 },
|
|
2396
|
+
{ pattern: /lib\/i18n\//, area: "i18n", priority: 80 },
|
|
2397
|
+
// ============================================================================
|
|
2398
|
+
// HOOKS - Por nome
|
|
2399
|
+
// ============================================================================
|
|
2400
|
+
{ pattern: /hooks\/.*[Pp]et/, area: "meus-pets", priority: 70 },
|
|
2401
|
+
{ pattern: /hooks\/.*[Aa]uth/, area: "auth", priority: 70 },
|
|
2402
|
+
{ pattern: /hooks\/.*[Ss]ubscription/, area: "stripe", priority: 70 },
|
|
2403
|
+
{ pattern: /hooks\/.*[Nn]otification/, area: "notifications", priority: 70 },
|
|
2404
|
+
{ pattern: /hooks\/.*[Hh]ealth/, area: "health-tracking", priority: 70 },
|
|
2405
|
+
{ pattern: /hooks\/.*[Tt]raining/, area: "training", priority: 70 },
|
|
2406
|
+
// ============================================================================
|
|
2407
|
+
// STORE - Por nome
|
|
2408
|
+
// ============================================================================
|
|
2409
|
+
{ pattern: /store\/.*[Pp]et/, area: "meus-pets", priority: 70 },
|
|
2410
|
+
{ pattern: /store\/.*[Aa]uth/, area: "auth", priority: 70 },
|
|
2411
|
+
{ pattern: /store\/.*[Uu]ser/, area: "auth", priority: 70 },
|
|
2412
|
+
// ============================================================================
|
|
2413
|
+
// SCHEMAS - Por nome
|
|
2414
|
+
// ============================================================================
|
|
2415
|
+
{ pattern: /schemas\/.*[Pp]et/, area: "meus-pets", priority: 70 },
|
|
2416
|
+
{ pattern: /schemas\/.*[Aa]uth/, area: "auth", priority: 70 },
|
|
2417
|
+
// ============================================================================
|
|
2418
|
+
// TYPES - Por nome
|
|
2419
|
+
// ============================================================================
|
|
2420
|
+
{ pattern: /types\/.*[Pp]et/, area: "meus-pets", priority: 70 },
|
|
2421
|
+
{ pattern: /types\/.*[Aa]uth/, area: "auth", priority: 70 },
|
|
2422
|
+
{ pattern: /types\/.*[Ss]tripe/, area: "stripe", priority: 70 },
|
|
2423
|
+
{ pattern: /types\/.*[Ss]ubscription/, area: "stripe", priority: 70 },
|
|
2424
|
+
// ============================================================================
|
|
2425
|
+
// CLOUD FUNCTIONS
|
|
2426
|
+
// ============================================================================
|
|
2427
|
+
{ pattern: /functions\/src\//, area: "cloud-functions", priority: 80 },
|
|
2428
|
+
// ============================================================================
|
|
2429
|
+
// OUTROS
|
|
2430
|
+
// ============================================================================
|
|
2431
|
+
{ pattern: /messages\//, area: "i18n", priority: 60 },
|
|
2432
|
+
{ pattern: /i18n\//, area: "i18n", priority: 60 },
|
|
2433
|
+
{ pattern: /public\//, area: "assets", priority: 50 },
|
|
2434
|
+
{ pattern: /scripts\//, area: "scripts", priority: 50 }
|
|
2435
|
+
];
|
|
2436
|
+
var KEYWORD_PATTERNS = [
|
|
2437
|
+
// Pets
|
|
2438
|
+
{ keyword: /[Pp]et/, area: "meus-pets", priority: 60 },
|
|
2439
|
+
{ keyword: /[Vv]accin/, area: "meus-pets", priority: 60 },
|
|
2440
|
+
{ keyword: /[Dd]eworm/, area: "meus-pets", priority: 60 },
|
|
2441
|
+
{ keyword: /[Mm]edication/, area: "meus-pets", priority: 60 },
|
|
2442
|
+
{ keyword: /[Ss]urgery/, area: "meus-pets", priority: 60 },
|
|
2443
|
+
{ keyword: /[Vv]eterinary/, area: "meus-pets", priority: 60 },
|
|
2444
|
+
// Consultas IA
|
|
2445
|
+
{ keyword: /[Cc]onsultation/, area: "consultas-ia", priority: 60 },
|
|
2446
|
+
{ keyword: /[Cc]hat/, area: "consultas-ia", priority: 50 },
|
|
2447
|
+
{ keyword: /[Gg]emini/, area: "firebase-ai", priority: 60 },
|
|
2448
|
+
// Health
|
|
2449
|
+
{ keyword: /[Hh]ealth[Tt]racking/, area: "health-tracking", priority: 65 },
|
|
2450
|
+
{ keyword: /[Hh]ome[Cc]are/, area: "health-tracking", priority: 65 },
|
|
2451
|
+
// Training
|
|
2452
|
+
{ keyword: /[Tt]raining/, area: "training", priority: 60 },
|
|
2453
|
+
{ keyword: /[Gg]uide/, area: "training", priority: 55 },
|
|
2454
|
+
{ keyword: /[Aa]destramento/, area: "training", priority: 60 },
|
|
2455
|
+
// Auth
|
|
2456
|
+
{ keyword: /[Aa]uth/, area: "auth", priority: 60 },
|
|
2457
|
+
{ keyword: /[Ll]ogin/, area: "auth", priority: 60 },
|
|
2458
|
+
{ keyword: /[Rr]egister/, area: "auth", priority: 60 },
|
|
2459
|
+
{ keyword: /[Ss]ignup/, area: "auth", priority: 60 },
|
|
2460
|
+
{ keyword: /[Ss]ignin/, area: "auth", priority: 60 },
|
|
2461
|
+
// Stripe
|
|
2462
|
+
{ keyword: /[Ss]tripe/, area: "stripe", priority: 65 },
|
|
2463
|
+
{ keyword: /[Ss]ubscription/, area: "stripe", priority: 60 },
|
|
2464
|
+
{ keyword: /[Pp]ayment/, area: "stripe", priority: 60 },
|
|
2465
|
+
{ keyword: /[Cc]heckout/, area: "stripe", priority: 60 },
|
|
2466
|
+
{ keyword: /[Pp]rice/, area: "pricing", priority: 55 },
|
|
2467
|
+
{ keyword: /[Pp]ricing/, area: "pricing", priority: 60 },
|
|
2468
|
+
// Notifications
|
|
2469
|
+
{ keyword: /[Nn]otification/, area: "notifications", priority: 60 },
|
|
2470
|
+
{ keyword: /[Ff][Cc][Mm]/, area: "notifications", priority: 65 },
|
|
2471
|
+
{ keyword: /[Pp]ush/, area: "notifications", priority: 55 },
|
|
2472
|
+
// i18n
|
|
2473
|
+
{ keyword: /[Ii]18n/, area: "i18n", priority: 60 },
|
|
2474
|
+
{ keyword: /[Ll]ocale/, area: "i18n", priority: 55 },
|
|
2475
|
+
{ keyword: /[Tt]ranslat/, area: "i18n", priority: 55 },
|
|
2476
|
+
// SEO
|
|
2477
|
+
{ keyword: /[Ss][Ee][Oo]/, area: "seo", priority: 60 },
|
|
2478
|
+
{ keyword: /[Ss]itemap/, area: "seo", priority: 60 },
|
|
2479
|
+
{ keyword: /[Mm]eta/, area: "seo", priority: 50 },
|
|
2480
|
+
// Analytics
|
|
2481
|
+
{ keyword: /[Aa]nalytics/, area: "analytics", priority: 60 },
|
|
2482
|
+
{ keyword: /[Uu]tm/, area: "analytics", priority: 55 },
|
|
2483
|
+
{ keyword: /[Tt]racking/, area: "analytics", priority: 50 },
|
|
2484
|
+
// Admin
|
|
2485
|
+
{ keyword: /[Aa]dmin/, area: "admin", priority: 60 },
|
|
2486
|
+
// PWA
|
|
2487
|
+
{ keyword: /[Pp][Ww][Aa]/, area: "pwa", priority: 60 },
|
|
2488
|
+
{ keyword: /[Ss]ervice[Ww]orker/, area: "pwa", priority: 60 },
|
|
2489
|
+
{ keyword: /[Mm]anifest/, area: "pwa", priority: 55 },
|
|
2490
|
+
{ keyword: /[Oo]ffline/, area: "pwa", priority: 55 },
|
|
2491
|
+
// PDF
|
|
2492
|
+
{ keyword: /[Pp]df/, area: "pdf", priority: 60 },
|
|
2493
|
+
{ keyword: /[Rr]eport/, area: "pdf", priority: 50 }
|
|
2494
|
+
];
|
|
2495
|
+
var AREA_NAMES = {
|
|
2496
|
+
// Áreas específicas de domínio
|
|
2497
|
+
"meus-pets": "Meus Pets",
|
|
2498
|
+
"consultas-ia": "Consultas IA",
|
|
2499
|
+
"health-tracking": "Health Tracking",
|
|
2500
|
+
training: "Adestramento",
|
|
2501
|
+
// Autenticação e usuário
|
|
2502
|
+
auth: "Autentica\xE7\xE3o",
|
|
2503
|
+
user: "Usu\xE1rio",
|
|
2504
|
+
profile: "Perfil",
|
|
2505
|
+
settings: "Configura\xE7\xF5es",
|
|
2506
|
+
onboarding: "Onboarding",
|
|
2507
|
+
// E-commerce
|
|
2508
|
+
stripe: "Pagamentos (Stripe)",
|
|
2509
|
+
payments: "Pagamentos",
|
|
2510
|
+
checkout: "Checkout",
|
|
2511
|
+
cart: "Carrinho",
|
|
2512
|
+
shop: "Loja",
|
|
2513
|
+
products: "Produtos",
|
|
2514
|
+
orders: "Pedidos",
|
|
2515
|
+
pricing: "Pre\xE7os",
|
|
2516
|
+
// Comunicação
|
|
2517
|
+
notifications: "Notifica\xE7\xF5es",
|
|
2518
|
+
chat: "Chat",
|
|
2519
|
+
feedback: "Feedback",
|
|
2520
|
+
support: "Suporte",
|
|
2521
|
+
help: "Ajuda",
|
|
2522
|
+
faq: "FAQ",
|
|
2523
|
+
contact: "Contato",
|
|
2524
|
+
// Firebase
|
|
2525
|
+
"firebase-core": "Firebase Core",
|
|
2526
|
+
"firebase-ai": "Firebase AI",
|
|
2527
|
+
"firebase-firestore": "Firestore",
|
|
2528
|
+
// Conteúdo
|
|
2529
|
+
blog: "Blog",
|
|
2530
|
+
docs: "Documenta\xE7\xE3o",
|
|
2531
|
+
legal: "P\xE1ginas Legais",
|
|
2532
|
+
about: "Sobre",
|
|
2533
|
+
// Marketing e SEO
|
|
2534
|
+
landing: "Landing Pages",
|
|
2535
|
+
seo: "SEO",
|
|
2536
|
+
analytics: "Analytics",
|
|
2537
|
+
beta: "Programa Beta",
|
|
2538
|
+
// Admin e Dashboard
|
|
2539
|
+
admin: "Admin",
|
|
2540
|
+
dashboard: "Dashboard",
|
|
2541
|
+
// Técnico
|
|
2542
|
+
i18n: "Internacionaliza\xE7\xE3o",
|
|
2543
|
+
pwa: "PWA",
|
|
2544
|
+
pdf: "PDF",
|
|
2545
|
+
core: "Core",
|
|
2546
|
+
"shared-ui": "UI Compartilhado",
|
|
2547
|
+
"cloud-functions": "Cloud Functions",
|
|
2548
|
+
assets: "Assets",
|
|
2549
|
+
scripts: "Scripts",
|
|
2550
|
+
// UI patterns
|
|
2551
|
+
forms: "Formul\xE1rios",
|
|
2552
|
+
tables: "Tabelas",
|
|
2553
|
+
modals: "Modais",
|
|
2554
|
+
// Genéricos
|
|
2555
|
+
app: "Aplica\xE7\xE3o"
|
|
2556
|
+
};
|
|
2557
|
+
var AREA_DESCRIPTIONS = {
|
|
2558
|
+
// Áreas específicas de domínio
|
|
2559
|
+
"meus-pets": "Gerenciamento completo de pets do usu\xE1rio",
|
|
2560
|
+
"consultas-ia": "Chat com IA para consultas veterin\xE1rias",
|
|
2561
|
+
"health-tracking": "Acompanhamento de sa\xFAde e sintomas",
|
|
2562
|
+
training: "Sistema de adestramento com guias e progresso",
|
|
2563
|
+
// Autenticação e usuário
|
|
2564
|
+
auth: "Autentica\xE7\xE3o e gerenciamento de sess\xE3o",
|
|
2565
|
+
user: "Gerenciamento de dados do usu\xE1rio",
|
|
2566
|
+
profile: "Perfil do usu\xE1rio",
|
|
2567
|
+
settings: "Configura\xE7\xF5es do usu\xE1rio",
|
|
2568
|
+
onboarding: "Fluxo de onboarding de novos usu\xE1rios",
|
|
2569
|
+
// E-commerce
|
|
2570
|
+
stripe: "Integra\xE7\xE3o Stripe para pagamentos e assinaturas",
|
|
2571
|
+
payments: "Sistema de pagamentos",
|
|
2572
|
+
checkout: "Fluxo de checkout e finaliza\xE7\xE3o de compra",
|
|
2573
|
+
cart: "Carrinho de compras",
|
|
2574
|
+
shop: "Loja e cat\xE1logo de produtos",
|
|
2575
|
+
products: "Gerenciamento de produtos",
|
|
2576
|
+
orders: "Gerenciamento de pedidos",
|
|
2577
|
+
pricing: "P\xE1gina de pre\xE7os e planos",
|
|
2578
|
+
// Comunicação
|
|
2579
|
+
notifications: "Sistema de notifica\xE7\xF5es push",
|
|
2580
|
+
chat: "Sistema de chat e mensagens",
|
|
2581
|
+
feedback: "Coleta de feedback dos usu\xE1rios",
|
|
2582
|
+
support: "Suporte ao cliente",
|
|
2583
|
+
help: "Central de ajuda",
|
|
2584
|
+
faq: "Perguntas frequentes",
|
|
2585
|
+
contact: "P\xE1gina de contato",
|
|
2586
|
+
// Firebase
|
|
2587
|
+
"firebase-core": "Configura\xE7\xE3o e servi\xE7os Firebase client-side",
|
|
2588
|
+
"firebase-ai": "Integra\xE7\xE3o com Firebase AI (Gemini)",
|
|
2589
|
+
"firebase-firestore": "Opera\xE7\xF5es CRUD no Firestore",
|
|
2590
|
+
// Conteúdo
|
|
2591
|
+
blog: "Blog e artigos",
|
|
2592
|
+
docs: "Documenta\xE7\xE3o e guias",
|
|
2593
|
+
legal: "Termos de uso, privacidade e pol\xEDticas",
|
|
2594
|
+
about: "P\xE1gina sobre a empresa",
|
|
2595
|
+
// Marketing e SEO
|
|
2596
|
+
landing: "Landing pages e marketing",
|
|
2597
|
+
seo: "SEO, meta tags e sitemaps",
|
|
2598
|
+
analytics: "Analytics e tracking de eventos",
|
|
2599
|
+
beta: "Programa de beta testers",
|
|
2600
|
+
// Admin e Dashboard
|
|
2601
|
+
admin: "Painel administrativo",
|
|
2602
|
+
dashboard: "Dashboard do usu\xE1rio",
|
|
2603
|
+
// Técnico
|
|
2604
|
+
i18n: "Internacionaliza\xE7\xE3o e tradu\xE7\xF5es",
|
|
2605
|
+
pwa: "Progressive Web App (offline, install)",
|
|
2606
|
+
pdf: "Gera\xE7\xE3o de relat\xF3rios PDF",
|
|
2607
|
+
core: "Providers e layout principal",
|
|
2608
|
+
"shared-ui": "Componentes de UI compartilhados",
|
|
2609
|
+
"cloud-functions": "Cloud Functions (serverless)",
|
|
2610
|
+
assets: "Assets p\xFAblicos (imagens, fontes)",
|
|
2611
|
+
scripts: "Scripts de automa\xE7\xE3o",
|
|
2612
|
+
// UI patterns
|
|
2613
|
+
forms: "Componentes de formul\xE1rio reutiliz\xE1veis",
|
|
2614
|
+
tables: "Componentes de tabela reutiliz\xE1veis",
|
|
2615
|
+
modals: "Modais e dialogs reutiliz\xE1veis",
|
|
2616
|
+
// Genéricos
|
|
2617
|
+
app: "\xC1rea principal da aplica\xE7\xE3o"
|
|
2618
|
+
};
|
|
2619
|
+
|
|
2620
|
+
// src/areas/detector.ts
|
|
2621
|
+
function detectFileAreas(filePath, config) {
|
|
2622
|
+
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
2623
|
+
const matches = [];
|
|
2624
|
+
for (const [areaId, areaConfig] of Object.entries(config.areas)) {
|
|
2625
|
+
if (matchesAreaConfig(normalizedPath, areaConfig)) {
|
|
2626
|
+
matches.push({ area: areaId, priority: 200, source: "config" });
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
for (const { pattern, area: area2, priority } of FOLDER_PATTERNS) {
|
|
2630
|
+
if (pattern.test(normalizedPath)) {
|
|
2631
|
+
if (!matches.some((m) => m.area === area2 && m.source === "config")) {
|
|
2632
|
+
matches.push({ area: area2, priority, source: "folder" });
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
const fileName = normalizedPath.split("/").pop() || "";
|
|
2637
|
+
for (const { keyword, area: area2, priority } of KEYWORD_PATTERNS) {
|
|
2638
|
+
if (keyword.test(fileName) || keyword.test(normalizedPath)) {
|
|
2639
|
+
if (!matches.some((m) => m.area === area2)) {
|
|
2640
|
+
matches.push({ area: area2, priority, source: "keyword" });
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
const sorted = matches.sort((a, b) => b.priority - a.priority);
|
|
2645
|
+
const unique = [...new Set(sorted.map((m) => m.area))];
|
|
2646
|
+
return unique;
|
|
2647
|
+
}
|
|
2648
|
+
function matchesAreaConfig(filePath, config) {
|
|
2649
|
+
if (config.exclude) {
|
|
2650
|
+
for (const pattern of config.exclude) {
|
|
2651
|
+
if (minimatch(filePath, pattern, { dot: true })) {
|
|
2652
|
+
return false;
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
for (const pattern of config.patterns) {
|
|
2657
|
+
if (minimatch(filePath, pattern, { dot: true })) {
|
|
2658
|
+
return true;
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
if (config.keywords) {
|
|
2662
|
+
const lowerPath = filePath.toLowerCase();
|
|
2663
|
+
for (const keyword of config.keywords) {
|
|
2664
|
+
if (lowerPath.includes(keyword.toLowerCase())) {
|
|
2665
|
+
return true;
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
return false;
|
|
2670
|
+
}
|
|
2671
|
+
function getAreaName(areaId, config) {
|
|
2672
|
+
if (config.areas[areaId]?.name) {
|
|
2673
|
+
return config.areas[areaId].name;
|
|
2674
|
+
}
|
|
2675
|
+
if (AREA_NAMES[areaId]) {
|
|
2676
|
+
return AREA_NAMES[areaId];
|
|
2677
|
+
}
|
|
2678
|
+
return areaId.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
2679
|
+
}
|
|
2680
|
+
function getAreaDescription(areaId, config) {
|
|
2681
|
+
if (config.areas[areaId]?.description) {
|
|
2682
|
+
return config.areas[areaId].description;
|
|
2683
|
+
}
|
|
2684
|
+
return AREA_DESCRIPTIONS[areaId];
|
|
2685
|
+
}
|
|
2686
|
+
function inferFileDescription(filePath, category) {
|
|
2687
|
+
const fileName = filePath.split("/").pop() || "";
|
|
2688
|
+
const fileNameNoExt = fileName.replace(/\.(tsx?|jsx?|mjs|cjs)$/, "");
|
|
2689
|
+
const patterns = [
|
|
2690
|
+
// Pages
|
|
2691
|
+
{ pattern: /^page$/, description: () => "P\xE1gina principal" },
|
|
2692
|
+
{ pattern: /^layout$/, description: () => "Layout" },
|
|
2693
|
+
{ pattern: /^loading$/, description: () => "Estado de loading" },
|
|
2694
|
+
{ pattern: /^error$/, description: () => "P\xE1gina de erro" },
|
|
2695
|
+
{ pattern: /^not-found$/, description: () => "P\xE1gina 404" },
|
|
2696
|
+
// Components com sufixo
|
|
2697
|
+
{ pattern: /(.+)PageClient$/, description: (m) => `Client component da p\xE1gina ${m[1]}` },
|
|
2698
|
+
{ pattern: /(.+)Dialog$/, description: (m) => `Dialog de ${m[1].toLowerCase()}` },
|
|
2699
|
+
{ pattern: /(.+)Modal$/, description: (m) => `Modal de ${m[1].toLowerCase()}` },
|
|
2700
|
+
{ pattern: /(.+)Form$/, description: (m) => `Formul\xE1rio de ${m[1].toLowerCase()}` },
|
|
2701
|
+
{ pattern: /(.+)Card$/, description: (m) => `Card de ${m[1].toLowerCase()}` },
|
|
2702
|
+
{ pattern: /(.+)List$/, description: (m) => `Lista de ${m[1].toLowerCase()}` },
|
|
2703
|
+
{ pattern: /(.+)Table$/, description: (m) => `Tabela de ${m[1].toLowerCase()}` },
|
|
2704
|
+
{ pattern: /(.+)Manager$/, description: (m) => `Gerenciador de ${m[1].toLowerCase()}` },
|
|
2705
|
+
{ pattern: /(.+)Provider$/, description: (m) => `Provider de ${m[1].toLowerCase()}` },
|
|
2706
|
+
{ pattern: /(.+)Context$/, description: (m) => `Context de ${m[1].toLowerCase()}` },
|
|
2707
|
+
{ pattern: /(.+)Step$/, description: (m) => `Step: ${m[1]}` },
|
|
2708
|
+
{ pattern: /(.+)Tab$/, description: (m) => `Aba: ${m[1]}` },
|
|
2709
|
+
{ pattern: /(.+)Section$/, description: (m) => `Se\xE7\xE3o: ${m[1]}` },
|
|
2710
|
+
{ pattern: /(.+)Header$/, description: (m) => `Header de ${m[1].toLowerCase()}` },
|
|
2711
|
+
{ pattern: /(.+)Footer$/, description: (m) => `Footer de ${m[1].toLowerCase()}` },
|
|
2712
|
+
{ pattern: /(.+)Skeleton$/, description: (m) => `Skeleton de ${m[1].toLowerCase()}` },
|
|
2713
|
+
{ pattern: /(.+)Chip$/, description: (m) => `Chip de ${m[1].toLowerCase()}` },
|
|
2714
|
+
{ pattern: /(.+)Badge$/, description: (m) => `Badge de ${m[1].toLowerCase()}` },
|
|
2715
|
+
{ pattern: /(.+)Button$/, description: (m) => `Bot\xE3o ${m[1].toLowerCase()}` },
|
|
2716
|
+
{ pattern: /(.+)Icon$/, description: (m) => `\xCDcone ${m[1].toLowerCase()}` },
|
|
2717
|
+
// Hooks
|
|
2718
|
+
{ pattern: /^use(.+)$/, description: (m) => `Hook de ${m[1].toLowerCase()}` },
|
|
2719
|
+
// Types/Schemas
|
|
2720
|
+
{ pattern: /(.+)\.types$/, description: (m) => `Tipos de ${m[1].toLowerCase()}` },
|
|
2721
|
+
{ pattern: /(.+)Schemas?$/, description: (m) => `Schema de ${m[1].toLowerCase()}` },
|
|
2722
|
+
// Utils
|
|
2723
|
+
{ pattern: /(.+)Helpers?$/, description: (m) => `Helpers de ${m[1].toLowerCase()}` },
|
|
2724
|
+
{ pattern: /(.+)Utils?$/, description: (m) => `Utilit\xE1rios de ${m[1].toLowerCase()}` },
|
|
2725
|
+
{ pattern: /(.+)Formatters?$/, description: (m) => `Formatador de ${m[1].toLowerCase()}` },
|
|
2726
|
+
{ pattern: /(.+)Validators?$/, description: (m) => `Validador de ${m[1].toLowerCase()}` },
|
|
2727
|
+
{ pattern: /(.+)Mappers?$/, description: (m) => `Mapper de ${m[1].toLowerCase()}` },
|
|
2728
|
+
{ pattern: /(.+)Converters?$/, description: (m) => `Conversor de ${m[1].toLowerCase()}` },
|
|
2729
|
+
// Services
|
|
2730
|
+
{ pattern: /(.+)Service$/, description: (m) => `Servi\xE7o de ${m[1].toLowerCase()}` },
|
|
2731
|
+
// Index
|
|
2732
|
+
{ pattern: /^index$/, description: () => "Export principal" }
|
|
2733
|
+
];
|
|
2734
|
+
for (const { pattern, description } of patterns) {
|
|
2735
|
+
const match = fileNameNoExt.match(pattern);
|
|
2736
|
+
if (match) {
|
|
2737
|
+
return description(match);
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
const categoryDescriptions = {
|
|
2741
|
+
page: "P\xE1gina",
|
|
2742
|
+
layout: "Layout",
|
|
2743
|
+
route: "API Route",
|
|
2744
|
+
component: "Componente",
|
|
2745
|
+
hook: "Hook",
|
|
2746
|
+
service: "Servi\xE7o",
|
|
2747
|
+
store: "Store",
|
|
2748
|
+
util: "Utilit\xE1rio",
|
|
2749
|
+
type: "Tipos",
|
|
2750
|
+
config: "Configura\xE7\xE3o",
|
|
2751
|
+
test: "Teste"
|
|
2752
|
+
};
|
|
2753
|
+
return categoryDescriptions[category];
|
|
2754
|
+
}
|
|
2755
|
+
|
|
2756
|
+
// src/commands/areas.ts
|
|
2757
|
+
var CODE_EXTENSIONS3 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
2758
|
+
var IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
2759
|
+
"node_modules",
|
|
2760
|
+
"dist",
|
|
2761
|
+
"build",
|
|
2762
|
+
".git",
|
|
2763
|
+
".next",
|
|
2764
|
+
".cache",
|
|
2765
|
+
"coverage",
|
|
2766
|
+
".turbo",
|
|
2767
|
+
".vercel",
|
|
2768
|
+
".analyze"
|
|
2769
|
+
]);
|
|
2770
|
+
async function areas(options = {}) {
|
|
2771
|
+
const cwd = options.cwd || process.cwd();
|
|
2772
|
+
const format = options.format || "text";
|
|
2773
|
+
try {
|
|
2774
|
+
const config = readConfig(cwd);
|
|
2775
|
+
const allFiles = getAllCodeFiles2(cwd);
|
|
2776
|
+
const areaMap = /* @__PURE__ */ new Map();
|
|
2777
|
+
const unmapped = [];
|
|
2778
|
+
for (const filePath of allFiles) {
|
|
2779
|
+
const category = detectCategory(filePath);
|
|
2780
|
+
const areas2 = detectFileAreas(filePath, config);
|
|
2781
|
+
let description = getFileDescription(cwd, filePath);
|
|
2782
|
+
if (!description && config.settings?.inferDescriptions !== false) {
|
|
2783
|
+
description = inferFileDescription(filePath, category);
|
|
2784
|
+
}
|
|
2785
|
+
const areaFile = {
|
|
2786
|
+
path: filePath,
|
|
2787
|
+
category,
|
|
2788
|
+
description
|
|
2789
|
+
};
|
|
2790
|
+
if (areas2.length === 0) {
|
|
2791
|
+
unmapped.push(areaFile);
|
|
2792
|
+
} else {
|
|
2793
|
+
for (const areaId of areas2) {
|
|
2794
|
+
if (!areaMap.has(areaId)) {
|
|
2795
|
+
areaMap.set(areaId, []);
|
|
2796
|
+
}
|
|
2797
|
+
areaMap.get(areaId).push(areaFile);
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2801
|
+
const detectedAreas = [];
|
|
2802
|
+
for (const [areaId, files] of areaMap) {
|
|
2803
|
+
const categories = {};
|
|
2804
|
+
for (const file of files) {
|
|
2805
|
+
categories[file.category] = (categories[file.category] || 0) + 1;
|
|
2806
|
+
}
|
|
2807
|
+
detectedAreas.push({
|
|
2808
|
+
id: areaId,
|
|
2809
|
+
name: getAreaName(areaId, config),
|
|
2810
|
+
description: getAreaDescription(areaId, config),
|
|
2811
|
+
files,
|
|
2812
|
+
fileCount: files.length,
|
|
2813
|
+
categories,
|
|
2814
|
+
isAutoDetected: !config.areas[areaId]
|
|
2815
|
+
});
|
|
2816
|
+
}
|
|
2817
|
+
detectedAreas.sort((a, b) => b.fileCount - a.fileCount);
|
|
2818
|
+
const result = {
|
|
2819
|
+
version: "1.0.0",
|
|
2820
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2821
|
+
cwd,
|
|
2822
|
+
areas: detectedAreas,
|
|
2823
|
+
unmapped,
|
|
2824
|
+
summary: {
|
|
2825
|
+
totalAreas: detectedAreas.length,
|
|
2826
|
+
totalFiles: allFiles.length,
|
|
2827
|
+
unmappedCount: unmapped.length
|
|
2828
|
+
}
|
|
2829
|
+
};
|
|
2830
|
+
if (format === "json") {
|
|
2831
|
+
return JSON.stringify(result, null, 2);
|
|
2832
|
+
}
|
|
2833
|
+
return formatAreasText(result);
|
|
2834
|
+
} catch (error) {
|
|
2835
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2836
|
+
throw new Error(`Erro ao executar areas: ${message}`);
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
function getAllCodeFiles2(dir, files = [], baseDir = dir) {
|
|
2840
|
+
try {
|
|
2841
|
+
const entries = readdirSync3(dir);
|
|
2842
|
+
for (const entry of entries) {
|
|
2843
|
+
const fullPath = join5(dir, entry);
|
|
2844
|
+
if (IGNORED_DIRS.has(entry) || entry.startsWith(".")) {
|
|
2845
|
+
continue;
|
|
2846
|
+
}
|
|
2847
|
+
try {
|
|
2848
|
+
const stat = statSync3(fullPath);
|
|
2849
|
+
if (stat.isDirectory()) {
|
|
2850
|
+
getAllCodeFiles2(fullPath, files, baseDir);
|
|
2851
|
+
} else {
|
|
2852
|
+
const ext = extname3(entry).toLowerCase();
|
|
2853
|
+
if (CODE_EXTENSIONS3.has(ext)) {
|
|
2854
|
+
const relativePath = fullPath.slice(baseDir.length + 1).replace(/\\/g, "/");
|
|
2855
|
+
files.push(relativePath);
|
|
2856
|
+
}
|
|
2857
|
+
}
|
|
2858
|
+
} catch {
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
} catch {
|
|
2862
|
+
}
|
|
2863
|
+
return files;
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2866
|
+
// src/commands/area.ts
|
|
2867
|
+
import { readdirSync as readdirSync4, statSync as statSync4 } from "fs";
|
|
2868
|
+
import { join as join6, extname as extname4 } from "path";
|
|
2869
|
+
var CODE_EXTENSIONS4 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
2870
|
+
var IGNORED_DIRS2 = /* @__PURE__ */ new Set([
|
|
2871
|
+
"node_modules",
|
|
2872
|
+
"dist",
|
|
2873
|
+
"build",
|
|
2874
|
+
".git",
|
|
2875
|
+
".next",
|
|
2876
|
+
".cache",
|
|
2877
|
+
"coverage",
|
|
2878
|
+
".turbo",
|
|
2879
|
+
".vercel",
|
|
2880
|
+
".analyze"
|
|
2881
|
+
]);
|
|
2882
|
+
async function area(target, options = {}) {
|
|
2883
|
+
const cwd = options.cwd || process.cwd();
|
|
2884
|
+
const format = options.format || "text";
|
|
2885
|
+
const filterType = options.type;
|
|
2886
|
+
const full = options.full ?? false;
|
|
2887
|
+
if (!target) {
|
|
2888
|
+
throw new Error("Nome da \xE1rea \xE9 obrigat\xF3rio. Exemplo: ai-tool area meus-pets");
|
|
2889
|
+
}
|
|
2890
|
+
try {
|
|
2891
|
+
const config = readConfig(cwd);
|
|
2892
|
+
const allFiles = getAllCodeFiles3(cwd);
|
|
2893
|
+
const areaFiles = [];
|
|
2894
|
+
const targetLower = target.toLowerCase();
|
|
2895
|
+
for (const filePath of allFiles) {
|
|
2896
|
+
const fileAreas = detectFileAreas(filePath, config);
|
|
2897
|
+
const belongsToArea = fileAreas.some(
|
|
2898
|
+
(a) => a.toLowerCase() === targetLower || a.toLowerCase().includes(targetLower)
|
|
2899
|
+
);
|
|
2900
|
+
if (belongsToArea) {
|
|
2901
|
+
const category = detectCategory(filePath);
|
|
2902
|
+
if (filterType && category !== filterType) {
|
|
2903
|
+
continue;
|
|
2904
|
+
}
|
|
2905
|
+
let description = getFileDescription(cwd, filePath);
|
|
2906
|
+
if (!description && config.settings?.inferDescriptions !== false) {
|
|
2907
|
+
description = inferFileDescription(filePath, category);
|
|
2908
|
+
}
|
|
2909
|
+
areaFiles.push({
|
|
2910
|
+
path: filePath,
|
|
2911
|
+
category,
|
|
2912
|
+
description
|
|
2913
|
+
});
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
if (areaFiles.length === 0) {
|
|
2917
|
+
const availableAreas = getAvailableAreas(allFiles, config);
|
|
2918
|
+
return formatAreaNotFound(target, availableAreas);
|
|
2919
|
+
}
|
|
2920
|
+
const byCategory = {};
|
|
2921
|
+
const categories = {};
|
|
2922
|
+
for (const file of areaFiles) {
|
|
2923
|
+
if (!byCategory[file.category]) {
|
|
2924
|
+
byCategory[file.category] = [];
|
|
2925
|
+
}
|
|
2926
|
+
byCategory[file.category].push(file);
|
|
2927
|
+
categories[file.category] = (categories[file.category] || 0) + 1;
|
|
2928
|
+
}
|
|
2929
|
+
for (const cat of Object.keys(byCategory)) {
|
|
2930
|
+
byCategory[cat].sort((a, b) => a.path.localeCompare(b.path));
|
|
2931
|
+
}
|
|
2932
|
+
const realAreaId = findRealAreaId(target, allFiles, config);
|
|
2933
|
+
const detectedArea = {
|
|
2934
|
+
id: realAreaId || target,
|
|
2935
|
+
name: getAreaName(realAreaId || target, config),
|
|
2936
|
+
description: getAreaDescription(realAreaId || target, config),
|
|
2937
|
+
files: areaFiles,
|
|
2938
|
+
fileCount: areaFiles.length,
|
|
2939
|
+
categories,
|
|
2940
|
+
isAutoDetected: !config.areas[realAreaId || target]
|
|
2941
|
+
};
|
|
2942
|
+
const result = {
|
|
2943
|
+
version: "1.0.0",
|
|
2944
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2945
|
+
area: detectedArea,
|
|
2946
|
+
byCategory
|
|
2947
|
+
};
|
|
2948
|
+
if (format === "json") {
|
|
2949
|
+
return JSON.stringify(result, null, 2);
|
|
2950
|
+
}
|
|
2951
|
+
return formatAreaDetailText(result, { full, filterType });
|
|
2952
|
+
} catch (error) {
|
|
2953
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2954
|
+
throw new Error(`Erro ao executar area: ${message}`);
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
function findRealAreaId(target, allFiles, config) {
|
|
2958
|
+
const targetLower = target.toLowerCase();
|
|
2959
|
+
for (const areaId of Object.keys(config.areas)) {
|
|
2960
|
+
if (areaId.toLowerCase() === targetLower || areaId.toLowerCase().includes(targetLower)) {
|
|
2961
|
+
return areaId;
|
|
2962
|
+
}
|
|
2963
|
+
}
|
|
2964
|
+
const detectedAreas = /* @__PURE__ */ new Set();
|
|
2965
|
+
for (const filePath of allFiles) {
|
|
2966
|
+
const areas2 = detectFileAreas(filePath, config);
|
|
2967
|
+
for (const areaId of areas2) {
|
|
2968
|
+
if (areaId.toLowerCase() === targetLower || areaId.toLowerCase().includes(targetLower)) {
|
|
2969
|
+
detectedAreas.add(areaId);
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
return detectedAreas.size > 0 ? [...detectedAreas][0] : null;
|
|
2974
|
+
}
|
|
2975
|
+
function getAvailableAreas(allFiles, config) {
|
|
2976
|
+
const areaCounts = /* @__PURE__ */ new Map();
|
|
2977
|
+
for (const filePath of allFiles) {
|
|
2978
|
+
const areas2 = detectFileAreas(filePath, config);
|
|
2979
|
+
for (const areaId of areas2) {
|
|
2980
|
+
areaCounts.set(areaId, (areaCounts.get(areaId) || 0) + 1);
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
return [...areaCounts.entries()].map(([id, count]) => ({ id, count })).sort((a, b) => b.count - a.count);
|
|
2984
|
+
}
|
|
2985
|
+
function formatAreaNotFound(target, availableAreas) {
|
|
2986
|
+
let out = `
|
|
2987
|
+
\u274C \xC1rea n\xE3o encontrada: "${target}"
|
|
2988
|
+
|
|
2989
|
+
`;
|
|
2990
|
+
if (availableAreas.length > 0) {
|
|
2991
|
+
out += `\u{1F4E6} \xC1reas dispon\xEDveis:
|
|
2992
|
+
|
|
2993
|
+
`;
|
|
2994
|
+
for (const { id, count } of availableAreas.slice(0, 15)) {
|
|
2995
|
+
out += ` ${id.padEnd(25)} ${count} arquivos
|
|
2996
|
+
`;
|
|
2997
|
+
}
|
|
2998
|
+
if (availableAreas.length > 15) {
|
|
2999
|
+
out += ` ... e mais ${availableAreas.length - 15}
|
|
3000
|
+
`;
|
|
3001
|
+
}
|
|
3002
|
+
out += `
|
|
3003
|
+
`;
|
|
3004
|
+
}
|
|
3005
|
+
out += `\u{1F4A1} Dicas:
|
|
3006
|
+
`;
|
|
3007
|
+
out += ` - Use o ID exato da \xE1rea (ex: ai-tool area meus-pets)
|
|
3008
|
+
`;
|
|
3009
|
+
out += ` - Use 'ai-tool areas' para listar todas as \xE1reas
|
|
3010
|
+
`;
|
|
3011
|
+
return out;
|
|
3012
|
+
}
|
|
3013
|
+
function getAllCodeFiles3(dir, files = [], baseDir = dir) {
|
|
3014
|
+
try {
|
|
3015
|
+
const entries = readdirSync4(dir);
|
|
3016
|
+
for (const entry of entries) {
|
|
3017
|
+
const fullPath = join6(dir, entry);
|
|
3018
|
+
if (IGNORED_DIRS2.has(entry) || entry.startsWith(".")) {
|
|
3019
|
+
continue;
|
|
3020
|
+
}
|
|
3021
|
+
try {
|
|
3022
|
+
const stat = statSync4(fullPath);
|
|
3023
|
+
if (stat.isDirectory()) {
|
|
3024
|
+
getAllCodeFiles3(fullPath, files, baseDir);
|
|
3025
|
+
} else {
|
|
3026
|
+
const ext = extname4(entry).toLowerCase();
|
|
3027
|
+
if (CODE_EXTENSIONS4.has(ext)) {
|
|
3028
|
+
const relativePath = fullPath.slice(baseDir.length + 1).replace(/\\/g, "/");
|
|
3029
|
+
files.push(relativePath);
|
|
3030
|
+
}
|
|
3031
|
+
}
|
|
3032
|
+
} catch {
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
3035
|
+
} catch {
|
|
3036
|
+
}
|
|
3037
|
+
return files;
|
|
3038
|
+
}
|
|
3039
|
+
|
|
3040
|
+
// src/commands/areas-init.ts
|
|
3041
|
+
import { readdirSync as readdirSync5, statSync as statSync5 } from "fs";
|
|
3042
|
+
import { join as join7, extname as extname5 } from "path";
|
|
3043
|
+
var CODE_EXTENSIONS5 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
3044
|
+
var IGNORED_DIRS3 = /* @__PURE__ */ new Set([
|
|
3045
|
+
"node_modules",
|
|
3046
|
+
"dist",
|
|
3047
|
+
"build",
|
|
3048
|
+
".git",
|
|
3049
|
+
".next",
|
|
3050
|
+
".cache",
|
|
3051
|
+
"coverage",
|
|
3052
|
+
".turbo",
|
|
3053
|
+
".vercel",
|
|
3054
|
+
".analyze"
|
|
3055
|
+
]);
|
|
3056
|
+
async function areasInit(options = {}) {
|
|
3057
|
+
const cwd = options.cwd || process.cwd();
|
|
3058
|
+
const force = options.force ?? false;
|
|
3059
|
+
try {
|
|
3060
|
+
if (configExists(cwd) && !force) {
|
|
3061
|
+
return `
|
|
3062
|
+
\u26A0\uFE0F Arquivo de configura\xE7\xE3o j\xE1 existe: .analyze/areas.config.json
|
|
3063
|
+
|
|
3064
|
+
Use --force para sobrescrever:
|
|
3065
|
+
ai-tool areas init --force
|
|
3066
|
+
|
|
3067
|
+
Ou edite manualmente o arquivo existente.
|
|
3068
|
+
`.trim();
|
|
3069
|
+
}
|
|
3070
|
+
const allFiles = getAllCodeFiles4(cwd);
|
|
3071
|
+
const currentConfig = readConfig(cwd);
|
|
3072
|
+
const areaCounts = /* @__PURE__ */ new Map();
|
|
3073
|
+
for (const filePath of allFiles) {
|
|
3074
|
+
const areas2 = detectFileAreas(filePath, currentConfig);
|
|
3075
|
+
for (const areaId of areas2) {
|
|
3076
|
+
if (!areaCounts.has(areaId)) {
|
|
3077
|
+
areaCounts.set(areaId, /* @__PURE__ */ new Set());
|
|
3078
|
+
}
|
|
3079
|
+
areaCounts.get(areaId).add(filePath);
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
const generatedAreas = {};
|
|
3083
|
+
for (const [areaId, files] of areaCounts) {
|
|
3084
|
+
const patterns = inferPatternsFromFiles([...files]);
|
|
3085
|
+
generatedAreas[areaId] = {
|
|
3086
|
+
name: getAreaName(areaId, currentConfig),
|
|
3087
|
+
description: getAreaDescription(areaId, currentConfig),
|
|
3088
|
+
patterns
|
|
3089
|
+
};
|
|
3090
|
+
}
|
|
3091
|
+
const newConfig = {
|
|
3092
|
+
$schema: "./areas.schema.json",
|
|
3093
|
+
version: "1.0.0",
|
|
3094
|
+
areas: generatedAreas,
|
|
3095
|
+
descriptions: {},
|
|
3096
|
+
settings: {
|
|
3097
|
+
autoDetect: true,
|
|
3098
|
+
inferDescriptions: true,
|
|
3099
|
+
groupByCategory: true
|
|
3100
|
+
}
|
|
3101
|
+
};
|
|
3102
|
+
writeConfig(cwd, newConfig);
|
|
3103
|
+
const sortedAreas = [...areaCounts.entries()].sort((a, b) => b[1].size - a[1].size);
|
|
3104
|
+
let out = `
|
|
3105
|
+
\u2705 Arquivo criado: .analyze/areas.config.json
|
|
3106
|
+
|
|
3107
|
+
\u{1F4E6} \xC1reas detectadas: ${sortedAreas.length}
|
|
3108
|
+
|
|
3109
|
+
`;
|
|
3110
|
+
for (const [areaId, files] of sortedAreas.slice(0, 15)) {
|
|
3111
|
+
const name = getAreaName(areaId, newConfig);
|
|
3112
|
+
out += ` ${name.padEnd(25)} ${files.size} arquivos
|
|
3113
|
+
`;
|
|
3114
|
+
}
|
|
3115
|
+
if (sortedAreas.length > 15) {
|
|
3116
|
+
out += ` ... e mais ${sortedAreas.length - 15}
|
|
3117
|
+
`;
|
|
3118
|
+
}
|
|
3119
|
+
const unmappedCount = allFiles.filter(
|
|
3120
|
+
(f) => detectFileAreas(f, currentConfig).length === 0
|
|
3121
|
+
).length;
|
|
3122
|
+
if (unmappedCount > 0) {
|
|
3123
|
+
out += `
|
|
3124
|
+
\u26A0\uFE0F ${unmappedCount} arquivos sem \xE1rea definida
|
|
3125
|
+
Use 'ai-tool areas' para ver detalhes
|
|
3126
|
+
`;
|
|
3127
|
+
}
|
|
3128
|
+
out += `
|
|
3129
|
+
\u{1F4A1} Edite o arquivo para:
|
|
3130
|
+
- Renomear \xE1reas (campo "name")
|
|
3131
|
+
- Adicionar descri\xE7\xF5es (campo "description")
|
|
3132
|
+
- Ajustar padr\xF5es (campo "patterns")
|
|
3133
|
+
- Adicionar/remover \xE1reas
|
|
3134
|
+
- Definir descri\xE7\xF5es espec\xEDficas de arquivos (campo "descriptions")
|
|
3135
|
+
`;
|
|
3136
|
+
return out.trim();
|
|
3137
|
+
} catch (error) {
|
|
3138
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3139
|
+
throw new Error(`Erro ao executar areas init: ${message}`);
|
|
3140
|
+
}
|
|
3141
|
+
}
|
|
3142
|
+
function inferPatternsFromFiles(files) {
|
|
3143
|
+
const patterns = /* @__PURE__ */ new Set();
|
|
3144
|
+
const folderGroups = /* @__PURE__ */ new Map();
|
|
3145
|
+
for (const file of files) {
|
|
3146
|
+
const parts = file.split("/");
|
|
3147
|
+
if (parts.length > 1) {
|
|
3148
|
+
const folder = parts.slice(0, Math.min(3, parts.length - 1)).join("/");
|
|
3149
|
+
if (!folderGroups.has(folder)) {
|
|
3150
|
+
folderGroups.set(folder, []);
|
|
3151
|
+
}
|
|
3152
|
+
folderGroups.get(folder).push(file);
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
for (const [folder, folderFiles] of folderGroups) {
|
|
3156
|
+
if (folderFiles.length >= 2) {
|
|
3157
|
+
patterns.add(`${folder}/**`);
|
|
3158
|
+
} else {
|
|
3159
|
+
patterns.add(folderFiles[0]);
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
for (const file of files) {
|
|
3163
|
+
if (!file.includes("/")) {
|
|
3164
|
+
patterns.add(file);
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
3167
|
+
return [...patterns].sort();
|
|
3168
|
+
}
|
|
3169
|
+
function getAllCodeFiles4(dir, files = [], baseDir = dir) {
|
|
3170
|
+
try {
|
|
3171
|
+
const entries = readdirSync5(dir);
|
|
3172
|
+
for (const entry of entries) {
|
|
3173
|
+
const fullPath = join7(dir, entry);
|
|
3174
|
+
if (IGNORED_DIRS3.has(entry) || entry.startsWith(".")) {
|
|
3175
|
+
continue;
|
|
3176
|
+
}
|
|
3177
|
+
try {
|
|
3178
|
+
const stat = statSync5(fullPath);
|
|
3179
|
+
if (stat.isDirectory()) {
|
|
3180
|
+
getAllCodeFiles4(fullPath, files, baseDir);
|
|
3181
|
+
} else {
|
|
3182
|
+
const ext = extname5(entry).toLowerCase();
|
|
3183
|
+
if (CODE_EXTENSIONS5.has(ext)) {
|
|
3184
|
+
const relativePath = fullPath.slice(baseDir.length + 1).replace(/\\/g, "/");
|
|
3185
|
+
files.push(relativePath);
|
|
3186
|
+
}
|
|
3187
|
+
}
|
|
3188
|
+
} catch {
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3191
|
+
} catch {
|
|
3192
|
+
}
|
|
3193
|
+
return files;
|
|
3194
|
+
}
|
|
3195
|
+
|
|
1946
3196
|
// src/index.ts
|
|
1947
|
-
|
|
3197
|
+
import { createRequire } from "module";
|
|
3198
|
+
var require2 = createRequire(import.meta.url);
|
|
3199
|
+
var pkg = require2("../package.json");
|
|
3200
|
+
var VERSION = pkg.version;
|
|
1948
3201
|
|
|
1949
3202
|
export {
|
|
1950
3203
|
detectCategory,
|
|
@@ -1965,5 +3218,23 @@ export {
|
|
|
1965
3218
|
impact,
|
|
1966
3219
|
suggest,
|
|
1967
3220
|
context,
|
|
3221
|
+
configExists,
|
|
3222
|
+
readConfig,
|
|
3223
|
+
writeConfig,
|
|
3224
|
+
setArea,
|
|
3225
|
+
removeArea,
|
|
3226
|
+
setFileDescription,
|
|
3227
|
+
getFileDescription,
|
|
3228
|
+
FOLDER_PATTERNS,
|
|
3229
|
+
KEYWORD_PATTERNS,
|
|
3230
|
+
AREA_NAMES,
|
|
3231
|
+
AREA_DESCRIPTIONS,
|
|
3232
|
+
detectFileAreas,
|
|
3233
|
+
getAreaName,
|
|
3234
|
+
getAreaDescription,
|
|
3235
|
+
inferFileDescription,
|
|
3236
|
+
areas,
|
|
3237
|
+
area,
|
|
3238
|
+
areasInit,
|
|
1968
3239
|
VERSION
|
|
1969
3240
|
};
|